__( 'CHATGPT ADS', 'agentic-commerce-for-woocommerce' ), 'title' => __( 'Run ChatGPT Ads without leaving WooCommerce', 'agentic-commerce-for-woocommerce' ), 'sub' => __( 'Campaigns, budgets and results in one place — with the orders we reconciled against your real store shown next to what the ad platform reports. The gap between those two is the most useful number here.', 'agentic-commerce-for-woocommerce' ), ) ); $e = self::eligibility(); self::render_eligibility( $e ); if ( ! $e['eligible'] ) { self::organic_path(); Xpay_UI::close(); return; } if ( ! Xpay_Plugin::is_connected() ) { Xpay_UI::note( 'info', '' . esc_html__( 'Connect your store to continue.', 'agentic-commerce-for-woocommerce' ) . ' ' . esc_html__( 'Ad credentials are held in our backend, never in your WordPress database — an advertising key can spend your money, and a database row is readable by every other plugin on the site and lands in every staging copy.', 'agentic-commerce-for-woocommerce' ) . ' ' . esc_html__( 'Connect →', 'agentic-commerce-for-woocommerce' ) . '' ); Xpay_UI::close(); return; } self::account_state(); Xpay_UI::close(); } /** * Locally computable eligibility. No credentials required to answer this. * * ⛔ Catalog size is reported, NOT gated on. See the class docblock. * * @return array{eligible:bool,products:int,country:string,country_ok:bool} */ public static function eligibility() { $count = 0; if ( function_exists( 'wp_count_posts' ) ) { $counts = wp_count_posts( 'product' ); $count = isset( $counts->publish ) ? (int) $counts->publish : 0; } $country = ''; if ( function_exists( 'wc_get_base_location' ) ) { $loc = wc_get_base_location(); $country = isset( $loc['country'] ) ? (string) $loc['country'] : ''; } $country_ok = in_array( strtoupper( $country ), self::COUNTRIES, true ); return array( 'eligible' => $country_ok, 'products' => $count, 'country' => $country, 'country_ok' => $country_ok, ); } /** * Show where the store stands, before it invests any time. * * @param array $e Eligibility. * @return void */ private static function render_eligibility( $e ) { Xpay_UI::section( __( 'Can your store run ChatGPT Ads?', 'agentic-commerce-for-woocommerce' ), __( 'These are the ad platform\'s requirements, not ours. We check them here so you find out now rather than after setting up an account.', 'agentic-commerce-for-woocommerce' ) ); echo '
'; Xpay_UI::check( 'pass', __( 'Catalog size', 'agentic-commerce-for-woocommerce' ), sprintf( /* translators: %s: product count. */ __( '%s published products.', 'agentic-commerce-for-woocommerce' ), number_format_i18n( $e['products'] ) ) ); Xpay_UI::check( $e['country_ok'] ? 'pass' : 'high', __( 'Store country', 'agentic-commerce-for-woocommerce' ), $e['country_ok'] ? sprintf( /* translators: %s: country code. */ __( 'Your store base is %s, which is supported.', 'agentic-commerce-for-woocommerce' ), esc_html( $e['country'] ) ) : sprintf( /* translators: %s: country code. */ __( 'ChatGPT Ads is currently available to stores based in the United States, Canada, Australia and New Zealand. Your store base is %s.', 'agentic-commerce-for-woocommerce' ), $e['country'] ? $e['country'] : __( 'not set', 'agentic-commerce-for-woocommerce' ) ) ); echo '
'; } /** * What to do instead — never leave an ineligible merchant at a dead end. * * @return void */ private static function organic_path() { Xpay_UI::section( __( 'What to do instead', 'agentic-commerce-for-woocommerce' ), __( 'Ads are one route into ChatGPT and not the main one. Appearing in answers organically is open to every store, at any size, in any country.', 'agentic-commerce-for-woocommerce' ) ); echo '
'; echo '

' . esc_html__( 'Be readable', 'agentic-commerce-for-woocommerce' ) . '

' . esc_html__( 'Publish your catalog, prices and stock in the formats AI shopping assistants actually read. This plugin does that already.', 'agentic-commerce-for-woocommerce' ) . '

'; echo '

' . esc_html__( 'Be complete', 'agentic-commerce-for-woocommerce' ) . '

' . esc_html__( 'Assistants compare on attributes. Missing descriptions, brands and identifiers are the most common reason a product is skipped.', 'agentic-commerce-for-woocommerce' ) . '

'; echo '

' . esc_html__( 'Measure it', 'agentic-commerce-for-woocommerce' ) . '

' . esc_html__( 'See which assistants read your store and which orders they drive — with no ads spend at all.', 'agentic-commerce-for-woocommerce' ) . '

'; echo '
'; echo '

' . esc_html__( 'See your AI revenue →', 'agentic-commerce-for-woocommerce' ) . '

'; } /** * Connected + eligible: the ads account surface. * * @return void */ private static function account_state() { self::conversion_tracking(); Xpay_UI::section( __( 'Your ads account', 'agentic-commerce-for-woocommerce' ) ); echo '
'; Xpay_UI::empty_state( __( 'No ads account linked yet', 'agentic-commerce-for-woocommerce' ), __( 'Link one from your xpay dashboard and your campaigns, budgets and reconciled results appear here. Your key is stored in our backend, never on this site.', 'agentic-commerce-for-woocommerce' ), Xpay_Admin::app_url( 'chatgpt-ads' ), __( 'Link an ads account', 'agentic-commerce-for-woocommerce' ) ); echo '
'; } /** * Conversion tracking: link a ChatGPT Ads pixel so purchases are reported. * * ⛔ Every credential on this card is FORWARDED to our backend and dropped. * Nothing typed here is saved to the WordPress database, logged, or echoed * back — an ads key can spend the merchant's money. * * ⛔ A refusal to create a pixel is never worded as a rejected key. "Only an * account admin can do this" and "that key is wrong" are different problems * with different fixes, and confusing them has already cost us an install. * * @return void */ private static function conversion_tracking() { $flash = Xpay_ChatGPT_Pixel::take_flash(); $c = Xpay_ChatGPT_Pixel::config(); $s = Xpay_ChatGPT_Pixel::status(); Xpay_UI::section( __( 'Conversion tracking', 'agentic-commerce-for-woocommerce' ), __( 'Report purchases from ChatGPT Ads back to your ads account, so its results count real orders. Funnel events come from shoppers\' browsers and every paid order is also sent from your server, under one id so it is counted once.', 'agentic-commerce-for-woocommerce' ), '' . esc_html__( 'Check again', 'agentic-commerce-for-woocommerce' ) . '' ); if ( $flash ) { Xpay_UI::note( $flash['tone'], esc_html( $flash['message'] ) ); } echo '
'; Xpay_UI::check( $s['state'], $s['headline'], $s['detail'] ); if ( ! empty( $c['pixel_id'] ) ) { Xpay_UI::check( 'pass', __( 'Linked pixel', 'agentic-commerce-for-woocommerce' ), (string) $c['pixel_id'] ); } if ( ! empty( $c['needs_pixel'] ) ) { Xpay_UI::check( 'med', __( 'Waiting for a pixel', 'agentic-commerce-for-woocommerce' ), __( 'Your ads account only lets an account admin create a pixel. Create one in ChatGPT Ads Manager (Events → Pixels), then set up conversion tracking again and we will pick it up.', 'agentic-commerce-for-woocommerce' ) ); } echo '
'; if ( 'ready' === $c['forwarding'] ) { self::tracking_settings(); return; } $post = esc_url( admin_url( 'admin-post.php' ) ); $choice = Xpay_ChatGPT_Pixel::pending_choice(); if ( $choice ) { echo '

' . esc_html__( 'Choose a pixel', 'agentic-commerce-for-woocommerce' ) . '

'; echo '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped above. echo ''; wp_nonce_field( 'xpay_px_connect' ); // ⛔ Nothing is preselected. A preselected "create" that the platform // then refuses is the PixelProof install we lost; the merchant picks. foreach ( $choice['pixels'] as $px ) { echo '

'; } if ( ! empty( $choice['can_create'] ) ) { echo '

'; } submit_button( __( 'Use this pixel', 'agentic-commerce-for-woocommerce' ), 'primary', 'submit', false ); echo '
'; } echo '
'; echo '

' . esc_html__( 'Set up conversion tracking', 'agentic-commerce-for-woocommerce' ) . '

'; echo '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped above. echo ''; wp_nonce_field( 'xpay_px_connect' ); if ( ! empty( $c['ads_key_linked'] ) ) { echo '

' . esc_html__( 'Your ads account is linked in your xpay dashboard. We will find or create the pixel and its Conversions API key for you.', 'agentic-commerce-for-woocommerce' ) . '

'; } else { // ⛔ One place to paste the key: the xpay dashboard. A key pasted here // reached the relay only, so the dashboard asked for it a second time. echo '

' . esc_html__( 'First link your ChatGPT Ads account on your xpay dashboard (ChatGPT Ads → Settings). Then come back and click the button below. We find or create the pixel and its Conversions API key for you.', 'agentic-commerce-for-woocommerce' ) . '

'; echo '

' . esc_html__( 'Link your ads account', 'agentic-commerce-for-woocommerce' ) . '

'; } echo '

' . esc_html__( 'Your Ads Manager API key is kept by our backend. It is never saved on this site.', 'agentic-commerce-for-woocommerce' ) . '

'; submit_button( __( 'Set up conversion tracking', 'agentic-commerce-for-woocommerce' ), 'primary', 'submit', false ); echo '
'; echo '

' . esc_html__( 'Already have a pixel?', 'agentic-commerce-for-woocommerce' ) . '

'; echo '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped above. echo ''; wp_nonce_field( 'xpay_px_manual' ); echo '

' . esc_html__( 'Enter the pixel ID and a Conversions API key from ChatGPT Ads Manager → Events.', 'agentic-commerce-for-woocommerce' ) . '

'; echo '


'; echo '

'; echo '


'; echo '

'; submit_button( __( 'Save pixel', 'agentic-commerce-for-woocommerce' ), 'secondary', 'submit', false ); echo '
'; echo '
'; self::tracking_settings(); } /** * The two switches: is the pixel on, and may it forward to OpenAI. * * @return void */ private static function tracking_settings() { $enabled = (string) get_option( Xpay_ChatGPT_Pixel::OPTION_ENABLED, 'auto' ); $forward = (string) get_option( Xpay_ChatGPT_Pixel::OPTION_FORWARD, 'auto' ); echo '
' . esc_html__( 'Tracking settings', 'agentic-commerce-for-woocommerce' ) . ''; echo '
'; echo ''; wp_nonce_field( 'xpay_px_settings' ); echo '


'; echo '


'; submit_button( __( 'Save settings', 'agentic-commerce-for-woocommerce' ), 'secondary', 'submit', false ); echo '
'; } }