'woocommerce_enable_reviews', 'wishlist' => 'woocommerce_product_wishlist_enabled', 'save_for_later' => 'woocommerce_cart_save_for_later_enabled', 'withdrawal' => 'woocommerce_feature_order_withdrawal_enabled', 'back_in_stock' => 'woocommerce_feature_customer_stock_notifications_enabled', ); const NOT_YET_REPLACED = array( 'reviews' ); public static function init() { foreach ( self::OPTIONS as $key => $option ) { add_filter( 'pre_update_option_' . $option, static function ( $value, $old ) use ( $key ) { return self::guard( $key, $value, $old ); }, 10, 2 ); } add_action( 'admin_init', array( __CLASS__, 'follow_ours' ), 20 ); add_action( 'admin_notices', array( __CLASS__, 'notices' ) ); add_action( 'admin_post_aieo_wc_overlap', array( __CLASS__, 'resolve' ) ); } public static function ours_on( $key ) { switch ( $key ) { case 'reviews': if ( ! class_exists( 'AIEO_Ratings' ) ) { return null; } $s = AIEO_Ratings::get_settings(); return ! empty( $s['enabled'] ); case 'wishlist': if ( ! class_exists( 'AIEO_Wishlist' ) ) { return null; } return AIEO_Wishlist::is_type_enabled( 'product' ); case 'save_for_later': return '0' !== (string) get_option( 'aieo_carts_save_enabled', '1' ); case 'withdrawal': if ( ! class_exists( 'AIEO_Withdrawal' ) ) { return null; } return AIEO_Withdrawal::is_enabled(); case 'back_in_stock': $s = get_option( 'aieo_dmm_waitlist', array() ); return is_array( $s ) && isset( $s['frontend_enabled'] ) && 'yes' === $s['frontend_enabled'] && ! ( isset( $s['enabled'] ) && empty( $s['enabled'] ) ); } return false; } private static function labels( $key ) { $dmm = admin_url( 'admin.php?page=ai-eshop-dmm&dmm_tab=' ); $features = admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=features' ); $all = array( 'reviews' => array( 'ours' => __( 'Rooster One star ratings', 'ai-eshop-optimizer' ), 'theirs' => __( 'WooCommerce product reviews', 'ai-eshop-optimizer' ), 'ours_url' => $dmm . 'ratings', 'theirs_url' => admin_url( 'admin.php?page=wc-settings&tab=products' ), 'note' => __( 'The ratings already given in reviews stay in your stats.', 'ai-eshop-optimizer' ), ), 'wishlist' => array( 'ours' => __( 'Rooster One favourites', 'ai-eshop-optimizer' ), 'theirs' => __( 'WooCommerce Wishlists', 'ai-eshop-optimizer' ), 'ours_url' => $dmm . 'wishlist', 'theirs_url' => $features, 'note' => '', ), 'save_for_later' => array( 'ours' => __( 'Rooster One saved carts', 'ai-eshop-optimizer' ), 'theirs' => __( 'WooCommerce Save for Later in Cart', 'ai-eshop-optimizer' ), 'ours_url' => $dmm . 'saved_abandoned_carts', 'theirs_url' => $features, 'note' => '', ), 'withdrawal' => array( 'ours' => __( 'Rooster One right of withdrawal', 'ai-eshop-optimizer' ), 'theirs' => __( 'WooCommerce Order withdrawal', 'ai-eshop-optimizer' ), 'ours_url' => $dmm . 'withdrawal', 'theirs_url' => $features, 'note' => '', ), 'back_in_stock' => array( 'ours' => __( 'Rooster One waiting list', 'ai-eshop-optimizer' ), 'theirs' => __( 'WooCommerce Back in Stock Notifications', 'ai-eshop-optimizer' ), 'ours_url' => $dmm . 'waitlist', 'theirs_url' => $features, 'note' => '', ), ); return $all[ $key ]; } private static function kept( $key ) { $kept = get_option( self::KEPT_OPTION, array() ); return is_array( $kept ) && ! empty( $kept[ $key ] ); } public static function guard( $key, $value, $old ) { if ( 'yes' !== $value || 'yes' === $old || self::kept( $key ) || in_array( $key, self::NOT_YET_REPLACED, true ) || true !== self::ours_on( $key ) ) { return $value; } self::flash( $key, 'refused' ); return false === $old ? 'no' : $old; } public static function follow_ours() { if ( wp_doing_ajax() || wp_doing_cron() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || ! current_user_can( 'manage_woocommerce' ) ) { return; } $state = get_option( self::STATE_OPTION, null ); $first = ! is_array( $state ); $state = $first ? array() : $state; $dirty = $first; foreach ( self::OPTIONS as $key => $option ) { $on = self::ours_on( $key ); if ( null === $on || in_array( $key, self::NOT_YET_REPLACED, true ) ) { continue; } $was = ! empty( $state[ $key ] ); if ( $on !== $was ) { $state[ $key ] = $on ? 1 : 0; $dirty = true; } if ( ! $on || 'yes' !== get_option( $option ) || self::kept( $key ) ) { continue; } if ( ( ! $first && ! $was ) || ( $first && 'reviews' === $key && ! self::store_has_reviews() ) ) { update_option( $option, 'no' ); self::flash( $key, 'switched' ); } } if ( $dirty ) { update_option( self::STATE_OPTION, $state, false ); } } private static function store_has_reviews() { global $wpdb; return (bool) $wpdb->get_var( "SELECT 1 FROM {$wpdb->comments} WHERE comment_type = 'review' LIMIT 1" ); } private static function flash( $key, $kind ) { $tkey = 'aieo_wc_overlap_flash_' . get_current_user_id(); $queue = get_transient( $tkey ); $queue = is_array( $queue ) ? $queue : array(); $queue[ $key . ':' . $kind ] = array( $key, $kind ); set_transient( $tkey, $queue, 10 * MINUTE_IN_SECONDS ); } public static function notices() { if ( ! current_user_can( 'manage_woocommerce' ) ) { return; } $tkey = 'aieo_wc_overlap_flash_' . get_current_user_id(); $queue = get_transient( $tkey ); if ( is_array( $queue ) && $queue ) { delete_transient( $tkey ); foreach ( $queue as $item ) { $l = self::labels( $item[0] ); if ( 'refused' === $item[1] ) { $text = sprintf( __( '%1$s stayed off: %2$s is on and does the same job. To use WooCommerce\'s instead, switch %2$s off first.', 'ai-eshop-optimizer' ), $l['theirs'], $l['ours'] ); $link = '' . esc_html__( 'Open the Rooster One setting', 'ai-eshop-optimizer' ) . ''; echo '

