Goal
Submit a fresh iOS and Android build to App Store Connect and Google Play Console via the WPMAM publish pipeline.
Prerequisites
- Enrollment complete and
local-app-account_codepopulated and verified - iOS bundle id reserved with Apple; Android package name reserved with Google
- App icon (1024×1024 PNG), launch screens, and theme assets uploaded
- APNs
.p8key + Firebase service-account JSON configured - Apple Developer Program membership active; Google Play Console developer account active
- Apple App Store Connect app record created (with the bundle id)
- Google Play Console app record created (with the package name)
Steps
1. Open the Publish page
Mobile App Manager → Publish Your App opens mam_app_submit::render(). The page first runs verify_account_code() against the WPMAM enrollment server. If verification fails, see Recipe: Customer enrollment and account code.
2. Fill in app identity
| Field | Option key | Notes |
|---|---|---|
| iOS app name | local-app-ios-app-name |
Display name on the iOS home screen |
| iOS bundle id | ios_pn_app_bundle_id |
Frozen — must match App Store Connect |
| iOS team id | ios_pn_team_id |
10-character Apple team id |
| iOS app channel | local-app-ios-app-channel |
TestFlight channel routing |
| Android package id | android_pn_app_bundle_id |
Frozen — must match Play Console |
⚠️ Bundle ids are frozen option keys (predate the mam_* rename convention). Once you’ve submitted to the stores, treat them as immutable; renaming would orphan customer Apple/Google submissions.
3. Fill in permission strings
iOS requires user-facing copy for every privacy-sensitive permission. The publish page collects:
| Field | Option key | Used when |
|---|---|---|
| Camera message | ios_app_camera_message |
App requests camera access |
| GPS message | ios_app_gps_message |
App requests location access |
| Contacts message | ios_app_contacts_message |
App requests contacts access |
These strings ship into Info.plist as NS*UsageDescription. Apple rejects builds with vague or empty copy.
4. Set version and build numbers
| Field | Option key |
|---|---|
| iOS version number | mam_ios_version_number (e.g., 1.4.2) |
| Android version number | mam_android_version_number |
| iOS build number | mam_ios_build_number (must increment per submission) |
| Android build number | mam_android_build_number (must increment per submission) |
⚠️ Build numbers must increment for each new submission. Apple and Google both reject duplicate build numbers within a release train.
5. Configure integrations
| Field | Option key |
|---|---|
| iOS Google plist | ios_app_google_plist (Firebase config) |
| Google Places API key | ios_app_google_places_api |
6. Save settings
Click Save. mam_main_app_publishing::local_app_save_publish_app_settings() writes ~20 options from POST and JSON-responds. The page reloads with the new values.
7. Submit the publish request
Click Submit Publish Request. The handler:
- Re-verifies
local-app-account_codeagainst WPMAM - Builds a Fastlane settings array from the persisted options
- Fires
apply_filters('mam_fastlane_settings', $settings)— sibling plugins use this hook to inject build-time config (third-party SDK keys, custom Info.plist entries, gradle properties) - POSTs the payload to the WPMAM publish endpoint
- Renders the response as the publish-status panel
The submit is fire-and-forget. WPMAM’s CI runs Fastlane asynchronously; status is polled separately.
8. Monitor build status
Refresh the publish page — the status panel polls WPMAM and shows the latest build state. A successful build appears in App Store Connect (TestFlight) and Google Play Console (Internal Testing) within 30–60 minutes.
If the build fails, the panel shows the Fastlane error. Common causes:
- Missing or invalid signing certificate (Apple side)
- Build number not incremented
- Permission strings missing or rejected
- Asset corruption (app icon wrong dimensions, launch screens wrong format)
Extending the publish payload
mam_fastlane_settings is the only extension point for the publish payload. Sibling plugins that need to inject build-time config (e.g., a third-party SDK key, a custom URL scheme) should hook here:
add_filter( 'mam_fastlane_settings', function ( array $settings ): array {
$settings['custom_url_schemes'][] = 'myplugin-callback';
$settings['ios_extra_plist']['MyPluginAPIKey'] = get_option( 'myplugin_api_key' );
return $settings;
} );
What WPMAM does with these keys is documented on the WPMAM side; coordinate with the build pipeline team before adding new keys.
Verification
- The publish-status panel shows “Build queued” or later
- TestFlight (iOS) shows a new build in 30–60 minutes
- Google Play Console → Internal Testing shows a new build
- The mobile app, once installed from the new build, returns the configured app name and shows your branding
Gotchas
app-submit.phpis 1076 lines of admin-page UI + save flow. Treat it as shared mutable presentation code; small edits can have large knock-on effects.- Bundle ids are frozen — they predate the
mam_*rename convention. Renaming orphans customer App Store / Play Store submissions. - Account-code verification is a guard, not a fix. A mismatch means contact support.
- Submit POSTs are fire-and-forget by design. The build runs async; status is polled separately. Don’t expect a synchronous success/failure response from the submit.
Related articles
- Recipe: Build an app end-to-end
- Recipe: Customer enrollment and account code
- Recipe: Configure push notifications
- Hook: mam_fastlane_settings
- Frozen public contracts reference
Metadata
| Field | Value |
|---|---|
| Article type | Recipe (Admin) |
| Plugin slug | mam-main |
| Applies to plugin version | 2.1.11+ |
| Category | Building Your App |
| Audience | WordPress admin |
| Estimated time | 30 minutes (excluding store review) |
| Last verified | 2026-05-02 |
