__( 'Get reco conversion', 'ai-eshop-optimizer' ), 'description' => __( 'Per-surface impression → cart-add conversion ratio. Joins `wp_aieo_reco_events` to `wp_aieo_addcart_events` (target_pid + surface alignment) to show which recommendation rails actually drive add-to-cart.', 'ai-eshop-optimizer' ), 'category' => \AIEO\Claude\Bootstrap::CATEGORY, 'input_schema' => self::input_schema(), 'output_schema' => array( 'type' => 'object' ), 'execute_callback' => array( __CLASS__, 'execute' ), 'permission_callback' => array( __CLASS__, 'permission_check' ), 'meta' => array( 'annotations' => array( 'readonly' => true, 'idempotent' => true, ), 'show_in_rest' => true, ), ) ); } public static function permission_check( $input = null ) { unset( $input ); return current_user_can( 'manage_woocommerce' ); } private static function input_schema() { return array( 'default' => array(), 'type' => 'object', 'properties' => array( 'period' => array( 'type' => 'string', 'default' => 'last_7_days', 'enum' => PeriodHelper::ALLOWED, 'description' => 'Time window. Defaults to last_7_days.', ), ), ); } public static function execute( $input ) { global $wpdb; $input = is_array( $input ) ? $input : array(); $period = PeriodHelper::resolve( $input['period'] ?? 'last_7_days' ); $reco = $wpdb->prefix . 'aieo_reco_daily'; $addcart = $wpdb->prefix . 'aieo_addcart_events'; $exists = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME IN (%s, %s)", $reco, $addcart ) ); if ( $exists < 2 ) { return array( 'period' => $period, 'rows' => array(), 'note' => __( 'Required attribution tables not yet installed.', 'ai-eshop-optimizer' ), ); } $impressions_by_surface = $wpdb->get_results( $wpdb->prepare( "SELECT surface, SUM(impressions) AS impressions, COUNT(DISTINCT CASE WHEN impressions > 0 THEN target_pid END) AS distinct_targets FROM {$reco} WHERE date BETWEEN DATE(%s) AND DATE(%s) GROUP BY surface HAVING impressions > 0", $period['since'], $period['until'] ), ARRAY_A ); $addcarts_by_surface = $wpdb->get_results( $wpdb->prepare( "SELECT source AS surface, COUNT(*) AS cart_adds, SUM(quantity) AS units, COUNT(DISTINCT product_id) AS distinct_products FROM {$addcart} WHERE ts_added BETWEEN %s AND %s GROUP BY source", $period['since'], $period['until'] ), ARRAY_A ); $map = array(); foreach ( (array) $impressions_by_surface as $r ) { $map[ (string) $r['surface'] ] = array( 'surface' => (string) $r['surface'], 'impressions' => (int) $r['impressions'], 'distinct_targets' => (int) $r['distinct_targets'], 'cart_adds' => 0, 'units' => 0, 'cart_add_rate' => 0.0, ); } foreach ( (array) $addcarts_by_surface as $r ) { $surface = (string) $r['surface']; if ( ! isset( $map[ $surface ] ) ) { $map[ $surface ] = array( 'surface' => $surface, 'impressions' => 0, 'distinct_targets' => 0, 'cart_adds' => 0, 'units' => 0, 'cart_add_rate' => 0.0, ); } $map[ $surface ]['cart_adds'] = (int) $r['cart_adds']; $map[ $surface ]['units'] = (int) $r['units']; $map[ $surface ]['distinct_products'] = (int) $r['distinct_products']; } foreach ( $map as &$row ) { if ( $row['impressions'] > 0 ) { $row['cart_add_rate'] = round( $row['cart_adds'] / $row['impressions'], 4 ); } } unset( $row ); usort( $map, static function ( $a, $b ) { return $b['impressions'] <=> $a['impressions']; } ); return array( 'period' => $period, 'rows' => array_values( $map ), 'note' => __( "cart_add_rate joins via surface only. A cart-add counts when its `source` matches the impression `surface` within the period.", 'ai-eshop-optimizer' ), ); } }