Page MenuHomePhabricator

Streamline updating fundraising banner content while accommodating multilingual campaigns
Closed, ResolvedPublic

Description

Background
As the Advancement team partners with members of our community to select the best messaging for banners during fundraising campaigns, it is imperative they're able to make timely updates, and apps messaging has parity with Web. Our current process for messaging to be updated is to hardcode it in the app, which means an update to language requires an update to the app.

User Story
As a staff member on the Online Fundraising team, I want to be able to easily update campaign content being displayed in the apps, so that I can update messaging that is not favorable in a banner without engineering intervention

As a staff member on the Online Fundraising team, I want to reach English speakers and Dutch speakers when deploying campaigns in The Netherlands, so that I can reach a larger number of potential donors.

Minimum Requirements

  • Solution should be something that requires login and special permissions to change the content
  • A member of advancement can update content and it is available in the app within 24 hour without a need for a new build
  • Banners can be shown in at least two countries and in two languages during the same campaign period

Task

  • Write out technical approach for achieving the requirements above
  • Spin off app specific tasks for implementation after getting consensus from the team

Timeline
We have a goal of testing these changes in October and having a full release in December

Reference
Deck

Event Timeline

JTannerWMF triaged this task as Medium priority.Aug 10 2023, 9:38 PM
JTannerWMF created this task.

Here's a rough outline of how we could move forward with both a) accommodating multilingual campaigns, and b) allowing self-service to modify campaigns without having to redeploy any resources.

Background

The current Spec for our announcement structure can be found here. (Interestingly, in a slightly older version of the spec, there were already plans to move the announcements to a Wiki page!)

Our current announcements look something like this:

