post_type !== self::POST_TYPE) { return; } if (!defined('AIEO_FILE')) { return; } wp_enqueue_media(); wp_enqueue_script( 'aieo-competitions-admin', plugins_url('assets/js/aieo-competitions-admin.js', AIEO_FILE), array('jquery'), defined('AIEO_VERSION') ? AIEO_VERSION : '1.0', true ); wp_localize_script('aieo-competitions-admin', 'aieoCompetitions', array( 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('aieo_competitions'), 'i18n' => array( 'select' => __('Select image', 'ai-eshop-optimizer'), 'use' => __('Use this image', 'ai-eshop-optimizer'), 'copied' => __('Copied!', 'ai-eshop-optimizer'), 'saving' => __('Drawing…', 'ai-eshop-optimizer'), 'removeWinner' => __('Remove winner', 'ai-eshop-optimizer'), ), )); self::enqueue_picker_bundle(); } private static function enqueue_picker_bundle() { if (!defined('AIEO_URI') || !defined('AIEO_DIR')) { return; } foreach (array('select2', 'selectWoo') as $h) { if (wp_script_is($h, 'registered')) { wp_enqueue_script($h); break; } } foreach (array('select2', 'selectWoo') as $h) { if (wp_style_is($h, 'registered')) { wp_enqueue_style($h); break; } } wp_enqueue_script('jquery-ui-sortable'); $dmm_js = AIEO_DIR . 'assets/js/dmm.js'; wp_enqueue_script('aieo-dmm', AIEO_URI . 'assets/js/dmm.js', array('jquery', 'jquery-ui-sortable'), file_exists($dmm_js) ? (string) filemtime($dmm_js) : (defined('AIEO_VERSION') ? AIEO_VERSION : '1.0'), true); $dmm_css = AIEO_DIR . 'assets/css/dmm.css'; if (file_exists($dmm_css)) { wp_enqueue_style('aieo-dmm', AIEO_URI . 'assets/css/dmm.css', array(), (string) filemtime($dmm_css)); } if (class_exists('AIEO_DMM_Product_Picker')) { AIEO_DMM_Product_Picker::enqueue_assets(); } wp_localize_script('aieo-dmm', 'aieoDmm', array( 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('aieo_dmm_nonce'), 'activeTab' => '', 'i18n' => array( 'pickBrands' => __('Pick brand(s)…', 'ai-eshop-optimizer'), 'pickCategories' => __('Pick categories…', 'ai-eshop-optimizer'), 'pickNeeds' => __('Pick needs…', 'ai-eshop-optimizer'), 'searchByNameSku' => __('Search by name or SKU…', 'ai-eshop-optimizer'), 'picker' => array( 'deleted' => __('deleted', 'ai-eshop-optimizer'), 'draft' => __('draft', 'ai-eshop-optimizer'), 'variations' => __('variations', 'ai-eshop-optimizer'), 'searching' => __('Searching…', 'ai-eshop-optimizer'), 'none' => __('No products found.', 'ai-eshop-optimizer'), 'failed' => __('Search failed.', 'ai-eshop-optimizer'), 'loadingV' => __('Loading variations…', 'ai-eshop-optimizer'), 'noV' => __('No variations.', 'ai-eshop-optimizer'), 'failV' => __('Failed to load variations.', 'ai-eshop-optimizer'), 'cancel' => __('Cancel', 'ai-eshop-optimizer'), 'done' => __('Done', 'ai-eshop-optimizer'), 'ph' => __('Search products by name or SKU…', 'ai-eshop-optimizer'), 'selOne' => __('item selected', 'ai-eshop-optimizer'), 'selMany' => __('items selected', 'ai-eshop-optimizer'), 'titleInc' => __('Choose products to INCLUDE', 'ai-eshop-optimizer'), 'titleExc' => __('Choose products to EXCLUDE', 'ai-eshop-optimizer'), 'remove' => __('Remove', 'ai-eshop-optimizer'), ), ), )); } private static function term_select($name, $css_class, $selected_ids, $describedby = '') { $out = ''; return $out; } public static function register_cpt() { register_post_type(self::POST_TYPE, array( 'labels' => array( 'name' => __('Competitions', 'ai-eshop-optimizer'), 'singular_name' => __('Competition', 'ai-eshop-optimizer'), 'add_new_item' => __('Add Competition', 'ai-eshop-optimizer'), 'edit_item' => __('Edit Competition', 'ai-eshop-optimizer'), 'menu_name' => __('Competitions', 'ai-eshop-optimizer'), ), 'public' => true, 'show_in_rest' => true, 'has_archive' => true, 'menu_icon' => 'dashicons-awards', 'show_in_menu' => false, 'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields', 'page-attributes'), 'rewrite' => array('slug' => 'competitions', 'with_front' => false), )); register_post_meta(self::POST_TYPE, self::META_GF, array( 'type' => 'integer', 'single' => true, 'show_in_rest' => true, 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); register_post_meta(self::POST_TYPE, self::META_TERMS, array( 'type' => 'integer', 'single' => true, 'show_in_rest' => true, 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); register_post_meta(self::POST_TYPE, self::META_SHORTDESC, array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); foreach (array(self::META_IMG_DESK, self::META_IMG_MOB) as $key) { register_post_meta(self::POST_TYPE, $key, array( 'type' => 'integer', 'single' => true, 'show_in_rest' => true, 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); } foreach (array(self::META_START, self::META_END, self::META_ANNOUNCE_AT) as $key) { register_post_meta(self::POST_TYPE, $key, array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); } register_post_meta(self::POST_TYPE, self::META_WINNERS_ANNOUNCE, array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => static function ($v) { return wp_kses_post((string) $v); }, 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); foreach (array(self::META_BRANDS, self::META_CATEGORIES, self::META_PRODUCTS) as $key) { register_post_meta(self::POST_TYPE, $key, array( 'type' => 'array', 'single' => true, 'show_in_rest' => array('schema' => array('type' => 'array', 'items' => array('type' => 'integer'))), 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); } register_post_meta(self::POST_TYPE, self::META_WINNERS_COUNT, array( 'type' => 'integer', 'single' => true, 'show_in_rest' => true, 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); register_post_meta(self::POST_TYPE, self::META_PRIZE_VALUE, array( 'type' => 'number', 'single' => true, 'show_in_rest' => true, 'auth_callback' => static function () { return current_user_can('edit_posts'); }, )); if (!get_option('aieo_competition_cpt_flushed')) { update_option('aieo_competition_cpt_flushed', 1, false); flush_rewrite_rules(false); } } public static function add_metabox() { add_meta_box( 'aieo-competition-details', __('Competition details', 'ai-eshop-optimizer'), array(__CLASS__, 'render_metabox'), self::POST_TYPE, 'normal', 'high' ); add_meta_box( 'aieo-competition-announcement', __('Winners announcement', 'ai-eshop-optimizer'), array(__CLASS__, 'render_announcement_metabox'), self::POST_TYPE, 'normal', 'high' ); add_meta_box( 'aieo-competition-winners', __('Competition winners', 'ai-eshop-optimizer'), array(__CLASS__, 'render_winners_metabox'), self::POST_TYPE, 'side', 'default' ); add_meta_box( 'aieo-competition-insights', __('Competition insights', 'ai-eshop-optimizer'), array(__CLASS__, 'render_insights_metabox'), self::POST_TYPE, 'side', 'low' ); } public static function render_insights_metabox($post) { if (!class_exists('AIEO_Competition_Analytics')) { echo '
' . esc_html__('Analytics unavailable.', 'ai-eshop-optimizer') . '
'; return; } $i = AIEO_Competition_Analytics::insights($post->ID); $m = $i['metrics']; $cur = function_exists('get_woocommerce_currency_symbol') ? get_woocommerce_currency_symbol() : ''; $entries = (int) $m['entries']; $conv = $entries > 0 ? round(100 * (int) $i['converting_entrants'] / $entries, 1) : 0; echo '' . esc_html__('Participants are unavailable.', 'ai-eshop-optimizer') . '
'; return; } $target = max(1, (int) get_post_meta($post->ID, self::META_WINNERS_COUNT, true)); $m = AIEO_Competition_Participants::metrics($post->ID); $eligible = method_exists('AIEO_Competition_Participants', 'eligible_count') ? AIEO_Competition_Participants::eligible_count($post->ID) : (int) $m['confirmed']; $winners = AIEO_Competition_Participants::get_winners($post->ID); echo '' . esc_html(sprintf( __('%1$d eligible of %2$d confirmed. Winners exclude anyone who has already won and are weighted by how many competitions each person entered (more entries → more chances).', 'ai-eshop-optimizer'), (int) $eligible, (int) $m['confirmed'] )) . '
'; echo ''; echo '
' . esc_html__('Drawing again replaces the current winners. Set the number of winners in “Competition details”. Write the public message in the “Winners announcement” box.', 'ai-eshop-optimizer') . '
'; echo '' . esc_html__('Shown on the public competition page once it has ENDED, below the winners list. Congratulate the winners, add photos, prize details, claim/redemption instructions, etc. Draw the winners in the “Competition winners” box (right) first.', 'ai-eshop-optimizer') . '
'; wp_editor($announce_html, 'aieocompwinnersannouncement', array( 'textarea_name' => 'aieo_comp_winners_announcement', 'textarea_rows' => 8, 'media_buttons' => true, 'teeny' => false, 'tinymce' => true, 'quicktags' => true, )); } public static function render_metabox($post) { wp_nonce_field('aieo_comp_meta', 'aieo_comp_meta_nonce'); $gf_id = (int) get_post_meta($post->ID, self::META_GF, true); $desc = (string) get_post_meta($post->ID, self::META_SHORTDESC, true); $img_d = (int) get_post_meta($post->ID, self::META_IMG_DESK, true); $img_m = (int) get_post_meta($post->ID, self::META_IMG_MOB, true); $start = (string) get_post_meta($post->ID, self::META_START, true); $end = (string) get_post_meta($post->ID, self::META_END, true); $announce = (string) get_post_meta($post->ID, self::META_ANNOUNCE_AT, true); if (class_exists('AIEO_Competition_Entry_Form')) { echo '' . esc_html(AIEO_Competition_Entry_Form::in_use_note($post->ID)) . '
';
echo self::gf_form_select('aieo_comp_gf', $gf_id, 'aieo-comp-gf-help');
echo '
' . esc_html__('The Gravity Forms form entrants submit. With none, the competition’s built-in entry form takes the entries.', 'ai-eshop-optimizer') . '
';
echo self::terms_page_select('aieo_comp_terms', (int) get_post_meta($post->ID, self::META_TERMS, true), 'aieo-comp-terms-help');
echo '
' . esc_html__('The page with the competition’s terms. When one is chosen, the terms box of the built-in entry form links to it.', 'ai-eshop-optimizer') . '
';
echo '
'; echo ''; echo ''; echo ''; echo '
'; echo '' . esc_html__('Optional. Before the start, visitors see a “coming soon” notice; after the end, an “ended” message. Shop managers always see the live form (preview). Leave start/end empty for an always-open competition. “Winners announced” drives the “winners will be announced on …” message and the Events timeline.', 'ai-eshop-optimizer') . '
'; $brands = (array) get_post_meta($post->ID, self::META_BRANDS, true); $cats = (array) get_post_meta($post->ID, self::META_CATEGORIES, true); $prods = array_map('intval', (array) get_post_meta($post->ID, self::META_PRODUCTS, true)); $winners = (int) get_post_meta($post->ID, self::META_WINNERS_COUNT, true); $prize = (string) get_post_meta($post->ID, self::META_PRIZE_VALUE, true); $cur = function_exists('get_woocommerce_currency_symbol') ? get_woocommerce_currency_symbol() : ''; echo '' . esc_html__('Associated brands / categories / products', 'ai-eshop-optimizer') . '
' . esc_html__('Optional. Used to monitor which products this competition drives (its “pull”). The same pickers as the discount pages.', 'ai-eshop-optimizer') . '
';
echo self::term_select('aieo_comp_brands', 'aieo-dmm-brand-select', $brands, 'aieo-comp-assoc-help');
echo '
';
echo self::term_select('aieo_comp_categories', 'aieo-dmm-category-select', $cats, 'aieo-comp-assoc-help');
echo '
'; echo ''; echo ''; echo '
'; echo '' . esc_html__('e.g. 3 winners, prize value 50 each → total prize pool 150. Use the prize value when the prize is a bag of products rather than one SKU.', 'ai-eshop-optimizer') . '
'; echo '' . esc_html__('Tip: the public winners announcement (rich text) is in its own “Winners announcement” box, just below this one.', 'ai-eshop-optimizer') . '
'; if ($post->ID && get_post_status($post) === 'publish') { $links = self::share_links($post->ID); echo '' . esc_html__('Share links', 'ai-eshop-optimizer') . '
' . esc_html(ucfirst($net)) . ':