The idea in one sentence
When your MAM app shows the body of a WordPress page, post, or category list, you’re not looking at “live” WordPress — you’re looking at a snapshot MAM built by running your content through WordPress’s own the_content filter, pulling out the featured image, and normalizing the text, then handing the result to the device.
Once you understand that pipeline, most of the “why does my content look like that in the app?” questions answer themselves: why a shortcode rendered (or didn’t), why a smart quote turned into a straight quote, why the featured image you picked is the one that shows at the top of the screen.
Why this matters
In the no-code builder, you point a button at a WordPress page, post, or category — but on the device, the app doesn’t open a browser to that page (that’s a different content type, Web URL). Instead, MAM reads the post out of your database, processes it server-side, and ships the processed HTML and image references down in the app’s data payload — the bundle of data your app downloads from your site.
That server-side processing step is where everything in this article happens. Once you know what it does, you can predict how your content will look once it lands in the app — and spot the cases where it won’t quite match the website.
The three things MAM does to your content
Every time the app asks for the content behind a WordPress-backed button, MAM does three jobs for that post:
- Filters the body through WordPress’s
the_contentpipeline. - Extracts the featured image into a small set of image fields.
- Normalizes the text encoding so it travels cleanly to the device.
The same three jobs run every time, whether the button points at a single page, a single post, or one entry in a category list. The code lives in the content classes — the small building blocks that turn a piece of WordPress content into app-ready data — under mam-main/includes/content-classes/: local-app-wp-content-class.php (a WordPress Page), local-app-wp-post-content-class.php (a single Post), and local-app-wp-post-category-class.php (a list of posts). Each one exposes a get_data_for_app() method that the phone-data pipeline calls whenever it renders that button.
Here’s what each of those three jobs actually does.
1. The body runs through the_content
First, MAM loads the post and runs its raw body through WordPress’s own standard content filter:
remove_filter( 'the_content', 'wptexturize' );
$content = apply_filters( 'the_content', $post->post_content );
This is the exact filter WordPress uses to render a post on your website. Running it server-side means the app receives content that’s already been processed the way a browser would see it, not raw editor markup. That has a couple of practical consequences worth knowing:
- Shortcodes and
the_contentfilters run. Anything hooked tothe_content— auto-embeds,wpautopparagraph wrapping, plugin shortcodes that register on that filter — executes here, so content that depends on athe_contentfilter generally renders in the app the same way it does on your site. wptexturizeis deliberately turned off. MAM removes thewptexturizefilter right before runningthe_content.wptexturizeis the WordPress step that turns straight quotes and dashes into “smart” typographic characters — MAM turns it off so those special characters never get injected in the first place, which keeps the text simpler and safer to render on the device. That’s half of MAM’s encoding story; the other half is step 3, below.
One subtlety in the single-post path worth flagging: in
local-app-wp-post-content-class.php, MAM computes the filtered$content, but the field that actually ships to the app is then re-derived from the rawpost_contentduring the encoding step (see step 3) — while the page path and the category-list path ship the filtered HTML directly. If a single post looks less processed than it does on the website, this is why. Flag it to engineering rather than assuming something’s broken.
2. The featured image is extracted into image fields
If the post has a featured image (WordPress “post thumbnail”), MAM pulls the full-size version and writes a small set of fields so the app can display and cache it:
if ( has_post_thumbnail( $post->ID ) ) {
$image = get_post_thumbnail_id( $post->ID );
$featured_image = wp_get_attachment_image_src( $image, 'full' );
$featured_image = $featured_image[0];
// ...image url, a sanitized filename, the file extension, and the attachment id
}
A few things worth knowing:
- It’s the WordPress featured image, not the first image in the body. Whatever you’ve set as the post’s featured image is exactly what the app shows for that post. If the app is showing the “wrong” image, that’s the first place to check.
- The full-size original is used (
wp_get_attachment_image_src( $image, 'full' )), not a thumbnail crop — so a very large original travels to the device as-is. Right-sizing your source images keeps the app lean. - If there is no featured image, no image is shipped. The single-post path seeds the image fields with blank placeholder values before checking for a thumbnail, so a post with no featured image ends up with blank image fields; the page and category-list paths simply skip the image fields altogether. Either way, you get no image, never an error.
Behind the scenes, MAM also derives a sanitized filename (spaces and slashes in the URL become dashes) and records the file extension and the WordPress attachment ID. These exist so the app can cache the image on the device and know what kind of file it’s dealing with. The exact field names are part of the app’s data contract — you’ll never need to touch them, and developers should treat them as a frozen surface rather than renaming them.
3. The text is normalized for the device
WordPress content can contain characters from across the full Unicode range — smart quotes pasted from a word processor, em-dashes, accented characters, emoji. To make the body safe to transport and render, MAM normalizes it, and in the single-post path that’s done with iconv:
$content = iconv( 'UTF-8', 'ASCII//TRANSLIT', $post->post_content );
ASCII//TRANSLIT asks PHP to transliterate the text from UTF-8 down toward plain ASCII — converting characters that have a reasonable ASCII equivalent (a curly quote toward a straight quote, an accented letter toward its unaccented form) instead of leaving raw multibyte bytes in the payload. Combined with turning off wptexturize in step 1, the goal is the same both times: keep the body in a simple, predictable character set so it renders consistently on the device.
This step is behind the most common “the app text doesn’t quite match the website” reports:
- Typographic characters get simplified. A fancy curly quote on the website may show up as a plain straight quote in the app; an em-dash may get simplified too. That’s the transliteration doing its job, not a bug.
- Characters with no ASCII equivalent may be dropped or substituted. Because the target is ASCII, characters far outside it — some emoji, some non-Latin scripts — may not survive transliteration cleanly. If a customer’s content leans heavily on non-Latin scripts or emoji in the body, that’s worth raising with engineering; the current normalization is tuned for content that’s predominantly Latin-script.
- The category-list and page paths do not currently apply
iconv. They ship thethe_content-filtered HTML directly (withwptexturizestill removed), so the same post can normalize a little differently depending on whether you’re viewing it as a single post, a single page, or one row in a category list. Older commented-out code in the content classes shows earlier attempts at the same problem — astr_replacecharacter swap in the single-post class and anmb_convert_encodingcall in the category-list class — a sign this step has evolved over time and is a reasonable candidate to standardize. If you notice this kind of cross-path inconsistency, treat it as a known rough edge rather than something misconfigured on your end.
Putting it together
For a WordPress-backed button, here’s conceptually what the app receives for each post:
post body → the_content filter (wptexturize removed) → encoding normalization → "data" / "content"
featured img → full-size attachment src → image url + sanitized filename + extension + attachment id
The app then renders that HTML body and shows the featured image at the top of the screen. There’s no live round-trip to WordPress when the body is viewed — everything was assembled the moment the app requested its data payload. That’s why an edit on the website only shows up in the app after it next pulls fresh data, and why everything described above gets baked in at that pull, not worked out on the device.
How this connects to the rest of MAM
- Content classes are the building blocks all of this lives inside — each WordPress-content button is one content class, and
get_data_for_app()is the method that produces the payload described here. See Content classes overview. - The phone-data pipeline is what calls
get_data_for_app()for each button whenever the app requests its data — see the phone-data pipeline overview for where in the request this happens. - Web URL is the alternative: if you want the app to show the live web page — running JavaScript, rendering exactly like a browser — that’s a different content type, and none of the filtering or encoding above applies. The device just loads the URL directly.
- The app data contract — the image and body field names produced here — is a frozen surface. You configure which post shows; developers should never rename the produced fields without a coordinated migration.
What to take away
- App content for a WordPress page or post is a server-built snapshot — not live WordPress.
- The body is run through
the_content(so shortcodes and content filters apply) withwptexturizeremoved. - The featured image (full size) is what shows — not the first inline image.
- Text is normalized toward ASCII, which is why smart quotes and some special characters look simpler in the app than on the website.
- A few path-to-path inconsistencies exist (single post vs. page vs. category list) in how aggressively the encoding gets normalized — if content looks different across those views, that’s the cause, and it’s worth a note to engineering rather than a change to your settings.