{
  announce: [
  {
    type: "fundraising",
    start_time: "2023-08-22T00:00:00Z",
    end_time: "2023-09-19T23:59:00Z",
    domain: "en.wikipedia.org",
    id: "<campaign id>",
    platforms: [ "AndroidAppV2" ],
    countries: [ "US" ],
    border: true,
    placement: "article",
    text: "<announcement text>",
    caption_HTML: "<privacy policy link>",
    negative_text: "<negative button>",
    action: {
      title: "<positive button>",
      url: "<url for positive button>"
    }
  },
  ... more announcements
}

These announcements are basically hosted statically at this REST endpoint, and are generated using some minimal logic in the wikifeeds repo.

Proposal

  • The list of announcements, consumed by both iOS and Android apps, shall be moved from the current REST endpoint to a wiki page (with an agreed-upon name) with a similar JSON structure as the current announcements.
  • To accommodate multiple languages for a single announcement, the structure shall be updated as follows:
{
  announce: [
  {
    type: "fundraising",
    start_time: "2023-08-22T00:00:00Z",
    end_time: "2023-09-19T23:59:00Z",
    domain: "en.wikipedia.org",
    id: "<campaign id>",
    platforms: [ "AppsV3" ],
    countries: [ "US" ],
    border: true,
    placement: "article",

    assets: {
      "en": {
        text: "<announcement text>",
        footer: "<privacy policy link>",
        action_positive: {
          title: "<positive button>",
          url: "<url for positive button>"
        }
        action_negative: {
          title: "<negative button>",
          url: "<url (optional) for negative button>"
        }
      }
      "hi": {
        text: "<announcement text>",
        footer: "<privacy policy link>",
        action_positive: {
          title: "<positive button>",
          url: "<url for positive button>"
        }
        action_negative: {
          title: "<negative button>",
          url: "<url (optional) for negative button>"
        }
      }
      ... more languages
    }

  },
  ... more announcements
}

In other words, whereas the previous structure had a single text field and a single caption_html etc, the new structure will have a map between language codes and a structure that contains the same assets for that language.

  • If this new announcement structure is placed in a Wiki page, using the JsonConfig extension (in the Config: namespace), it will be editable by anyone who has access/permissions for it. The basic JSON syntax will be checked automatically by the extension when editing the page.
  • When a new announcement needs to be composed from scratch, the Apps team will compose it and put it on the wiki page. After it's composed, anyone wanting to make tweaks to the verbiage of the announcement will be able to discern where in the JSON structure the verbiage occurs, and make changes to it.
Questions to resolve
  • Do we still need separate announcements for Android vs iOS? Can they share literally the same announcement structure?
    • The URL for a campaign differs only by the "platform" code inside the URL string. Can we use a special replacement keyword, e.g. $platform; that the respective app will replace client-side when displaying the announcement?
  • If both apps will be implementing "multiple impressions" for announcements, do we want to include any configurable fields into the structure, such as max_impressions?
  • Is the domain field used for anything? Can it be removed?
  • Since we now have a list of language assets for each announcement, does it mean that the announcement should be shown only for those languages? i.e. If a user is in the target country, but doesn't have any of the target languages selected, should they still see the announcement in the default (first?) language in the list? (that would be basically the current behavior.)

@Dbrant

Do we still need separate announcements for Android vs iOS? Can they share literally the same announcement structure?

There are times when they want to only run a campaign on Android, or only run one on iOS, right? Would we lose that flexibility?

The list of announcements, consumed by both iOS and Android apps, shall be moved from the current REST endpoint to a Meta Wiki page (with an agreed-upon name) with a similar JSON structure as the current announcements.

Just curious, would we continue to update the older announcements endpoint with new campaigns, to display on older versions of the app? I do like this idea of a clean break away from wikifeeds moving forward, just want to confirm.

If this is a clean break (i.e. new versions of the app will only point to the Meta config and not flow through wikifeeds announcements at all) I wonder if we could clean things up even more? Here are the our current live announcements:

{
      "type": "fundraising",
      "start_time": "2023-08-22T00:00:00Z",
      "end_time": "2023-09-19T23:59:00Z",
      "domain": "en.wikipedia.org",
      "id": "INDIAFUNDRAISING23IOSV2EN",
      "platforms": [
        "iOSAppV2",
        "iOSAppV3",
        "iOSAppV4",
        "iOSAppV5"
      ],
      "countries": [
        "IN"
      ],
      "border": true,
      "placement": "article",
      "text": "...",
      "caption_HTML": "...",
      "negative_text": "....",
      "action": {
        "title": "DONATE NOW",
        "url": "..."
      }
    },

Cleanup proposal:

"type": "fundraising",
"start_time": "2023-08-22T00:00:00Z",
"end_time": "2023-09-19T23:59:00Z",
"domain": "en.wikipedia.org",
"id": "INDIAFUNDRAISING23",
"platforms": [
  "iOS",
  "Android"
],
"versions": {
    "iOS": 20, //an app hardcoded to 19 will ignore this entire object; it expects a different structure. 
    "Android': 20
}
"countries": [
  "IN"
],
assets: {..(multilingual bits)..}

I'm open to other ideas, but I specifically dislike how we combine platform with version in our current setup (I'm to blame for iOS getting out of hand), and I think the id could be simplified. I also don't think there's a need (for iOS anyway) to specify border and placement anymore.

Are we going to show other announcement types, like surveys? It would be good to know what they might look like.

@Dbrant

Is the domain field used for anything? Can it be removed?

I always thought we used it as extra filtering logic to limit modals on certain Wikis. That is, a user could have EN and ES as app wiki languages, EN returns with announcements during Big English, but if they land on an ES article we don't show the campaign modal. I don't see anything like that in the iOS code though, so I guess I'm mistaken.

Since we now have a list of language assets for each announcement, does it mean that the announcement should be shown only for those languages? i.e. If a user is in the target country, but doesn't have any of the target languages selected, should they still see the announcement in the default (first?) language in the list? (that would be basically the current behavior.)

doesn't have any of the target languages selected - I assumed this was based on device language, not app language. Are we ignoring device language?

Also, reminder that seems like we are moving away from a subdomain-based campaign response with Meta. (EN has items today vs ES does not), so maybe it would be good to keep domain.

domain: Means campaign should only display on an article in that wiki.
country: Means campaign should only display for users in that country (using GeoIP cookie)
assets.key: Pull strings based on device language?

After meeting with both apps teams, here is an updated version of the agreed-upon structure:

[
  {
    start_time: "2023-08-22T00:00:00Z",
    end_time: "2023-09-19T23:59:00Z",
    id: "<campaign id>",
    platforms: [ "iOS", “Android” ],
    version: 20,
    countries: [ "US" ],

    assets: {

      "en": {
        text: "<announcement text>",
        footer: "<privacy policy link>",
        action_positive: {
          title: "<positive button>",
          url: "<url for positive button>"
        },
        action_negative: {
          title: "<negative button>",
          url: "<url (optional) for negative button>"
        },
        currency_code: "<code>"
      }

      "zh-Hant": {
        text: "<announcement text>",
        footer: "<privacy policy link>",
        action_positive: {
          title: "<positive button>",
          url: "<url for positive button>"
        },
        action_negative: {
          title: "<negative button>",
          url: "<url (optional) for negative button>"
        },
        currency_code: "<code>"
      }

      ... more languages
    }

  },

  ... more announcements
]

A few notes and points of interest:

  • This structure will be placed in a wiki page on Donate Wiki (not meta wiki), so it will need to be made accessible by us (apps engineers) and FR tech.
  • The announcements in this structure are solely for fundraising. Existing announcements for surveys etc. will still be served from the existing endpoint.
  • The root object of the json structure is an array [...], and no longer an announce object.
  • The list of platforms is just iOS and/or Android, with the version number moved into its own field.
  • Each language asset bundle now contains a (optional) currency_code field, to serve for pre-selecting the currency in the native donation form.
This comment was removed by Tsevener.

iOS-specific task is at T347352. Moving previous sync comment to that.

Seddon added a subscriber: Dbrant.