get_module( 'web-push' ) : null; } public function render_subtab() { global $wpdb; $tbl_ci = $wpdb->prefix . 'aieo_customer_intelligence'; $push = $this->push_module(); if ( ! $push || ! method_exists( $push, 'cohort_rollup' ) ) { list( $open, $close ) = AIEO_DMM_UI::card( array( 'anchor' => 'web-push-lookalike-audience-export-meta-google', 'icon' => 'users-round', 'title' => __( 'Lookalike audience export', 'ai-eshop-optimizer' ), ) ); echo $open; echo \Rooster\Admin\Ui::notice( esc_html__( 'The export is unavailable in this build.', 'ai-eshop-optimizer' ), 'warning', array( 'inline' => true ) ); echo $close; return; } $this->render_export_cards( $tbl_ci, $push->cohort_rollup( $tbl_ci ), __( 'Export a group of customers as a hashed list and upload it to Meta or Google as the seed for a lookalike audience. The platforms then find new prospects who resemble that group. Emails are SHA-256 hashed before they leave this server, which is the format both platforms expect — no raw address is ever exported.', 'ai-eshop-optimizer' ), __( 'Tip: the strongest seed is usually your best customers rather than the largest group. VIP, Loyalist and Brand-Devoted are the ones to try first.', 'ai-eshop-optimizer' ) ); } private function part( $title, $description = '' ) { if ( function_exists( 'rooster_admin_card_section_html' ) && class_exists( 'AIEO_Chrome' ) && AIEO_Chrome::on() ) { echo rooster_admin_card_section_html( (string) $title, '' !== (string) $description ? array( 'description' => (string) $description ) : array() ); return; } echo '

' . esc_html( (string) $title ) . '

'; if ( '' !== (string) $description ) { echo '

' . esc_html( (string) $description ) . '

'; } } private function render_export_cards( $tbl_ci, $rollup, $intro, $tip ) { if ( ! is_array( $rollup ) ) { $rollup = array(); } if ( ! class_exists( 'AIEO_Audience_Rules' ) && defined( 'AIEO_DIR' ) ) { $f = AIEO_DIR . 'includes/class-aieo-audience-rules.php'; if ( is_readable( $f ) ) { require_once $f; } } $cohort_order = class_exists( 'AIEO_Audience_Rules' ) ? array_map( static function ( $c ) { return 'active' === $c ? '' : $c; }, AIEO_Audience_Rules::DORMANCY_COHORTS ) : array( '', 'drifting', 'lapsed', 'long_dormant', 'lost' ); $base = admin_url( 'admin-post.php?action=aieo_dmm_webpush_export_lookalike' ); $nonce = wp_create_nonce( 'aieo_dmm_webpush_export_lookalike' ); if ( function_exists( 'rooster_admin_band_open' ) ) { rooster_admin_band_open( array( 'cols' => 2 ) ); } list( $open, $close ) = AIEO_DMM_UI::card( array( 'anchor' => 'web-push-lookalike-audience-export-meta-google', 'icon' => 'users-round', 'title' => __( 'Lookalike audience export', 'ai-eshop-optimizer' ), 'description' => $intro, 'footnote' => $tip, 'col' => 1, ) ); echo $open; echo \Rooster\Admin\Guidance::text( __( 'Both Meta and Google accept SHA-256-hashed customer email lists as the seed for lookalike audiences — they find new prospects who match the profile of your Rooster One segment. Download the hashed CSV, upload via the platform UI, build the lookalike there. Native OAuth API integration is on the Phase 7 roadmap; the manual upload flow is fast (<5 min) and works for any cohort.', 'ai-eshop-optimizer' ) ); $this->part( __( 'Hashed CSV — drop into the platform UI', 'ai-eshop-optimizer' ), __( 'Each export contains: sha256_email, sha256_phone (when available). UTF-8, no BOM (Meta/Google prefer raw). Capped at 50,000 rows per file. A customer with no email address cannot be hashed, so the addressable count is shown as its own column next to the full cohort size — the "In cohort" figures are the same ones the Cohorts table further up reports, and the export file contains the "Addressable" count of rows.', 'ai-eshop-optimizer' ) ); $rows = array(); foreach ( $cohort_order as $cohort ) { if ( ! isset( $rollup[ $cohort ] ) ) { continue; } $total = isset( $rollup[ $cohort ]['cnt'] ) ? (int) $rollup[ $cohort ]['cnt'] : 0; $emailable = isset( $rollup[ $cohort ]['has_email'] ) ? (int) $rollup[ $cohort ]['has_email'] : 0; if ( 0 === $emailable ) { continue; } $rows[] = array( 'cohort' => '' === $cohort ? 'active' : $cohort, 'label' => '' === $cohort ? __( 'Active customers', 'ai-eshop-optimizer' ) : ucwords( str_replace( '_', ' ', $cohort ) ), 'slug' => $cohort, 'total' => $total, 'emailable' => $emailable, 'pct' => $total > 0 ? (int) round( 100 * $emailable / $total ) : 0, 'url' => add_query_arg( array( 'cohort' => '' === $cohort ? 'active' : $cohort, '_wpnonce' => $nonce, ), $base ), ); } if ( empty( $rows ) ) { echo \Rooster\Admin\States::state( 'first-use', array( 'title' => __( 'Nothing to show yet.', 'ai-eshop-optimizer' ), 'text' => __( 'Customer groups appear here once Customer Intelligence has built them and some of their customers have an email address.', 'ai-eshop-optimizer' ) ) ); } else { AIEO_Table::render( array( 'page_id' => 'lookalike_export', 'row_key' => 'cohort', 'rows' => $rows, 'columns' => array( array( 'key' => 'label', 'label' => __( 'Cohort', 'ai-eshop-optimizer' ), 'subline' => 'slug' ), array( 'key' => 'total', 'label' => __( 'In cohort', 'ai-eshop-optimizer' ), 'type' => 'integer', 'width' => '150px' ), array( 'key' => 'emailable', 'label' => __( 'Addressable (has email)', 'ai-eshop-optimizer' ), 'type' => 'integer', 'width' => '190px', 'suffix' => static function ( $r ) { return $r['pct'] > 0 ? '(' . number_format_i18n( $r['pct'] ) . '%)' : ''; }, ), ), 'actions' => array( array( 'id' => 'export', 'label' => '⬇ ' . __( 'Hashed CSV', 'ai-eshop-optimizer' ), 'href' => static function ( $r ) { return $r['url']; }, 'variant' => 'secondary', ), ), ) ); } $this->part( __( 'Upload UIs', 'ai-eshop-optimizer' ) ); echo '

'; echo '' . esc_html__( 'Open Meta Audience Manager →', 'ai-eshop-optimizer' ) . ' '; echo '' . esc_html__( 'Open Google Ads Audience Manager →', 'ai-eshop-optimizer' ) . ''; echo '

'; echo $close; list( $open, $close ) = AIEO_DMM_UI::card( array( 'anchor' => 'lookalike-export-start-here-pick-the-seed', 'icon' => 'list-checks', 'title' => __( 'Start here: pick the seed', 'ai-eshop-optimizer' ), 'description' => __( 'Export the cohort that represents your ideal customer, not the largest one. VIP, Loyalist and active Brand-Devoted make the strongest seeds; "Lost" makes a poor one. A few thousand rows is plenty — quality of the seed decides the quality of the audience.', 'ai-eshop-optimizer' ), 'col' => 2, ) ); echo $open; $this->part( __( 'Meta (Facebook / Instagram)', 'ai-eshop-optimizer' ) ); echo '
    '; echo '
  1. ' . esc_html__( 'In Ads Manager open Audiences, then Create audience → Custom audience → Customer list.', 'ai-eshop-optimizer' ) . '
  2. '; echo '
  3. ' . esc_html__( 'Upload the CSV and say the data is ALREADY HASHED — this file is SHA-256 hashed here, so letting Meta hash it again would match nobody. Map the column to Email.', 'ai-eshop-optimizer' ) . '
  4. '; echo '
  5. ' . esc_html__( 'Wait for it to populate, usually well under an hour. A list needs roughly 100 matched people before it can be used at all, and more like 1,000–5,000 before a lookalike is any good.', 'ai-eshop-optimizer' ) . '
  6. '; echo '
  7. ' . esc_html__( 'With that list selected, choose Create lookalike. Pick the country you sell to and a size of 1–10%: 1% is closest to your seed and usually the one to start with.', 'ai-eshop-optimizer' ) . '
  8. '; echo '
  9. ' . esc_html__( 'Run your prospecting campaign against the lookalike, and add the original customer list as an EXCLUSION — otherwise you pay to advertise to people who already buy from you.', 'ai-eshop-optimizer' ) . '
  10. '; echo '
'; $this->part( __( 'Google Ads', 'ai-eshop-optimizer' ) ); echo '
    '; echo '
  1. ' . esc_html__( 'Open Tools → Shared library → Audience manager, then add a new segment of type Customer list.', 'ai-eshop-optimizer' ) . '
  2. '; echo '
  3. ' . esc_html__( 'Upload the CSV and tick that the data is hashed. Google expects SHA-256 of the lowercased, trimmed email, which is exactly what this export produces.', 'ai-eshop-optimizer' ) . '
  4. '; echo '
  5. ' . esc_html__( 'Matching can take up to 48 hours. Google will not let you target a list until it has matched roughly 1,000 members, so a small cohort may never become targetable.', 'ai-eshop-optimizer' ) . '
  6. '; echo '
  7. ' . esc_html__( 'Do NOT look for Similar Audiences — Google retired them in 2023. Instead attach the customer list as an audience SIGNAL on a Performance Max or Search campaign and let optimised targeting find comparable people, or use it as an exclusion.', 'ai-eshop-optimizer' ) . '
  8. '; echo '
  9. ' . esc_html__( 'Customer Match also requires a compliant account with some spend history; a brand-new account may not have it enabled yet.', 'ai-eshop-optimizer' ) . '
  10. '; echo '
'; $this->part( __( 'Keep it fresh', 'ai-eshop-optimizer' ) ); echo \Rooster\Admin\Guidance::text( __( 'Re-export and re-upload monthly. Both platforms decay a list over time, and your best-customer cohort changes as people buy — a seed from six months ago is describing a shop you no longer run.', 'ai-eshop-optimizer' ) ); echo $close; if ( function_exists( 'rooster_admin_band_close' ) ) { rooster_admin_band_close(); } } }