guard_manager(); $on = isset( $_POST['on'] ) && '1' === (string) $_POST['on']; AIEO_DMM_Settings::update( array( 'seo' => array( 'dfs_weekly_pull' => $on ) ) ); wp_send_json_success( array( 'on' => $on ) ); } public function ajax_dfs_pull() { $this->guard_manager(); if ( ! class_exists( 'AIEO_DFS_Rankings' ) ) { require_once AIEO_DIR . 'includes/seo/class-aieo-dfs-rankings.php'; } if ( isset( $_POST['location_code'], $_POST['language_code'] ) ) { AIEO_DFS_Rankings::save_locale( (int) $_POST['location_code'], sanitize_key( wp_unslash( $_POST['language_code'] ) ) ); } if ( isset( $_POST['budget_usd'] ) ) { AIEO_DMM_Settings::update( array( 'seo' => array( 'dfs_budget_usd' => max( 0, (float) $_POST['budget_usd'] ) ) ) ); } $res = AIEO_DFS_Rankings::pull(); if ( isset( $res['error'] ) ) { wp_send_json_error( array( 'message' => $res['error'] ) ); } if ( isset( $res['skipped'] ) ) { wp_send_json_error( array( 'message' => sprintf( __( 'Pull skipped: %s', 'ai-eshop-optimizer' ), $res['skipped'] ) ) ); } wp_send_json_success( array( 'message' => sprintf( __( 'Snapshot: %1$d ranked keywords ($%2$s). Spend this month: $%3$s of $%4$s.', 'ai-eshop-optimizer' ), (int) $res['rows'], number_format_i18n( (float) $res['cost'], 4 ), number_format_i18n( AIEO_DFS_Rankings::spend_this_month(), 4 ), number_format_i18n( AIEO_DFS_Rankings::budget(), 2 ) ), ) ); } private function guard_manager() { AIEO_DMM::verify_ajax_request(); if ( ! current_user_can( 'manage_woocommerce' ) && ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Insufficient permissions for a site-wide change.', 'ai-eshop-optimizer' ) ) ); } } public function ajax_dfs_connect() { $this->guard_manager(); if ( ! class_exists( 'AIEO_DataForSEO' ) ) { require_once AIEO_DIR . 'includes/seo/class-aieo-dataforseo.php'; } $raw = isset( $_POST['credentials'] ) ? trim( (string) wp_unslash( $_POST['credentials'] ) ) : ''; if ( '' !== $raw ) { $saved = AIEO_DataForSEO::save_credentials( $raw ); if ( is_wp_error( $saved ) ) { wp_send_json_error( array( 'message' => $saved->get_error_message() ) ); } } elseif ( ! AIEO_DataForSEO::is_connected() ) { wp_send_json_error( array( 'message' => __( 'Paste the API credentials first.', 'ai-eshop-optimizer' ) ) ); } $test = AIEO_DataForSEO::test_connection(); if ( is_wp_error( $test ) ) { wp_send_json_error( array( 'message' => $test->get_error_message() ) ); } wp_send_json_success( array( 'message' => sprintf( __( 'Connected as %1$s — balance $%2$s.', 'ai-eshop-optimizer' ), $test['login'], null !== $test['balance'] ? number_format_i18n( $test['balance'], 2 ) : '?' ), 'login' => $test['login'], 'balance' => $test['balance'], ) ); } public function ajax_dfs_disconnect() { $this->guard_manager(); if ( ! class_exists( 'AIEO_DataForSEO' ) ) { require_once AIEO_DIR . 'includes/seo/class-aieo-dataforseo.php'; } AIEO_DataForSEO::disconnect(); wp_send_json_success( array( 'message' => __( 'Disconnected.', 'ai-eshop-optimizer' ) ) ); } public function ajax_backfill_canonical() { AIEO_DMM::verify_ajax_request(); if ( ! current_user_can( 'manage_woocommerce' ) && ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Insufficient permissions for a store-wide change.', 'ai-eshop-optimizer' ) ) ); } if ( ! class_exists( 'AIEO_SEO_Store' ) ) { wp_send_json_error( array( 'message' => __( 'SEO store unavailable.', 'ai-eshop-optimizer' ) ) ); } $after = isset( $_POST['last_id'] ) ? (int) $_POST['last_id'] : 0; global $wpdb; $ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish' AND ID > %d ORDER BY ID ASC LIMIT 200", $after ) ); $set = 0; $last = $after; foreach ( $ids as $pid ) { $pid = (int) $pid; $last = $pid; if ( AIEO_SEO_Store::get_primary_cat_id( 'product', $pid ) > 0 ) { continue; } $primary = class_exists( 'AIEO_SEO_Primary_Term' ) ? (int) AIEO_SEO_Primary_Term::deepest_term_id( $pid, 'product_cat' ) : 0; if ( $primary <= 0 ) { $terms = get_the_terms( $pid, 'product_cat' ); if ( empty( $terms ) || is_wp_error( $terms ) ) { continue; } usort( $terms, static function ( $a, $b ) { return $a->term_id - $b->term_id; } ); $primary = (int) $terms[0]->term_id; } AIEO_SEO_Store::set_primary_term( 'product', $pid, 'product_cat', $primary ); $set++; } wp_send_json_success( array( 'set' => $set, 'scanned' => count( $ids ), 'last_id' => $last, 'done' => count( $ids ) < 200, ) ); } public static function default_settings() { return array( 'enabled' => false, 'separator' => '-', 'site_profile' => 'auto', ); } public function render_subtab() { $stored = (array) AIEO_DMM_Settings::get( 'seo', array() ); $seo = array_merge( self::default_settings(), $stored ); global $wpdb; $hc_count = 0; $hc_table = $wpdb->prefix . 'aieo_seo_head_cache'; if ( (string) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $hc_table ) ) === $hc_table ) { $hc_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$hc_table}`" ); } if ( ! class_exists( 'AIEO_DataForSEO' ) ) { require_once AIEO_DIR . 'includes/seo/class-aieo-dataforseo.php'; } if ( ! class_exists( 'AIEO_DFS_Rankings' ) ) { require_once AIEO_DIR . 'includes/seo/class-aieo-dfs-rankings.php'; } $this->render_template( 'seo/general.php', array( 'dfs_locale' => AIEO_DFS_Rankings::locale(), 'dfs_budget' => AIEO_DFS_Rankings::budget(), 'dfs_spend' => AIEO_DFS_Rankings::spend_this_month(), 'dfs_last_pull' => (array) get_option( AIEO_DFS_Rankings::META_OPT, array() ), 'seo' => $seo, 'competitor' => AIEO_SEO_Store::competitor_seo_plugin(), 'is_active' => AIEO_SEO_Store::is_active_provider(), 'head_cache_count' => $hc_count, 'detected_profile' => AIEO_SEO_Score::detect_site_profile(), 'dfs_connected' => AIEO_DataForSEO::is_connected(), 'dfs_login' => AIEO_DataForSEO::login(), 'nonce' => wp_create_nonce( AIEO_DMM::NONCE_ACTION ), 'ajax' => admin_url( 'admin-ajax.php' ), ) ); } public function ajax_rebuild_head_cache() { AIEO_DMM::verify_ajax_request(); if ( ! class_exists( 'AIEO_SEO_Head_Builder' ) ) { wp_send_json_error( array( 'message' => __( 'SEO builder unavailable.', 'ai-eshop-optimizer' ) ) ); } if ( ! AIEO_SEO_Store::is_active_provider() ) { wp_send_json_error( array( 'message' => __( 'Enable the engine and ensure no competitor SEO plugin is active — the head cache only builds when Rooster One is the active provider.', 'ai-eshop-optimizer' ) ) ); } $reset = ! empty( $_POST['reset'] ); $cursor = $reset ? array( 'phase' => 0, 'last_id' => 0, 'last_tax' => '' ) : array( 'phase' => isset( $_POST['phase'] ) ? (int) $_POST['phase'] : 0, 'last_id' => isset( $_POST['last_id'] ) ? (int) $_POST['last_id'] : 0, 'last_tax' => isset( $_POST['last_tax'] ) ? sanitize_key( wp_unslash( $_POST['last_tax'] ) ) : '', ); $res = AIEO_SEO_Head_Builder::run_backfill( 500, $cursor ); global $wpdb; $t = $wpdb->prefix . 'aieo_seo_head_cache'; $total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$t}`" ); wp_send_json_success( array( 'built' => (int) $res['built'], 'done' => ! empty( $res['done'] ), 'cursor' => $res['cursor'], 'total' => $total, ) ); } public function ajax_save() { $this->guard_manager(); $separator = isset( $_POST['separator'] ) ? sanitize_text_field( wp_unslash( $_POST['separator'] ) ) : '-'; $separator = function_exists( 'mb_substr' ) ? mb_substr( $separator, 0, 8 ) : substr( $separator, 0, 8 ); if ( '' === trim( $separator ) ) { $separator = '-'; } $clean = array( 'enabled' => ! empty( $_POST['enabled'] ), 'separator' => $separator, ); if ( isset( $_POST['autopilot_present'] ) ) { $clean['autopilot'] = ! empty( $_POST['autopilot'] ); } if ( isset( $_POST['ai_write_nightly_present'] ) ) { $clean['ai_write_nightly'] = ! empty( $_POST['ai_write_nightly'] ); } if ( isset( $_POST['autofix_deterministic_present'] ) ) { $clean['autofix_deterministic'] = ! empty( $_POST['autofix_deterministic'] ); } if ( isset( $_POST['site_profile'] ) ) { $profile = sanitize_key( wp_unslash( $_POST['site_profile'] ) ); $clean['site_profile'] = ( 'auto' === $profile || AIEO_SEO_Score::is_profile( $profile ) ) ? $profile : 'auto'; } if ( isset( $_POST['robots_global_present'] ) ) { $clean['robots_global'] = array( 'noindex_paginated' => ! empty( $_POST['noindex_paginated'] ), 'nofollow_paginated' => ! empty( $_POST['nofollow_paginated'] ), 'noindex_date' => ! empty( $_POST['noindex_date'] ), 'noindex_author' => ! empty( $_POST['noindex_author'] ), ); } $old_profile = (string) AIEO_DMM_Settings::get( 'seo.site_profile', 'auto' ); AIEO_DMM_Settings::update( array( 'seo' => $clean ) ); if ( isset( $clean['site_profile'] ) && class_exists( 'AIEO_Catalogue_Mode' ) ) { $choices = isset( $_POST['catalogue_present'] ) ? array( 'cart' => ! empty( $_POST['catalogue_cart'] ), 'prices' => ! empty( $_POST['catalogue_prices'] ), 'requests' => ! empty( $_POST['catalogue_requests'] ), ) : null; AIEO_Catalogue_Mode::follow_profile( $old_profile, (string) $clean['site_profile'], $choices ); } wp_send_json_success( array( 'message' => __( 'SEO settings saved.', 'ai-eshop-optimizer' ) ) ); } }