account = $account; if ( ! WC_Payments_Features::should_use_stripe_billing() ) { return; } // This action is triggered on product save but after other required subscriptions logic is triggered. add_action( 'woocommerce_admin_process_product_object', [ $this, 'product_save' ] ); add_action( 'woocommerce_payments_account_refreshed', [ $this, 'account_data_refreshed' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_modal_scripts_and_styles' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_toast_script' ] ); add_filter( 'woocommerce_subscriptions_admin_pointer_script_parameters', [ $this, 'filter_admin_pointer_script_parameters' ] ); } /** * Sets the account service instance reference on the class. * * @param WC_Payments_Account $account account service instance. */ public function set_account( WC_Payments_Account $account ) { $this->account = $account; } /** * Convert subscriptions to drafts when using WCPay (without subscriptions) and onboarding is not complete. * This should be triggered just prior to a $product->save() call so no need to call product->save() * * @param WC_Product $product Subscriptions Product. */ public function product_save( WC_Product $product ) { if ( $this->account->is_stripe_connected() ) { return; } // If Subscriptions plugin is installed we don't need to do this check. if ( $this->is_subscriptions_plugin_active() ) { return; } // Skip products which have already been scheduled or aren't subscriptions. if ( ! WC_Subscriptions_Product::is_subscription( $product ) ) { return; } // We can skip if the post is not yet marked as published. if ( 'publish' !== $product->get_status() ) { return; } // Change the default WP saved post URL to correctly reflect the draft status and to add our saved-as-draft flag. add_filter( 'redirect_post_location', function () use ( $product ) { return add_query_arg( // nosemgrep: audit.php.wp.security.xss.query-arg -- server generated url is passed in. [ 'message' => 10, // Post saved as draft message. 'wcpay-subscription-saved-as-draft' => 1, ], get_edit_post_link( $product->get_id(), 'url' ) ); } ); $this->convert_subscription_to_draft( $product ); } /** * Convert a product to a draft and save the id in an array, so we can auto-publish once onboarding is complete. * * @param WC_Product $product Product to convert to draft. */ private function convert_subscription_to_draft( WC_Product $product ) { // Force into draft status. $product->set_status( 'draft' ); $product->save(); $auto_publish_ids = get_option( self::WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS, [] ); $auto_publish_ids[] = $product->get_id(); // Save and prevent duplicates from multiple updates. update_option( self::WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS, array_unique( $auto_publish_ids ) ); Tracker::track_admin( 'wcpay_subscriptions_account_not_connected_save_product' ); } /** * Method to handle when account data is refreshed and onboarding may have been completed */ public function account_data_refreshed() { if ( ! $this->account->is_stripe_connected() ) { return; } $products = get_option( self::WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS, [] ); if ( [] === $products ) { return; } foreach ( $products as $product_id ) { $product = wc_get_product( $product_id ); if ( ! $product || ! WC_Subscriptions_Product::is_subscription( $product ) ) { continue; } if ( 'draft' !== $product->get_status() ) { continue; } $product->set_status( 'publish' ); $product->save(); } // clear auto-published products from option. delete_option( self::WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS ); } /** * Enqueues the admin scripts needed on the add/edit product screen when the * merchant attempts to publish a subscription product prior to completing * WCPay onboarding. * * @param string $hook_suffix The current admin page. */ public function enqueue_modal_scripts_and_styles( $hook_suffix ) { global $post; if ( ! in_array( $hook_suffix, [ 'post.php', 'post-new.php' ], true ) ) { return; } if ( ! $post || 'product' !== $post->post_type ) { return; } if ( empty( $_GET['wcpay-subscription-saved-as-draft'] ) || 1 !== (int) $_GET['wcpay-subscription-saved-as-draft'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return; } if ( $this->is_subscriptions_plugin_active() ) { return; } if ( $this->account->is_stripe_connected() ) { return; } WC_Payments::register_script_with_dependencies( 'wcpay-subscription-product-onboarding-modal', 'dist/subscription-product-onboarding-modal' ); wp_localize_script( 'wcpay-subscription-product-onboarding-modal', 'wcpaySubscriptionProductOnboardingModal', [ 'connectUrl' => WC_Payments_Account::get_connect_url( 'WC_SUBSCRIPTIONS_PUBLISH_PRODUCT_' . $post->ID ), 'pluginScope' => ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '6.5', '>=' ) ) ? 'woocommerce-admin' : 'woocommerce', ] ); WC_Payments_Utils::register_style( 'wcpay-subscription-product-onboarding-modal', plugins_url( 'dist/subscription-product-onboarding-modal.css', WCPAY_PLUGIN_FILE ), [], WC_Payments::get_file_version( 'dist/subscription-product-onboarding-modal.css' ), 'all' ); wp_enqueue_script( 'wcpay-subscription-product-onboarding-modal' ); wp_enqueue_style( 'wcpay-subscription-product-onboarding-modal' ); } /** * Enqueues the admin scripts needed on the add/edit product screen when the * merchant has completed WCPay onboarding and is redirected back to product * edit page. * * @param string $hook_suffix The current admin page. */ public function enqueue_toast_script( $hook_suffix ) { global $post; if ( ! in_array( $hook_suffix, [ 'post.php', 'post-new.php' ], true ) ) { return; } if ( ! $post || 'product' !== $post->post_type ) { return; } if ( empty( $_GET['wcpay-subscriptions-onboarded'] ) || 1 !== (int) $_GET['wcpay-subscriptions-onboarded'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return; } if ( $this->is_subscriptions_plugin_active() ) { return; } WC_Payments::register_script_with_dependencies( 'wcpay-subscription-product-onboarding-toast', 'dist/subscription-product-onboarding-toast' ); wp_localize_script( 'wcpay-subscription-product-onboarding-toast', 'wcpaySubscriptionProductOnboardingToast', [ 'pluginScope' => ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '6.5', '>=' ) ) ? 'woocommerce-admin' : 'woocommerce', ] ); wp_enqueue_script( 'wcpay-subscription-product-onboarding-toast' ); } /** * Modifies the pointer content found on the "Add new product" page * when WooCommerce Subscriptions is not active. * * @param array $pointer_params Array of strings used on the "Add new product" page. * @return array Potentially modified array of strings used on the "Add new product" page. */ public function filter_admin_pointer_script_parameters( $pointer_params ) { if ( $this->is_subscriptions_plugin_active() ) { return $pointer_params; } // translators: %1$s:

tag, %2$s:

tag, %3$s:

tag, %4$s: WooPayments, %5$s: tag, %6$s: tag, %7$s: tag, %8$s: tag, %9$s:

tag. $pointer_params['typePointerContent'] = sprintf( _x( '%1$sChoose Subscription%2$s%3$s%4$s adds two new subscription product types - %5$sSimple subscription%6$s and %7$sVariable subscription%8$s.%9$s', 'used in admin pointer script params in javascript as type pointer content', 'woocommerce-payments' ), '

', '

', '

', 'WooPayments', '', '', '', '', '

' ); return $pointer_params; } }