'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 . '
' . esc_html( trim( $text . ' ' . $l['note'] ) ) . '
' . esc_html( trim( $text . ' ' . $l['note'] ) ) . '
' . '' . esc_html__( 'Switch WooCommerce\'s off', 'ai-eshop-optimizer' ) . ' ' . '' . esc_html__( 'Keep both', 'ai-eshop-optimizer' ) . '