Skip to content

Commit 8681cd1

Browse files
authored
Merge pull request #1727 from equalizedigital/steve/pro-726-when-site-has-latest-posts-set-as-the-home-location-the-scan
Fix: use correct post ID when site homepage is set to latest posts (PRO-726)
2 parents ae89430 + 0f5e9ae commit 8681cd1

4 files changed

Lines changed: 218 additions & 5 deletions

File tree

admin/class-enqueue-admin.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ public static function maybe_enqueue_admin_and_editor_app_scripts() {
7878

7979
global $post;
8080
$post_id = is_object( $post ) ? $post->ID : null;
81+
82+
// On a latest-posts homepage the global $post is the first blog post, not the page;
83+
// let extensions supply the correct ID (e.g. a Pro virtual-page ID).
84+
$post_id = apply_filters( 'edac_filter_admin_post_id', $post_id );
85+
8186
wp_enqueue_script( 'edac', plugin_dir_url( EDAC_PLUGIN_FILE ) . 'build/admin.bundle.js', [ 'jquery' ], EDAC_VERSION, false );
8287
wp_set_script_translations( 'edac', 'accessibility-checker', plugin_dir_path( EDAC_PLUGIN_FILE ) . 'languages' );
8388

@@ -99,8 +104,9 @@ public static function maybe_enqueue_admin_and_editor_app_scripts() {
99104

100105
if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
101106

102-
// Is this posttype setup to be checked?
103-
$active = $is_scannable_post;
107+
// Base the scannable check on the filtered $post_id, not the original global $post.
108+
$filtered_post_type = $post_id ? get_post_type( $post_id ) : false;
109+
$active = $filtered_post_type && is_array( $post_types ) && in_array( $filtered_post_type, $post_types, true );
104110

105111
$pro = defined( 'EDACP_VERSION' ) && EDAC_KEY_VALID;
106112

@@ -113,8 +119,15 @@ public static function maybe_enqueue_admin_and_editor_app_scripts() {
113119
wp_enqueue_script( 'edac-editor-app', plugin_dir_url( EDAC_PLUGIN_FILE ) . 'build/editorApp.bundle.js', false, EDAC_VERSION, false );
114120
wp_set_script_translations( 'edac-editor-app', 'accessibility-checker', plugin_dir_path( EDAC_PLUGIN_FILE ) . 'languages' );
115121

116-
// If this is the frontpage or homepage, preview URLs won't work. Use the live URL.
117-
if ( (int) get_option( 'page_on_front' ) === $post_id || (int) get_option( 'page_for_posts' ) === $post_id ) {
122+
// Preview URLs don't work for the homepage. On a latest-posts homepage (including the
123+
// show_on_front=page fallback with no static front page) use the live home URL instead.
124+
$show_on_front = get_option( 'show_on_front', 'posts' );
125+
$is_latest_posts_home = ( 'posts' === $show_on_front || ( 'page' === $show_on_front && ! get_option( 'page_on_front' ) ) )
126+
&& apply_filters( 'edac_filter_post_is_latest_posts_home', false, $post_id );
127+
128+
if ( $is_latest_posts_home ) {
129+
$scan_url = add_query_arg( 'edac_pageScanner', 1, trailingslashit( get_home_url() ) );
130+
} elseif ( (int) get_option( 'page_on_front' ) === $post_id || (int) get_option( 'page_for_posts' ) === $post_id ) {
118131
$scan_url = add_query_arg( 'edac_pageScanner', 1, get_permalink( $post_id ) );
119132
} else {
120133
$post_view_link = apply_filters(

includes/classes/class-enqueue-frontend.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,14 @@ public static function maybe_enqueue_frontend_highlighter() {
102102

103103
// Don't load on the frontend if we don't have a post to work with.
104104
global $post;
105-
$post_id = apply_filters( 'edac_filter_frontend_highlight_post_id', is_object( $post ) ? $post->ID : null );
105+
106+
// On a latest-posts homepage the global $post is the first blog post, so using its ID
107+
// would misattribute results; pass null and let the filter supply an ID (Pro) or bail.
108+
$default_post_id = ( is_home() && is_front_page() )
109+
? null
110+
: ( is_object( $post ) ? $post->ID : null );
111+
112+
$post_id = apply_filters( 'edac_filter_frontend_highlight_post_id', $default_post_id );
106113

107114
if ( null === $post_id ) {
108115
return;

tests/phpunit/Admin/EnqueueAdminTest.php

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,147 @@ public function testSrOnlyFormatDoesNotEnqueueOnOtherAdminPages() {
461461
}
462462

463463

464+
/**
465+
* Test that edac_filter_admin_post_id overrides the post ID localized into edac_script_vars.
466+
*
467+
* @return void
468+
*/
469+
public function testAdminPostIdFilterOverridesLocalizedPostId() {
470+
global $post, $pagenow, $wp_scripts;
471+
472+
$original_post = $this->factory()->post->create_and_get();
473+
$alternate_post = $this->factory()->post->create_and_get();
474+
$post = $original_post;
475+
$pagenow = 'post.php';
476+
477+
$filter_callback = static function () use ( $alternate_post ) {
478+
return $alternate_post->ID;
479+
};
480+
add_filter( 'edac_filter_admin_post_id', $filter_callback );
481+
482+
$this->enqueue_admin::maybe_enqueue_admin_and_editor_app_scripts();
483+
484+
remove_filter( 'edac_filter_admin_post_id', $filter_callback );
485+
486+
$localized_data = $wp_scripts->get_data( 'edac', 'data' );
487+
$this->assertStringContainsString( (string) $alternate_post->ID, $localized_data );
488+
}
489+
490+
/**
491+
* When the filter flags a latest-posts homepage (show_on_front=posts), the scan URL
492+
* uses get_home_url() rather than an invalid preview link.
493+
*
494+
* @return void
495+
*/
496+
public function testScanUrlUsesHomeUrlWhenLatestPostsHomeFilterReturnsTrue() {
497+
global $post, $pagenow, $wp_scripts;
498+
499+
$post = $this->factory()->post->create_and_get( [ 'post_type' => 'page' ] );
500+
$pagenow = 'post.php';
501+
502+
update_option( 'show_on_front', 'posts' );
503+
update_option( 'page_for_posts', 0 );
504+
505+
$filter_callback = static function () {
506+
return true;
507+
};
508+
add_filter( 'edac_filter_post_is_latest_posts_home', $filter_callback );
509+
510+
$this->enqueue_admin::maybe_enqueue_admin_and_editor_app_scripts();
511+
512+
remove_filter( 'edac_filter_post_is_latest_posts_home', $filter_callback );
513+
delete_option( 'show_on_front' );
514+
delete_option( 'page_for_posts' );
515+
516+
$localized_data = $wp_scripts->get_data( 'edac-editor-app', 'data' );
517+
$this->assertStringContainsString( 'edac_pageScanner', $localized_data );
518+
$this->assertStringNotContainsString( 'preview=true', $localized_data );
519+
// The scan URL should be based on the home URL, not a preview link.
520+
// In WP 6.9 forward slashes are no longer escaped in json_encode output; handle both forms.
521+
// See: https://github.com/WordPress/wordpress-develop/pull/9557.
522+
$expected_home = esc_url_raw( trailingslashit( get_home_url() ) );
523+
if ( version_compare( get_bloginfo( 'version' ), '6.9', '<' ) ) {
524+
$expected_home = str_replace( '/', '\\/', $expected_home );
525+
}
526+
$this->assertStringContainsString( $expected_home, $localized_data );
527+
}
528+
529+
/**
530+
* Fallback case: show_on_front=page with no static front page configured also
531+
* counts as a latest-posts homepage, so the scan URL still uses get_home_url().
532+
*
533+
* @return void
534+
*/
535+
public function testScanUrlUsesHomeUrlWhenShowOnFrontIsPageWithNoFrontPageConfigured() {
536+
global $post, $pagenow, $wp_scripts;
537+
538+
$post = $this->factory()->post->create_and_get( [ 'post_type' => 'page' ] );
539+
$pagenow = 'post.php';
540+
541+
update_option( 'show_on_front', 'page' );
542+
delete_option( 'page_on_front' ); // No static front page configured — WP falls back to latest posts.
543+
544+
$filter_callback = static function () {
545+
return true;
546+
};
547+
add_filter( 'edac_filter_post_is_latest_posts_home', $filter_callback );
548+
549+
$this->enqueue_admin::maybe_enqueue_admin_and_editor_app_scripts();
550+
551+
remove_filter( 'edac_filter_post_is_latest_posts_home', $filter_callback );
552+
delete_option( 'show_on_front' );
553+
554+
$localized_data = $wp_scripts->get_data( 'edac-editor-app', 'data' );
555+
$this->assertStringContainsString( 'edac_pageScanner', $localized_data );
556+
$this->assertStringNotContainsString( 'preview=true', $localized_data );
557+
// The scan URL should be based on the home URL, not a preview link.
558+
// In WP 6.9 forward slashes are no longer escaped in json_encode output; handle both forms.
559+
// See: https://github.com/WordPress/wordpress-develop/pull/9557.
560+
$expected_home = esc_url_raw( trailingslashit( get_home_url() ) );
561+
if ( version_compare( get_bloginfo( 'version' ), '6.9', '<' ) ) {
562+
$expected_home = str_replace( '/', '\\/', $expected_home );
563+
}
564+
$this->assertStringContainsString( $expected_home, $localized_data );
565+
}
566+
567+
/**
568+
* The 'active' flag must reflect the filtered post ID's type: when the filter returns a
569+
* non-scannable post type, $active is false so the scanner doesn't run.
570+
*
571+
* @return void
572+
*/
573+
public function testActiveReflectsFilteredPostIdPostType() {
574+
global $post, $pagenow, $wp_scripts;
575+
576+
// Global $post is a 'post' type (scannable under current option).
577+
$scannable_post = $this->factory()->post->create_and_get( [ 'post_type' => 'post' ] );
578+
// The filter will return a 'page' ID; make 'page' non-scannable for this test.
579+
$non_scannable_post = $this->factory()->post->create_and_get( [ 'post_type' => 'page' ] );
580+
$post = $scannable_post;
581+
$pagenow = 'post.php';
582+
583+
// Restrict scannable types to 'post' only so 'page' becomes non-scannable.
584+
update_option( 'edac_post_types', [ 'post' ] );
585+
586+
$filter_callback = static function () use ( $non_scannable_post ) {
587+
return $non_scannable_post->ID;
588+
};
589+
add_filter( 'edac_filter_admin_post_id', $filter_callback );
590+
591+
$this->enqueue_admin::maybe_enqueue_admin_and_editor_app_scripts();
592+
593+
remove_filter( 'edac_filter_admin_post_id', $filter_callback );
594+
// Restore original scannable post types.
595+
update_option( 'edac_post_types', [ 'post', 'page' ] );
596+
597+
$localized_data = $wp_scripts->get_data( 'edac-editor-app', 'data' );
598+
$this->assertNotEmpty( $localized_data );
599+
// $active must be false because the filtered post type ('page') is not scannable.
600+
// wp_localize_script serializes PHP false as "" (empty string) in older WP versions
601+
// and may serialize it as JSON false in newer ones — accept both forms.
602+
$this->assertMatchesRegularExpression( '/"active"\s*:\s*(false|"")/', $localized_data );
603+
}
604+
464605
/**
465606
* Helper to set a mock current screen with block editor context.
466607
*

tests/phpunit/includes/classes/EnqueueFrontendTest.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,58 @@ public function testScannerBundleUrlIncludesVersionQueryString(): void {
7373
$this->assertStringContainsString( 'ver=' . EDAC_VERSION, $localized_data );
7474
}
7575

76+
/**
77+
* Highlighter must NOT load on the "latest posts" homepage when no filter overrides the ID.
78+
*
79+
* When show_on_front=posts, the global $post is the first blog post from the main query, not
80+
* the homepage itself. The fix passes null to the filter so the free plugin bails gracefully.
81+
*/
82+
public function testFrontendHighlighterDoesNotLoadOnLatestPostsHomepage(): void {
83+
$admin_id = $this->factory()->user->create( [ 'role' => 'administrator' ] );
84+
wp_set_current_user( $admin_id );
85+
86+
// Create a post so the main query has results.
87+
$this->factory()->post->create_and_get( [ 'post_type' => 'post' ] );
88+
89+
update_option( 'show_on_front', 'posts' );
90+
91+
// Simulate visiting the homepage so is_home() / is_front_page() return true.
92+
$this->go_to( '/' );
93+
94+
Enqueue_Frontend::maybe_enqueue_frontend_highlighter();
95+
96+
$this->assertFalse( wp_script_is( 'edac-frontend-highlighter-app', 'enqueued' ) );
97+
98+
delete_option( 'show_on_front' );
99+
}
100+
101+
/**
102+
* A filter on edac_filter_frontend_highlight_post_id can enable the highlighter on the
103+
* "latest posts" homepage by supplying a valid post ID (e.g. a Pro virtual-page ID).
104+
*/
105+
public function testFrontendHighlighterLoadsOnLatestPostsHomepageWhenFilterProvidesId(): void {
106+
$admin_id = $this->factory()->user->create( [ 'role' => 'administrator' ] );
107+
wp_set_current_user( $admin_id );
108+
109+
$post = $this->factory()->post->create_and_get( [ 'post_type' => 'post' ] );
110+
111+
update_option( 'show_on_front', 'posts' );
112+
113+
$this->go_to( '/' );
114+
115+
$filter_callback = static function () use ( $post ) {
116+
return $post->ID;
117+
};
118+
$this->added_filters['edac_filter_frontend_highlight_post_id'] = $filter_callback;
119+
add_filter( 'edac_filter_frontend_highlight_post_id', $filter_callback );
120+
121+
Enqueue_Frontend::maybe_enqueue_frontend_highlighter();
122+
123+
$this->assertTrue( wp_script_is( 'edac-frontend-highlighter-app', 'enqueued' ) );
124+
125+
delete_option( 'show_on_front' );
126+
}
127+
76128
/**
77129
* Helper: enqueue the frontend highlighter as an admin and return the localized data string.
78130
*

0 commit comments

Comments
 (0)