' . esc_html( $text ) . ' ' . $link . '

'; } else { $text = sprintf( __( '%1$s was switched off: %2$s does the same job.', 'ai-eshop-optimizer' ), $l['theirs'], $l['ours'] ); echo '

' . esc_html( trim( $text . ' ' . $l['note'] ) ) . '

'; } } } $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; $where = $screen ? (string) $screen->id : ''; if ( ! in_array( $where, array( 'woocommerce_page_wc-settings', 'dashboard', 'plugins' ), true ) ) { return; } foreach ( self::OPTIONS as $key => $option ) { if ( true !== self::ours_on( $key ) || in_array( $key, self::NOT_YET_REPLACED, true ) || 'yes' !== get_option( $option ) || self::kept( $key ) ) { continue; } $l = self::labels( $key ); $text = sprintf( __( '%1$s and %2$s are both on and do the same job. Rooster One\'s leads: switch WooCommerce\'s off?', 'ai-eshop-optimizer' ), $l['ours'], $l['theirs'] ); $off = wp_nonce_url( admin_url( 'admin-post.php?action=aieo_wc_overlap&pair=' . $key . '&do=off' ), 'aieo_wc_overlap_' . $key ); $keep = wp_nonce_url( admin_url( 'admin-post.php?action=aieo_wc_overlap&pair=' . $key . '&do=keep' ), 'aieo_wc_overlap_' . $key ); echo '

' . esc_html( trim( $text . ' ' . $l['note'] ) ) . '

' . '' . esc_html__( 'Switch WooCommerce\'s off', 'ai-eshop-optimizer' ) . ' ' . '' . esc_html__( 'Keep both', 'ai-eshop-optimizer' ) . '

'; } } public static function resolve() { $key = isset( $_GET['pair'] ) ? sanitize_key( wp_unslash( $_GET['pair'] ) ) : ''; if ( ! isset( self::OPTIONS[ $key ] ) || ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'You are not allowed to do this.', 'ai-eshop-optimizer' ), 403 ); } check_admin_referer( 'aieo_wc_overlap_' . $key ); $do = isset( $_GET['do'] ) ? sanitize_key( wp_unslash( $_GET['do'] ) ) : ''; if ( 'off' === $do ) { update_option( self::OPTIONS[ $key ], 'no' ); self::flash( $key, 'switched' ); } elseif ( 'keep' === $do ) { $kept = get_option( self::KEPT_OPTION, array() ); $kept = is_array( $kept ) ? $kept : array(); $kept[ $key ] = 1; update_option( self::KEPT_OPTION, $kept, false ); } wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url() ); exit; } }