PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.2
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.2
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
← All changes | includes/class-metasync-seo-inventory-builder.php +33 -6 2.6.9 → 2.7.2 View file →
@@ -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 /**