You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a post or page has an Edit Flow custom status, its post_name is intentionally kept empty (see #523, #633). This breaks WordPress's page template hierarchy: page-{slug}.php can never match, so WordPress falls back to page.php — even when the theme has a slug-specific template the author expects to see in preview. ACF conditional logic tied to templates breaks for the same reason.
Reproduction
In a theme, create page-my-test-page.php with obvious markup.
Create a page with slug my-test-page, leave it in Draft (or any Edit Flow custom status).
Click "Preview in new tab".
Observe: page.php renders, not page-my-test-page.php.
Deactivate Edit Flow → preview renders page-my-test-page.php as expected.
Reported by a user at https://wordpress.org/support/topic/page-preview-using-incorrect-page-template/. They also noted that on their live site the slug appeared populated on the main edit screen but blank in Quick Edit — consistent with post_name never having been stored in the first place, while the edit screen shows the derived sample permalink via fix_get_sample_permalink().
Root cause
Two filters in modules/custom-status/custom-status.php:
maybe_keep_post_name_empty() (line 1641) on wp_insert_post_data — forces post_name to '' whenever the save payload doesn't include one, for any post/page with a custom status.
fix_unique_post_slug() (line 1680) on pre_wp_unique_post_slug — returns '' to stop core auto-generating one.
Both are labelled "hack! hack! hack!" in-source. Their original purpose (#123, 2012; #523, 2019; PR #575, 2020) was editorial: keep the slug tied to the final published title instead of freezing it from an early working title, and avoid drafts participating in slug-uniqueness contention.
get_page_template() (and the rest of the page template hierarchy) relies on $post->post_name to resolve page-{slug}.php. An empty post_name means only the generic fallback can match, so template selection silently degrades for every previewed draft with a custom status.
Questioning the premise
The editorial argument for this workaround is weaker than the code comments suggest:
Drafts aren't publicly reachable. There's no URL leak to prevent — drafts 404 for anyone who can't see them, and Edit Flow's own fix_preview_link_part_two() routes previews through ?p= / ?page_id= rather than the slug.
Slug rot is the author's job. Teams who care about slug hygiene (SEO, editors, authors) already check and update the slug before publish. A mysterious -2 suffix on a reused slug is an occasional, easily-fixed annoyance for a few.
The cost hits everyone, not just those with slug conflicts. Every previewed draft loses the correct template. That's a much bigger blast radius than the problem the workaround was trying to solve.
If the workaround were removed today, the question is whether any of the specific core/editor misbehaviours that motivated it still occur. Comments in #523 and PR #575 point to one concrete regression in particular:
"It appears that since the $_POST['post_name'] element is not set when editing a post in Gutenberg, the function always thinks the user did not set a custom slug, and therefore it clears the post slug." — @kjbenk, #523 (Oct 2019)
That was the specific bug that justified replacing @kjbenk's "just remove it" suggestion with the slug-emptying filters we have today. It needs re-verifying against current WordPress + Gutenberg before we can safely simplify.
Possible next steps
Re-verify the premise. Test against current WP trunk and current Gutenberg: when saving a post with a custom status through the block editor's normal save path, does post_name still get wiped if Edit Flow's filters are disabled? Same question for the Classic Editor and Quick Edit paths that motivated Bug: updating post slugs in Quick Edit and Classic Editor with a status different from Published #633. If core has tightened this up (plausible given several years of work on post-status handling and the REST save path), the whole workaround becomes candidate for removal.
Synthesise post_name at preview time only. If the core issue in (1) still holds and we can't remove the workaround, hook the_preview / template_include so that when a custom-status post is being previewed, $post->post_name is filled in-memory from sanitize_title( $post->post_title ). Nothing persists; the DB still sees an empty post_name; page-{slug}.php resolves correctly. PR Fix slug behaviour #575's persistence assertions remain green.
Defensive hardening of maybe_keep_post_name_empty(). Extend the "intentionally set" check to also honour an already-stored post_name from get_post( $postarr['ID'] ). This currently works via wp_update_post()'s own backfill for most callers, but an explicit guard makes the filter consistent with fix_unique_post_slug() (which already reads the stored post_name). Small and cheap; doesn't fix this bug on its own, but closes off a theoretical way to wipe a set slug.
Document the trade-off in the FAQ so theme authors who hit "wrong template on preview" have a pointer while (1) and (2) are worked out.
Preference order: (1) first — if the core misbehaviour is gone, we can delete the whole mess. If not, (2) is the correct scoped fix.
Summary
When a post or page has an Edit Flow custom status, its
post_nameis intentionally kept empty (see #523, #633). This breaks WordPress's page template hierarchy:page-{slug}.phpcan never match, so WordPress falls back topage.php— even when the theme has a slug-specific template the author expects to see in preview. ACF conditional logic tied to templates breaks for the same reason.Reproduction
page-my-test-page.phpwith obvious markup.my-test-page, leave it in Draft (or any Edit Flow custom status).page.phprenders, notpage-my-test-page.php.page-my-test-page.phpas expected.Reported by a user at https://wordpress.org/support/topic/page-preview-using-incorrect-page-template/. They also noted that on their live site the slug appeared populated on the main edit screen but blank in Quick Edit — consistent with
post_namenever having been stored in the first place, while the edit screen shows the derived sample permalink viafix_get_sample_permalink().Root cause
Two filters in
modules/custom-status/custom-status.php:maybe_keep_post_name_empty()(line 1641) onwp_insert_post_data— forcespost_nameto''whenever the save payload doesn't include one, for any post/page with a custom status.fix_unique_post_slug()(line 1680) onpre_wp_unique_post_slug— returns''to stop core auto-generating one.Both are labelled "hack! hack! hack!" in-source. Their original purpose (#123, 2012; #523, 2019; PR #575, 2020) was editorial: keep the slug tied to the final published title instead of freezing it from an early working title, and avoid drafts participating in slug-uniqueness contention.
get_page_template()(and the rest of the page template hierarchy) relies on$post->post_nameto resolvepage-{slug}.php. An emptypost_namemeans only the generic fallback can match, so template selection silently degrades for every previewed draft with a custom status.Questioning the premise
The editorial argument for this workaround is weaker than the code comments suggest:
fix_preview_link_part_two()routes previews through?p=/?page_id=rather than the slug.-2suffix on a reused slug is an occasional, easily-fixed annoyance for a few.If the workaround were removed today, the question is whether any of the specific core/editor misbehaviours that motivated it still occur. Comments in #523 and PR #575 point to one concrete regression in particular:
That was the specific bug that justified replacing @kjbenk's "just remove it" suggestion with the slug-emptying filters we have today. It needs re-verifying against current WordPress + Gutenberg before we can safely simplify.
Possible next steps
Re-verify the premise. Test against current WP trunk and current Gutenberg: when saving a post with a custom status through the block editor's normal save path, does
post_namestill get wiped if Edit Flow's filters are disabled? Same question for the Classic Editor and Quick Edit paths that motivated Bug: updating post slugs in Quick Edit and Classic Editor with a status different from Published #633. If core has tightened this up (plausible given several years of work on post-status handling and the REST save path), the whole workaround becomes candidate for removal.Synthesise
post_nameat preview time only. If the core issue in (1) still holds and we can't remove the workaround, hookthe_preview/template_includeso that when a custom-status post is being previewed,$post->post_nameis filled in-memory fromsanitize_title( $post->post_title ). Nothing persists; the DB still sees an emptypost_name;page-{slug}.phpresolves correctly. PR Fix slug behaviour #575's persistence assertions remain green.Defensive hardening of
maybe_keep_post_name_empty(). Extend the "intentionally set" check to also honour an already-storedpost_namefromget_post( $postarr['ID'] ). This currently works viawp_update_post()'s own backfill for most callers, but an explicit guard makes the filter consistent withfix_unique_post_slug()(which already reads the storedpost_name). Small and cheap; doesn't fix this bug on its own, but closes off a theoretical way to wipe a set slug.Document the trade-off in the FAQ so theme authors who hit "wrong template on preview" have a pointer while (1) and (2) are worked out.
Preference order: (1) first — if the core misbehaviour is gone, we can delete the whole mess. If not, (2) is the correct scoped fix.
Environment reported
WP 6.9.1, ACF 6.7.0.2, Edit Flow 0.10.3.