PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
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 | otto/otto_pixel.php +29 -68 2.7.2 → 2.7.1 View file →
@@ -44,9 +44,8 @@
44 44 require_once plugin_dir_path( __FILE__ ) . '/Otto_pixel_class.php';
45 45 require_once plugin_dir_path( __FILE__ ) . '/metasync-otto-seo-functions.php';
46 46 require_once plugin_dir_path( __FILE__ ) . '/class-metasync-otto-transient-cache.php';
47 47 require_once plugin_dir_path( __FILE__ ) . '/class-metasync-otto-job-status.php';
48 -require_once plugin_dir_path( __FILE__ ) . '/class-metasync-otto-webhook-audit.php';
49 48 require_once plugin_dir_path( __FILE__ ) . '/class-metasync-otto-render-strategy.php';
50 49 require_once plugin_dir_path( __FILE__ ) . '/class-metasync-otto-config.php';
51 50 require_once plugin_dir_path( __FILE__ ) . '/class-metasync-otto-bot-detector.php';
52 51 require_once plugin_dir_path( __FILE__ ) . '/class-metasync-otto-bot-statistics-database.php';
@@ -114,9 +113,8 @@
114 113 # OPTIMIZED: use cached uuid
115 114 $otto_tag = '<meta name="otto" content="uuid='.esc_attr(Metasync_Otto_Config::get_otto_uuid()).'; type=wordpress; enabled='.esc_attr($string_enabled).'; version='.esc_attr($plugin_version).'">';
116 115
117 116 # out the otto tag
118 - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- meta tag assembled on the line above with esc_attr() on every interpolated value
119 117 echo $otto_tag;
120 118 }, 1); # Priority 1 to output early in head
121 119
122 120 /**
@@ -167,13 +165,8 @@
167 165
168 166 # function to register the route
169 167 function metasync_otto_crawl_notify($request){
170 168
171 - # receipt time is captured before validation and scheduling, so the audit
172 - # record describes when WordPress received the delivery, not when its work
173 - # happened to finish.
174 - $received_at = time();
175 -
176 169 # get request data params
177 170 $data = $request->get_json_params();
178 171
179 172 # fields
@@ -193,29 +186,14 @@
193 186 }
194 187
195 188 }
196 189
197 - # The audit trail is deliberately after payload validation: invalid requests
198 - # receive the existing 400 response and are not recorded as deliveries.
199 - # It is also before any scheduling so a valid delivery is captured even if
200 - # later work is deferred or rejected. The failure guard is intentionally
201 - # broader than Exception: a broken option adapter or stale plugin copy must
202 - # never turn an otherwise acknowledged webhook into a 500 response.
203 - try {
204 - if (metasync_otto_class_provides('Metasync_Otto_Webhook_Audit', 'record')) {
205 - Metasync_Otto_Webhook_Audit::record(
206 - $received_at,
207 - $data['domain'],
208 - $data['urls']
209 - );
210 - }
211 - } catch (Throwable $metasync_otto_audit_failure) {
212 - error_log(
213 - 'MetaSync OTTO: failed to record crawl-notify webhook audit entry: '
214 - . $metasync_otto_audit_failure->getMessage()
215 - ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- audit failure must not break webhook acknowledgement
216 - }
190 + # load otto pixel
191 + $otto_pixel = new Metasync_otto_pixel(false);
217 192
193 + # save the otto data first (cheap local DB write — kept synchronous)
194 + $otto_pixel->save_crawl_data($data);
195 +
218 196 # Defer the expensive per-URL work (OTTO API fetch, post meta sync,
219 197 # per-URL cache purge) to background jobs. The webhook caller enforces a
220 198 # strict response-time budget, so the response acknowledges SCHEDULING,
221 199 # never execution. The per-URL status store records what actually
@@ -446,32 +424,10 @@
446 424 }
447 425
448 426 Metasync_Otto_Job_Status::record($route, Metasync_Otto_Job_Status::STATE_COMPLETED, 'job', $retry_count, $outcome);
449 427
450 - } catch (\Throwable $e) {
451 - # Cron must survive both Exception and PHP 7+ Error failures. Always use
452 - # the same bounded retry path, and emit structured context without the URL
453 - # payload or credentials. The retry is booked BEFORE the log attempt so a
454 - # failing logger can never swallow the retry; logging is best-effort.
455 - $schedule_retry('throwable:' . get_class($e));
456 - if (class_exists('Metasync_Error_Logger')) {
457 - try {
458 - Metasync_Error_Logger::log(
459 - Metasync_Error_Logger::CATEGORY_OTTO_RENDER,
460 - Metasync_Error_Logger::SEVERITY_ERROR,
461 - 'OTTO crawl-url job threw; retry policy applied',
462 - [
463 - 'operation' => 'crawl_url_job',
464 - 'outcome' => 'throwable',
465 - 'retry_count' => (int) $retry_count,
466 - 'exception' => get_class($e),
467 - ]
468 - );
469 - } catch (\Throwable $logger_error) {
470 - # Logging must never kill the handler after the retry is booked.
471 - error_log('MetaSync OTTO: crawl-url job error log failed: ' . $logger_error->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets
472 - }
473 - }
428 + } catch (Exception $e) {
429 + $schedule_retry('exception:' . $e->getMessage());
474 430 }
475 431 }
476 432
477 433 /**
@@ -933,9 +889,9 @@
933 889 return;
934 890 }
935 891
936 892 # OPTIMIZED: Check if Otto should be disabled for WP Rocket compatibility
937 - if (defined('WP_ROCKET_VERSION') || class_exists('WP_Rocket')) {
893 + if (class_exists('WP_Rocket')) {
938 894 $wp_rocket_compat_mode = Metasync_Otto_Config::get_wp_rocket_compat_mode();
939 895
940 896 if ($wp_rocket_compat_mode === 'disable_otto') {
941 897 return; # Exit early, Otto is disabled when WP Rocket is active
@@ -941,25 +897,14 @@
941 897 return; # Exit early, Otto is disabled when WP Rocket is active
942 898 }
943 899 }
944 900
945 - # Skip OTTO for Divi AJAX pagination, and for paginated archive requests
946 - # on Divi-built sites.
947 - # ?et_blog = Divi AJAX pagination callback — always skipped, on every
948 - # theme, because Divi fires it regardless of the site layout.
901 + # Skip OTTO for Divi AJAX pagination and paginated archive requests.
902 + # ?et_blog = Divi AJAX pagination callback
949 903 # /page/N/ = paginated blog/archive pages — OTTO's buffer/HTTP render causes
950 904 # module numbering mismatch between page 1 (with TB template) and page N
951 905 # (without TB template), breaking Divi's JS pagination selector matching.
952 - # That mismatch is a Divi rendering bug, so the /page/N/ skip is gated on
953 - # Divi detection: non-Divi sites (Elementor + the7, ...) keep OTTO on real
954 - # paginated archives. Detection covers the Divi theme and its child themes
955 - # (get_template() returns the PARENT template dir, "Divi" either way), the
956 - # Extra theme and the Divi Builder plugin (both define ET_BUILDER_VERSION
957 - # / et_setup_theme — same TB machinery, same bug).
958 - $is_divi = defined('ET_BUILDER_VERSION')
959 - || function_exists('et_setup_theme')
960 - || wp_get_theme()->get_template() === 'Divi';
961 - if (isset($_GET['et_blog']) || ($is_divi && is_paged() && !is_singular())) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only front-end check that skips OTTO
906 + if (isset($_GET['et_blog']) || (is_paged() && !is_singular())) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only front-end check that skips OTTO
962 907 return;
963 908 }
964 909
965 910 # Skip OTTO on search-results pages. A search request carries its
@@ -1102,9 +1047,9 @@
1102 1047 # Detect active plugins. SG Optimizer detection now lives in
1103 1048 # metasync_otto_disable_sg_page_cache(), which is invoked later
1104 1049 # once OTTO confirms suggestions for the URL.
1105 1050 $brizy_active = class_exists('Brizy_Editor') || defined('BRIZY_VERSION');
1106 - $wp_rocket_active = defined('WP_ROCKET_VERSION') || class_exists('WP_Rocket');
1051 + $wp_rocket_active = class_exists('WP_Rocket');
1107 1052
1108 1053 # OPTIMIZED: Get configuration option using cached config
1109 1054 $wp_rocket_compat_mode = Metasync_Otto_Config::get_wp_rocket_compat_mode();
1110 1055
@@ -1177,9 +1122,9 @@
1177 1122 * Only meaningful on SiteGround sites without WP Rocket; a no-op otherwise.
1178 1123 */
1179 1124 function metasync_otto_disable_sg_page_cache() {
1180 1125 # Only relevant when SG Optimizer is active and WP Rocket is not present.
1181 - if (defined('WP_ROCKET_VERSION') || class_exists('WP_Rocket')) {
1126 + if (class_exists('WP_Rocket')) {
1182 1127 return;
1183 1128 }
1184 1129 if (!is_plugin_active('sg-cachepress/sg-cachepress.php')) {
1185 1130 return;
@@ -1904,8 +1849,24 @@
1904 1849 metasync_record_failed_action( 'metasync_process_seo_job' );
1905 1850 return Metasync_Otto_Job_Status::OUTCOME_RETRYABLE;
1906 1851 }
1907 1852 }
1853 +
1854 + # Mark this URL as crawled by OTTO for SSR
1855 + # Extract domain and path from route
1856 + $parsed_url = wp_parse_url($route);
1857 + $domain_with_scheme = ($parsed_url['scheme'] ?? 'https') . '://' . ($parsed_url['host'] ?? '');
1858 + $url_path = ($parsed_url['path'] ?? '/');
1859 +
1860 + # Create crawl data structure
1861 + $crawl_data = array(
1862 + 'domain' => $domain_with_scheme,
1863 + 'urls' => array($url_path)
1864 + );
1865 +
1866 + # Load Otto pixel class and save crawl data
1867 + $otto_pixel = new Metasync_otto_pixel($otto_uuid);
1868 + $otto_pixel->save_crawl_data($crawl_data);
1908 1869
1909 1870 # Get WordPress post ID from URL
1910 1871 $post_id = url_to_postid($route);
1911 1872