> */ private const CATEGORY_TEMPLATES = array( 'coffee' => array( 'best coffee mugs under $30', 'affordable coffee accessories', 'coffee gifts for home barista', ), 'clothing' => array( 'casual shirts for men under $50', "women's summer tops", 'affordable everyday basics', ), 'electronics' => array( 'budget home office accessories', 'affordable desk gadgets', 'best USB hubs under $40', ), 'shoes' => array( 'comfortable walking shoes under $80', 'affordable running shoes', 'best casual sneakers', ), 'jewelry' => array( 'affordable jewelry gifts', 'everyday jewelry under $50', 'minimalist necklaces and bracelets', ), 'home' => array( 'best home decor under $30', 'affordable kitchen gadgets', 'top rated home accessories', ), 'beauty' => array( 'best skincare products under $30', 'affordable beauty essentials', 'natural beauty products online', ), 'toys' => array( 'best educational toys for kids', 'affordable toys under $25', 'popular toys for toddlers', ), ); /** * Generate queries tailored to the store's product categories. * * @return array Array of query strings. */ public function generate_queries_for_store(): array { $categories = $this->get_top_categories( 5 ); $queries = array(); foreach ( $categories as $category ) { $cat_queries = $this->get_queries_for_category( $category ); $queries = array_merge( $queries, $cat_queries ); } if ( empty( $queries ) ) { $queries = $this->get_generic_queries(); } return array_slice( $queries, 0, self::MAX_DAILY_QUERIES ); } /** * Get all queries for today's run. * * @return array */ public function get_all_queries(): array { return $this->generate_queries_for_store(); } /** * Detect if the AI response mentions the store. * * @param string $ai_response Raw AI response text. * @param string $store_url Store URL. * @param string $store_name Store name. * * @return bool True if store is mentioned. */ public function detect_own_mention( string $ai_response, string $store_url, string $store_name ): bool { $domain = wp_parse_url( $store_url, PHP_URL_HOST ); $domain_simple = $domain ? str_replace( 'www.', '', $domain ) : ''; $name_lower = strtolower( $store_name ); $response_lower = strtolower( $ai_response ); if ( $domain_simple && str_contains( $response_lower, strtolower( $domain_simple ) ) ) { return true; } if ( $name_lower && strlen( $name_lower ) > 2 && str_contains( $response_lower, $name_lower ) ) { return true; } return false; } /** * Detect competitor domain mentions in an AI response. * * @param string $ai_response Raw AI response text. * @param string[] $competitor_domains Array of competitor domains. * * @return array Domain => mention count. */ public function detect_competitor_mentions( string $ai_response, array $competitor_domains ): array { $mentions = array(); $response_lower = strtolower( $ai_response ); foreach ( $competitor_domains as $domain ) { $simple = strtolower( str_replace( 'www.', '', $domain ) ); if ( str_contains( $response_lower, $simple ) ) { $mentions[ $domain ] = substr_count( $response_lower, $simple ); } } return $mentions; } /** * Get queries for a specific category. * * @param string $category Category slug or name. * * @return array */ private function get_queries_for_category( string $category ): array { $cat_lower = strtolower( $category ); // Check for exact template match. foreach ( self::CATEGORY_TEMPLATES as $key => $templates ) { if ( str_contains( $cat_lower, $key ) ) { return $templates; } } // Generic fallback using category name. $avg_price = $this->get_category_avg_price( $category ); $price_str = $avg_price > 0 ? ' under $' . (int) ( $avg_price * 1.5 ) : ''; return array( "best {$cat_lower} products{$price_str}", "top rated {$cat_lower} items", "affordable {$cat_lower} for home", ); } /** * Get generic queries when no categories are available. * * @return array */ private function get_generic_queries(): array { return array( 'best products to buy online', 'affordable online shopping recommendations', 'top rated products under $50', ); } /** * Get top product categories by product count. * * @param int $limit Max categories to return. * * @return array Category names. */ private function get_top_categories( int $limit ): array { $terms = get_terms( array( 'taxonomy' => 'product_cat', 'orderby' => 'count', 'order' => 'DESC', 'number' => $limit, 'hide_empty' => true, ) ); if ( is_wp_error( $terms ) || empty( $terms ) ) { return array(); } return array_map( static function ( $term ) { return $term->name; }, $terms ); } /** * Get average product price in a category. * * @param string $category Category name. * * @return float Average price or 0. */ private function get_category_avg_price( string $category ): float { $term = get_term_by( 'name', $category, 'product_cat' ); if ( ! $term ) { $term = get_term_by( 'slug', $category, 'product_cat' ); } if ( ! $term ) { return 0.0; } $query = new \WC_Product_Query( array( 'status' => 'publish', 'limit' => 50, 'category' => array( $term->slug ), ) ); $products = $query->get_products(); if ( empty( $products ) ) { return 0.0; } $total = 0.0; $count = 0; foreach ( $products as $product ) { $price = (float) $product->get_price(); if ( $price > 0 ) { $total += $price; ++$count; } } return $count > 0 ? $total / $count : 0.0; } }