get_settings(); add_filter( 'wp_privacy_personal_data_exporters', array( $this, 'register_exporter' ) ); add_filter( 'wp_privacy_personal_data_erasers', array( $this, 'register_eraser' ) ); if ( 'yes' !== $s['enabled'] ) { return; } if ( did_action( 'woocommerce_init' ) && function_exists( 'woocommerce_register_additional_checkout_field' ) ) { $this->register_fields( $s ); } elseif ( ! did_action( 'woocommerce_init' ) ) { add_action( 'woocommerce_init', function () use ( $s ) { $this->register_fields( $s ); }, 20 ); } else { add_action( 'woocommerce_blocks_loaded', function () use ( $s ) { $this->register_fields( $s ); } ); } add_filter( 'woocommerce_get_default_value_for_' . self::FIELD_DAY, array( $this, 'default_day' ), 10, 3 ); add_filter( 'woocommerce_get_default_value_for_' . self::FIELD_MONTH, array( $this, 'default_month' ), 10, 3 ); add_filter( 'woocommerce_get_default_value_for_' . self::FIELD_YEAR, array( $this, 'default_year' ), 10, 3 ); add_action( 'wp_footer', array( $this, 'checkout_message_script' ) ); add_action( 'woocommerce_store_api_checkout_update_order_meta', array( $this, 'sync_to_user_meta' ) ); add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'sync_to_user_meta' ) ); add_action( 'woocommerce_edit_account_form', array( $this, 'render_account_field' ) ); add_action( 'woocommerce_save_account_details_errors', array( $this, 'save_account_field' ), 10, 2 ); add_action( 'template_redirect', array( $this, 'suppress_aw_birthdays_account_field' ), 1 ); } const DOB_META_KEYS = array( 'aieo_birthday_md', 'aieo_birthday_full', '_automatewoo_birthday_md', '_automatewoo_birthday_full' ); public function register_exporter( $exporters ) { $exporters['aieo-birthday'] = array( 'exporter_friendly_name' => __( 'Rooster One — Birthday', 'ai-eshop-optimizer' ), 'callback' => array( $this, 'export_birthday' ), ); return $exporters; } public function register_eraser( $erasers ) { $erasers['aieo-birthday'] = array( 'eraser_friendly_name' => __( 'Rooster One — Birthday', 'ai-eshop-optimizer' ), 'callback' => array( $this, 'erase_birthday' ), ); return $erasers; } public function export_birthday( $email, $page = 1 ) { $data = array(); $user = get_user_by( 'email', $email ); if ( $user ) { $md = (string) get_user_meta( $user->ID, 'aieo_birthday_md', true ); if ( '' === $md ) { $md = (string) get_user_meta( $user->ID, '_automatewoo_birthday_md', true ); } $full = (string) get_user_meta( $user->ID, 'aieo_birthday_full', true ); if ( '' === $full ) { $full = (string) get_user_meta( $user->ID, '_automatewoo_birthday_full', true ); } $items = array(); if ( '' !== $md ) { $items[] = array( 'name' => __( 'Birthday (month-day, MM-DD)', 'ai-eshop-optimizer' ), 'value' => $md ); } if ( '' !== $full ) { $items[] = array( 'name' => __( 'Date of birth', 'ai-eshop-optimizer' ), 'value' => $full ); } if ( $items ) { $data[] = array( 'group_id' => 'aieo-birthday', 'group_label' => __( 'Birthday', 'ai-eshop-optimizer' ), 'item_id' => 'aieo-birthday-' . (int) $user->ID, 'data' => $items, ); } } return array( 'data' => $data, 'done' => true ); } public function erase_birthday( $email, $page = 1 ) { $removed = false; $user = get_user_by( 'email', $email ); if ( $user ) { foreach ( self::DOB_META_KEYS as $k ) { if ( '' !== (string) get_user_meta( $user->ID, $k, true ) ) { delete_user_meta( $user->ID, $k ); $removed = true; } } } return array( 'items_removed' => $removed, 'items_retained' => false, 'messages' => $removed ? array( __( 'Birthday removed. The customer may set a new birthday from My Account.', 'ai-eshop-optimizer' ) ) : array(), 'done' => true, ); } private function register_fields( $s ) { $label = (string) $s['label']; try { woocommerce_register_additional_checkout_field( array( 'id' => self::FIELD_DAY, 'label' => __( 'Day', 'ai-eshop-optimizer' ), 'location' => 'order', 'type' => 'select', 'required' => false, 'options' => self::day_options(), 'attributes' => array( 'data-aieo-bday' => 'day' ), ) ); woocommerce_register_additional_checkout_field( array( 'id' => self::FIELD_MONTH, 'label' => __( 'Month', 'ai-eshop-optimizer' ), 'location' => 'order', 'type' => 'select', 'required' => false, 'options' => self::month_options(), 'attributes' => array( 'data-aieo-bday' => 'month' ), ) ); woocommerce_register_additional_checkout_field( array( 'id' => self::FIELD_YEAR, 'label' => __( 'Year', 'ai-eshop-optimizer' ), 'location' => 'order', 'type' => 'select', 'required' => false, 'options' => self::year_options(), 'attributes' => array( 'data-aieo-bday' => 'year' ), ) ); } catch ( \Throwable $e ) { unset( $e ); } } private static function day_options() { $o = array(); for ( $d = 1; $d <= 31; $d++ ) { $o[] = array( 'value' => (string) $d, 'label' => (string) $d ); } return $o; } private static function month_options() { $loc = ( isset( $GLOBALS['wp_locale'] ) && is_object( $GLOBALS['wp_locale'] ) ) ? $GLOBALS['wp_locale'] : null; $o = array(); for ( $m = 1; $m <= 12; $m++ ) { $o[] = array( 'value' => (string) $m, 'label' => $loc ? (string) $loc->get_month( $m ) : (string) $m ); } return $o; } private static function year_options() { $o = array(); $year = (int) gmdate( 'Y' ); for ( $y = $year; $y >= $year - 100; $y-- ) { $o[] = array( 'value' => (string) $y, 'label' => (string) $y ); } return $o; } public function default_day( $value = '' ) { return $this->prefill_part( 'day', $value ); } public function default_month( $value = '' ) { return $this->prefill_part( 'month', $value ); } public function default_year( $value = '' ) { return $this->prefill_part( 'year', $value ); } private function prefill_part( $part, $value = '' ) { $uid = get_current_user_id(); if ( $uid <= 0 ) { return $value; } $full = (string) get_user_meta( $uid, 'aieo_birthday_full', true ); if ( '' === $full ) { $full = (string) get_user_meta( $uid, '_automatewoo_birthday_full', true ); } $md = (string) get_user_meta( $uid, 'aieo_birthday_md', true ); if ( '' === $md ) { $md = (string) get_user_meta( $uid, '_automatewoo_birthday_md', true ); } $y = 0; $m = 0; $d = 0; if ( '' !== $full && preg_match( '#^(\d{4})-(\d{2})-(\d{2})$#', $full, $mm ) ) { $y = (int) $mm[1]; $m = (int) $mm[2]; $d = (int) $mm[3]; } elseif ( '' !== $md && preg_match( '#^(\d{2})-(\d{2})$#', $md, $mm ) ) { $m = (int) $mm[1]; $d = (int) $mm[2]; } if ( 'day' === $part ) { return $d > 0 ? (string) $d : $value; } if ( 'month' === $part ) { return $m > 0 ? (string) $m : $value; } return $y > 0 ? (string) $y : $value; } public function checkout_message_script() { if ( ! function_exists( 'is_checkout' ) || ! is_checkout() ) { return; } $s = $this->get_settings(); if ( 'yes' !== $s['enabled'] ) { return; } $msg = isset( $s['message'] ) ? trim( (string) $s['message'] ) : ''; if ( '' === $msg ) { return; } $msg = wp_kses( $msg, array( 'strong' => array(), 'em' => array(), 'br' => array() ) ); $bg = function_exists( 'sanitize_hex_color' ) ? sanitize_hex_color( (string) ( $s['message_bg'] ?? '' ) ) : ''; $txt = function_exists( 'sanitize_hex_color' ) ? sanitize_hex_color( (string) ( $s['message_text'] ?? '' ) ) : ''; if ( ! $bg ) { $bg = '#fff6e5'; } if ( ! $txt ) { $txt = '#5b4400'; } ?> get_meta( self::META_DAY ); $month = (int) $order->get_meta( self::META_MONTH ); $year = (int) $order->get_meta( self::META_YEAR ); if ( $day > 0 || $month > 0 ) { $md = self::mk_md( $month, $day ); $full = ( '' !== $md && $year > 0 && checkdate( $month, $day, $year ) ) ? sprintf( '%04d-%s', $year, $md ) : ''; $raw = ( '' !== $md ) ? ( $year > 0 ? sprintf( '%02d/%02d/%04d', $day, $month, $year ) : sprintf( '%02d/%02d', $day, $month ) ) : ''; } else { $raw = trim( (string) $order->get_meta( self::META_KEY ) ); $md = self::parse_md( $raw ); $full = self::parse_full( $raw ); } if ( '' === $md ) { return; } $order->update_meta_data( '_aieo_birthday_raw', $raw ); $order->update_meta_data( '_aieo_birthday_md', $md ); $order->save(); $user_id = (int) $order->get_customer_id(); if ( $user_id > 0 && '' !== $md ) { $existing = (string) get_user_meta( $user_id, 'aieo_birthday_md', true ); if ( '' === $existing ) { $existing = (string) get_user_meta( $user_id, '_automatewoo_birthday_md', true ); } if ( '' !== $existing ) { return; } update_user_meta( $user_id, 'aieo_birthday_md', $md ); update_user_meta( $user_id, '_automatewoo_birthday_md', $md ); if ( '' !== $full ) { update_user_meta( $user_id, 'aieo_birthday_full', $full ); update_user_meta( $user_id, '_automatewoo_birthday_full', $full ); } else { $existing = (string) get_user_meta( $user_id, 'aieo_birthday_full', true ); if ( '' !== $existing && substr( $existing, 5 ) !== $md ) { delete_user_meta( $user_id, 'aieo_birthday_full' ); delete_user_meta( $user_id, '_automatewoo_birthday_full' ); } } } } public function render_account_field() { $user_id = get_current_user_id(); if ( $user_id <= 0 ) { return; } $md = (string) get_user_meta( $user_id, 'aieo_birthday_md', true ); if ( '' === $md ) { $md = (string) get_user_meta( $user_id, '_automatewoo_birthday_md', true ); } $full = (string) get_user_meta( $user_id, 'aieo_birthday_full', true ); if ( '' === $full ) { $full = (string) get_user_meta( $user_id, '_automatewoo_birthday_full', true ); } $locked = ( '' !== $md ); $sel_d = 0; $sel_m = 0; $sel_y = 0; if ( '' !== $full && preg_match( '#^(\d{4})-(\d{2})-(\d{2})$#', $full, $mm ) ) { $sel_y = (int) $mm[1]; $sel_m = (int) $mm[2]; $sel_d = (int) $mm[3]; } elseif ( '' !== $md && preg_match( '#^(\d{2})-(\d{2})$#', $md, $mm ) ) { $sel_m = (int) $mm[1]; $sel_d = (int) $mm[2]; } $s = $this->get_settings(); $label = ( '' !== trim( (string) $s['label'] ) ) ? (string) $s['label'] : __( 'Birthday', 'ai-eshop-optimizer' ); $dis = $locked ? ' disabled' : ''; $loc = ( isset( $GLOBALS['wp_locale'] ) && is_object( $GLOBALS['wp_locale'] ) ) ? $GLOBALS['wp_locale'] : null; echo '
'; echo '' . esc_html( $label ) . ''; $msg = isset( $s['message'] ) ? trim( (string) $s['message'] ) : ''; if ( '' !== $msg ) { $bg = function_exists( 'sanitize_hex_color' ) ? sanitize_hex_color( (string) ( $s['message_bg'] ?? '' ) ) : ''; $txt = function_exists( 'sanitize_hex_color' ) ? sanitize_hex_color( (string) ( $s['message_text'] ?? '' ) ) : ''; if ( ! $bg ) { $bg = '#fff6e5'; } if ( ! $txt ) { $txt = '#5b4400'; } echo '

' . wp_kses( $msg, array( 'strong' => array(), 'em' => array(), 'br' => array() ) ) . '

'; } echo ''; echo ''; echo ''; echo ''; echo ''; $note = $locked ? __( 'Your birthday can’t be changed once set.', 'ai-eshop-optimizer' ) : __( 'Add your birthday to receive a discount coupon and personalised offers on your birthday. It can’t be changed once saved.', 'ai-eshop-optimizer' ); echo '' . esc_html( $note ) . ''; echo '
'; } public function save_account_field( $errors, $user ) { if ( ! is_a( $user, 'WP_User' ) || (int) $user->ID <= 0 ) { return; } if ( ( is_a( $errors, 'WP_Error' ) && $errors->get_error_messages() ) || 0 !== wc_notice_count( 'error' ) ) { return; } $user_id = (int) $user->ID; $existing = (string) get_user_meta( $user_id, 'aieo_birthday_md', true ); if ( '' === $existing ) { $existing = (string) get_user_meta( $user_id, '_automatewoo_birthday_md', true ); } if ( '' !== $existing ) { return; } $day = isset( $_POST['aieo_birthday_day'] ) ? absint( wp_unslash( $_POST['aieo_birthday_day'] ) ) : 0; $month = isset( $_POST['aieo_birthday_month'] ) ? absint( wp_unslash( $_POST['aieo_birthday_month'] ) ) : 0; $year = isset( $_POST['aieo_birthday_year'] ) ? absint( wp_unslash( $_POST['aieo_birthday_year'] ) ) : 0; if ( 0 === $day && 0 === $month && 0 === $year ) { return; } $md = self::mk_md( $month, $day ); if ( '' === $md ) { if ( is_a( $errors, 'WP_Error' ) ) { $errors->add( 'aieo_birthday_invalid', __( 'Please choose a valid birthday (day and month).', 'ai-eshop-optimizer' ) ); } return; } update_user_meta( $user_id, 'aieo_birthday_md', $md ); update_user_meta( $user_id, '_automatewoo_birthday_md', $md ); if ( $year > 0 ) { list( $mo, $da ) = explode( '-', $md ); if ( checkdate( (int) $mo, (int) $da, $year ) ) { $full = sprintf( '%04d-%s', $year, $md ); update_user_meta( $user_id, 'aieo_birthday_full', $full ); update_user_meta( $user_id, '_automatewoo_birthday_full', $full ); } } } public function suppress_aw_birthdays_account_field() { if ( ! class_exists( 'AutomateWoo\\Birthdays\\Frontend' ) ) { return; } remove_action( 'woocommerce_edit_account_form', array( 'AutomateWoo\\Birthdays\\Frontend', 'add_birthday_field_to_edit_account_form' ) ); remove_action( 'woocommerce_save_account_details_errors', array( 'AutomateWoo\\Birthdays\\Frontend', 'save_account_details_form' ) ); } public static function parse_md( $raw ) { $raw = trim( (string) $raw ); if ( preg_match( '#^(\d{4})[/.\-](\d{1,2})[/.\-](\d{1,2})$#', $raw, $m ) ) { return self::mk_md( (int) $m[2], (int) $m[3] ); } if ( preg_match( '#^(\d{1,2})[/.\-](\d{1,2})[/.\-]\d{2,4}$#', $raw, $m ) ) { return self::resolve_dm( (int) $m[1], (int) $m[2] ); } if ( preg_match( '#^(\d{1,2})[/.\-](\d{1,2})$#', $raw, $m ) ) { return self::resolve_dm( (int) $m[1], (int) $m[2] ); } return ''; } public static function parse_full( $raw ) { $raw = trim( (string) $raw ); if ( preg_match( '#^(\d{4})[/.\-](\d{1,2})[/.\-](\d{1,2})$#', $raw, $m ) ) { return checkdate( (int) $m[2], (int) $m[3], (int) $m[1] ) ? sprintf( '%04d-%02d-%02d', $m[1], $m[2], $m[3] ) : ''; } if ( preg_match( '#^(\d{1,2})[/.\-](\d{1,2})[/.\-](\d{4})$#', $raw, $m ) ) { $md = self::resolve_dm( (int) $m[1], (int) $m[2] ); if ( '' !== $md ) { list( $mo, $da ) = explode( '-', $md ); if ( checkdate( (int) $mo, (int) $da, (int) $m[3] ) ) { return sprintf( '%04d-%s', $m[3], $md ); } } } return ''; } private static function resolve_dm( $a, $b ) { if ( $a > 12 && $b <= 12 ) { return self::mk_md( $b, $a ); } if ( $b > 12 && $a <= 12 ) { return self::mk_md( $a, $b ); } return self::mk_md( $b, $a ); } private static function mk_md( $month, $day ) { $month = (int) $month; $day = (int) $day; if ( ! checkdate( $month, $day, 2024 ) ) { return ''; } return sprintf( '%02d-%02d', $month, $day ); } private function get_settings() { $stored = get_option( self::OPTION_KEY, array() ); if ( ! is_array( $stored ) ) { $stored = array(); } return self::fill_i18n_defaults( array_merge( array( 'enabled' => 'no', 'label' => '', 'message' => '', 'message_bg' => '#fff6e5', 'message_text' => '#5b4400', ), $stored ) ); } private static function fill_i18n_defaults( array $s ) { if ( ! did_action( 'init' ) ) { return $s; } $i18n = array( 'label' => __( 'Birthday (DD/MM)', 'ai-eshop-optimizer' ), 'message' => __( 'Fill in your birthday to receive your birthday gift from our store! 🎁', 'ai-eshop-optimizer' ), ); foreach ( $i18n as $k => $v ) { if ( ! isset( $s[ $k ] ) || '' === trim( (string) $s[ $k ] ) ) { $s[ $k ] = $v; } } return $s; } } }