| @@ -16,9 +16,9 @@ | ||
| 16 | 16 | |
| 17 | 17 | class Metasync_SEO_Inventory_Builder { |
| 18 | 18 | |
| 19 | 19 | /** |
| 20 | - * Meta keys we read for every post (MCP field set — matches WP-134). | |
| 20 | + * Meta keys we read for every post (MCP field set — matches). | |
| 21 | 21 | */ |
| 22 | 22 | const SEO_META_KEYS = [ |
| 23 | 23 | 'meta_title' => '_metasync_metatitle', |
| 24 | 24 | 'meta_description' => '_metasync_metadesc', |
| @@ -88,12 +88,22 @@ | ||
| 88 | 88 | ], |
| 89 | 89 | ]; |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | - $query = new WP_Query($query_args); | |
| 92 | + // Exclude custom/LPS pages — their SEO is self-managed, so the platform | |
| 93 | + // must not treat them as "missing SEO". | |
| 94 | + $query_args['metasync_exclude_custom_pages'] = true; | |
| 95 | + add_filter('posts_where', 'metasync_filter_exclude_custom_pages_where', 10, 2); | |
| 93 | 96 | |
| 94 | - // Remove the filter immediately so it doesn't affect other queries | |
| 95 | - remove_filter('posts_where', [__CLASS__, 'filter_where_id_gt'], 10); | |
| 97 | + try { | |
| 98 | + $query = new WP_Query($query_args); | |
| 99 | + } finally { | |
| 100 | + // Remove filters immediately so they don't affect other queries | |
| 101 | + if ($cursor > 0) { | |
| 102 | + remove_filter('posts_where', [__CLASS__, 'filter_where_id_gt'], 10); | |
| 103 | + } | |
| 104 | + remove_filter('posts_where', 'metasync_filter_exclude_custom_pages_where', 10); | |
| 105 | + } | |
| 96 | 106 | |
| 97 | 107 | $posts = $query->posts; |
| 98 | 108 | $has_more = count($posts) > $limit; |
| 99 | 109 | |
| @@ -133,9 +143,16 @@ | ||
| 133 | 143 | private static function build_item(WP_Post $post, bool $include_issues): array { |
| 134 | 144 | $post_id = $post->ID; |
| 135 | 145 | |
| 136 | 146 | // Basic info |
| 137 | - $content_text = wp_strip_all_tags($post->post_content); | |
| 147 | + // Page-builder content (Divi [et_pb_*], Elementor, WPBakery) is stored | |
| 148 | + // as shortcodes whose handlers are not registered during a REST inventory request. | |
| 149 | + // Render what we can, then strip registered + leftover shortcode-style tags so raw | |
| 150 | + // builder markup does not leak into the content/word-count sent to SearchAtlas. | |
| 151 | + $content_text = do_shortcode($post->post_content); | |
| 152 | + $content_text = strip_shortcodes($content_text); | |
| 153 | + $content_text = preg_replace('/\[\/?[a-zA-Z][^\]]*\]/', '', $content_text); | |
| 154 | + $content_text = wp_strip_all_tags($content_text); | |
| 138 | 155 | $word_count = str_word_count($content_text); |
| 139 | 156 | |
| 140 | 157 | $item = [ |
| 141 | 158 | 'post_id' => $post_id, |
| @@ -228,8 +245,12 @@ | ||
| 228 | 245 | 'fields' => 'ids', |
| 229 | 246 | 'no_found_rows' => false, // we need found_rows for total |
| 230 | 247 | 'update_post_meta_cache' => false, |
| 231 | 248 | 'update_post_term_cache' => false, |
| 249 | + // Exclude custom/LPS pages so the total matches the excluded item list | |
| 250 | + // in build() — otherwise the platform sees a count larger than the | |
| 251 | + // number of items it can page through. | |
| 252 | + 'metasync_exclude_custom_pages' => true, | |
| 232 | 253 | ]; |
| 233 | 254 | |
| 234 | 255 | if (!empty($modified_after)) { |
| 235 | 256 | $args['date_query'] = [ |
| @@ -240,9 +261,15 @@ | ||
| 240 | 261 | ], |
| 241 | 262 | ]; |
| 242 | 263 | } |
| 243 | 264 | |
| 244 | - $query = new WP_Query($args); | |
| 265 | + add_filter('posts_where', 'metasync_filter_exclude_custom_pages_where', 10, 2); | |
| 266 | + try { | |
| 267 | + $query = new WP_Query($args); | |
| 268 | + } finally { | |
| 269 | + remove_filter('posts_where', 'metasync_filter_exclude_custom_pages_where', 10); | |
| 270 | + } | |
| 271 | + | |
| 245 | 272 | return (int) $query->found_posts; |
| 246 | 273 | } |
| 247 | 274 | |
| 248 | 275 | /** |