From aa493c95e609853c8380830c72faf39c69713759 Mon Sep 17 00:00:00 2001 From: Laurel Date: Mon, 22 Apr 2024 12:02:15 -0700 Subject: [PATCH 1/2] fix: add option to display subscriptionless memberships (#3058) --- .../views/reader-activation/index.js | 12 ++ .../wc-memberships/class-memberships.php | 21 ++++ .../class-woocommerce-my-account.php | 110 +++++++++++++++++- includes/reader-revenue/my-account/style.scss | 39 +++++++ includes/wizards/class-engagement-wizard.php | 14 ++- 5 files changed, 190 insertions(+), 6 deletions(-) diff --git a/assets/wizards/engagement/views/reader-activation/index.js b/assets/wizards/engagement/views/reader-activation/index.js index 8c78199340..1507278dbe 100644 --- a/assets/wizards/engagement/views/reader-activation/index.js +++ b/assets/wizards/engagement/views/reader-activation/index.js @@ -263,6 +263,17 @@ export default withWizardScreen( ( { wizardApiFetch } ) => { toggleChecked={ membershipsConfig.require_all_plans } /> ) } + + setMembershipsConfig( { ...membershipsConfig, show_on_subscription_tab: value } ) + } + toggleChecked={ membershipsConfig.show_on_subscription_tab } + />
) : null } @@ -384,6 +395,7 @@ export default withWizardScreen( ( { wizardApiFetch } ) => { mailchimp_reader_default_status: config.mailchimp_reader_default_status, active_campaign_master_list: config.active_campaign_master_list, memberships_require_all_plans: membershipsConfig.require_all_plans, + memberships_show_on_subscription_tab: membershipsConfig.show_on_subscription_tab, use_custom_lists: config.use_custom_lists, newsletter_lists: config.newsletter_lists, sync_esp: config.sync_esp, diff --git a/includes/plugins/wc-memberships/class-memberships.php b/includes/plugins/wc-memberships/class-memberships.php index 378494aa36..dacab6f8eb 100644 --- a/includes/plugins/wc-memberships/class-memberships.php +++ b/includes/plugins/wc-memberships/class-memberships.php @@ -378,6 +378,27 @@ public static function set_require_all_plans_setting( $require = false ) { return \update_option( 'newspack_memberships_require_all_plans', $require ); } + /** + * Get the current setting of the "Display memberships on the subscriptions tab" option. + * + * @return boolean + */ + public static function get_show_on_subscription_tab_setting() { + return \get_option( 'newspack_memberships_show_on_subscription_tab', false ); + } + + /** + * Set the "Display memberships on the subscriptions tab" option. + * + * @param boolean $show False to show memberships without subscriptions on the subscriptions tab (default) + * or true to display those memberships on the subscriptions tab.. + * + * @return boolean + */ + public static function set_show_on_subscription_tab_setting( $show = false ) { + return \update_option( 'newspack_memberships_show_on_subscription_tab', $show ); + } + /** * Whether the current user is a member of the given plan. * diff --git a/includes/reader-revenue/my-account/class-woocommerce-my-account.php b/includes/reader-revenue/my-account/class-woocommerce-my-account.php index c7fa21de92..48ec85cbd1 100644 --- a/includes/reader-revenue/my-account/class-woocommerce-my-account.php +++ b/includes/reader-revenue/my-account/class-woocommerce-my-account.php @@ -46,6 +46,12 @@ public static function init() { \add_action( 'template_redirect', [ __CLASS__, 'verify_saved_account_details' ] ); \add_action( 'logout_redirect', [ __CLASS__, 'add_param_after_logout' ] ); \add_action( 'template_redirect', [ __CLASS__, 'show_message_after_logout' ] ); + \add_action( 'woocommerce_account_subscriptions_endpoint', [ __CLASS__, 'append_membership_table' ], 11 ); + \add_filter( 'wc_memberships_general_settings', [ __CLASS__, 'option_display_memberships_without_subs' ] ); + \add_filter( 'wcs_my_account_redirect_to_single_subscription', [ __CLASS__, 'redirect_to_single_subscription' ] ); + \add_filter( 'wc_memberships_members_area_my-memberships_actions', [ __CLASS__, 'hide_cancel_button_from_memberships_table' ] ); + \add_filter( 'wc_memberships_my_memberships_column_names', [ __CLASS__, 'remove_next_bill_on' ], 21 ); + } } @@ -333,11 +339,13 @@ public static function is_user_verified() { * Redirect to "Account details" if accessing "My Account" directly. * Do not redirect if the request is a resubscribe request, as resubscribe * requests do their own redirect to the cart/checkout page. + * Do not redirect if this request is a membership cancellation. */ public static function redirect_to_account_details() { - $resubscribe_request = isset( $_REQUEST['resubscribe'] ) ? 'shop_subscription' === get_post_type( absint( $_REQUEST['resubscribe'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $resubscribe_request = isset( $_REQUEST['resubscribe'] ) ? 'shop_subscription' === \get_post_type( absint( $_REQUEST['resubscribe'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $cancel_membership_request = isset( $_REQUEST['cancel_membership'] ) ? true : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended - if ( \is_user_logged_in() && Reader_Activation::is_enabled() && function_exists( 'wc_get_page_permalink' ) && ! $resubscribe_request ) { + if ( \is_user_logged_in() && Reader_Activation::is_enabled() && function_exists( 'wc_get_page_permalink' ) && ! $resubscribe_request && ! $cancel_membership_request ) { global $wp; $current_url = \home_url( $wp->request ); $my_account_page_permalink = \wc_get_page_permalink( 'myaccount' ); @@ -514,6 +522,104 @@ public static function show_message_after_logout() { WooCommerce_Connection::add_wc_notice( __( 'You have successfully logged out.', 'newspack-plugin' ), 'success' ); } } + + /** + * Check if a reader has memberships that aren't associated with subscriptions. + * + * @return array + */ + public static function get_memberships_without_subs() { + if ( function_exists( 'wc_memberships_get_user_active_memberships' ) ) { + $customer_id = \get_current_user_id(); + $memberships_info = \wc_memberships_get_user_active_memberships( $customer_id ); + $memberships_without_subs = []; + + // Create an array of active memberships without active subscriptions. + if ( function_exists( 'wc_memberships_has_subscription_product_granted_access' ) ) { + foreach ( $memberships_info as $membership ) { + if ( ! \wc_memberships_has_subscription_product_granted_access( $membership ) ) { + $memberships_without_subs[] = $membership; + } + } + } + + return $memberships_without_subs; + } + } + + /** + * Optionally append a table of active memberships without subscriptions on the My Account Subscriptions tab. + */ + public static function append_membership_table() { + // If this option is not enabled, stop. + if ( ! Memberships::get_show_on_subscription_tab_setting() ) { + return; + } + + $memberships_without_subs = self::get_memberships_without_subs(); + + // If there are active memberships without subscriptions, present them in a table. + if ( $memberships_without_subs ) { + echo '
'; + echo '

' . esc_html__( 'Active Memberships', 'newspack-plugin' ) . '

'; + echo '

' . esc_html__( 'These memberships are active, but don\'t have an associated subscription. They will need to be manually renewed when they expire.', 'newspack-plugin' ) . '

'; + wc_get_template( + 'myaccount/my-memberships.php', + array( + 'customer_memberships' => $memberships_without_subs, + 'user_id' => \get_current_user_id(), + ) + ); + echo '
'; + } + } + + /** + * Returns whether or not to redirect the Subscriptions link to a single subscription, or to the main Subscriptions screen. + * + * @return bool + */ + public static function redirect_to_single_subscription() { + // If this option is not enabled, stop. + if ( ! Memberships::get_show_on_subscription_tab_setting() ) { + return true; + } + + $memberships_without_subs = self::get_memberships_without_subs(); + + // If there are memberships without subs, we want to remove the redirect and go to Subscriptions; otherwise, return true. + if ( $memberships_without_subs ) { + return false; + } else { + return true; + } + } + + /** + * Hides 'Cancel' button on main Memberships table to tidy it up. + * + * @param array $actions WooCommerce Memberships available actions. + * @return array + */ + public static function hide_cancel_button_from_memberships_table( $actions ) { + if ( ! empty( $actions['cancel'] ) ) { + unset( $actions['cancel'] ); + } + return $actions; + } + + /** + * Removes the 'Next Bill On' column in the main Memberships table to tidy it up. + * + * @param array $columns WooCommerce Memberships table columns. + * @return array + */ + public static function remove_next_bill_on( $columns ) { + if ( ! empty( $columns['membership-next-bill-on'] ) ) { + unset( $columns['membership-next-bill-on'] ); + } + return $columns; + } } WooCommerce_My_Account::init(); diff --git a/includes/reader-revenue/my-account/style.scss b/includes/reader-revenue/my-account/style.scss index d614e9a747..ee14e6165e 100644 --- a/includes/reader-revenue/my-account/style.scss +++ b/includes/reader-revenue/my-account/style.scss @@ -84,6 +84,45 @@ vertical-align: middle; } } + + /* WooCommerce Membership styles */ + .woocommerce-memberships-without-subs { + h2 { + font-size: 1em; + margin-top: 0; + } + + p { + font-size: 0.8rem; + } + + .my_account_memberships { + table-layout: unset; + + td { + width: 20%; + + &:first-child { + width: 25%; + } + + &:last-child { + width: 15%; + } + } + } + } + + .woocommerce_account_subscriptions:has( ~ .woocommerce-memberships-without-subs ) { + margin-bottom: 2rem; + + // Hide the 'You have no active subscriptions' message if memberships table is present. + &:has( > .no_subscriptions ) { + display: none; + } + } + + } /* stylelint-disable-next-line */ diff --git a/includes/wizards/class-engagement-wizard.php b/includes/wizards/class-engagement-wizard.php index f810a255f4..1a99b7206a 100644 --- a/includes/wizards/class-engagement-wizard.php +++ b/includes/wizards/class-engagement-wizard.php @@ -204,10 +204,11 @@ public function register_api_endpoints() { */ private static function get_memberships_settings() { return [ - 'edit_gate_url' => Memberships::get_edit_gate_url(), - 'gate_status' => get_post_status( Memberships::get_gate_post_id() ), - 'plans' => Memberships::get_plans(), - 'require_all_plans' => Memberships::get_require_all_plans_setting(), + 'edit_gate_url' => Memberships::get_edit_gate_url(), + 'gate_status' => \get_post_status( Memberships::get_gate_post_id() ), + 'plans' => Memberships::get_plans(), + 'require_all_plans' => Memberships::get_require_all_plans_setting(), + 'show_on_subscription_tab' => Memberships::get_show_on_subscription_tab_setting(), ]; } @@ -244,6 +245,11 @@ public function api_update_reader_activation_settings( $request ) { Memberships::set_require_all_plans_setting( (bool) $args['memberships_require_all_plans'] ); } + // Update Memberships options. + if ( isset( $args['memberships_show_on_subscription_tab'] ) ) { + Memberships::set_show_on_subscription_tab_setting( (bool) $args['memberships_show_on_subscription_tab'] ); + } + return rest_ensure_response( [ 'config' => Reader_Activation::get_settings(), From 310b4ee487dd78c5933270541172edaa15db341e Mon Sep 17 00:00:00 2001 From: matticbot Date: Mon, 22 Apr 2024 19:06:04 +0000 Subject: [PATCH 2/2] chore(release): 3.6.13 [skip ci] ## [3.6.13](https://github.com/Automattic/newspack-plugin/compare/v3.6.12...v3.6.13) (2024-04-22) ### Bug Fixes * add option to display subscriptionless memberships ([#3058](https://github.com/Automattic/newspack-plugin/issues/3058)) ([aa493c9](https://github.com/Automattic/newspack-plugin/commit/aa493c95e609853c8380830c72faf39c69713759)) --- CHANGELOG.md | 7 +++++++ newspack.php | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57f2e71f21..eb8d070820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [3.6.13](https://github.com/Automattic/newspack-plugin/compare/v3.6.12...v3.6.13) (2024-04-22) + + +### Bug Fixes + +* add option to display subscriptionless memberships ([#3058](https://github.com/Automattic/newspack-plugin/issues/3058)) ([aa493c9](https://github.com/Automattic/newspack-plugin/commit/aa493c95e609853c8380830c72faf39c69713759)) + ## [3.6.12](https://github.com/Automattic/newspack-plugin/compare/v3.6.11...v3.6.12) (2024-04-22) diff --git a/newspack.php b/newspack.php index 8c3a0a0f08..f97e4d0630 100644 --- a/newspack.php +++ b/newspack.php @@ -2,7 +2,7 @@ /** * Plugin Name: Newspack * Description: An advanced open-source publishing and revenue-generating platform for news organizations. - * Version: 3.6.12 + * Version: 3.6.13 * Author: Automattic * Author URI: https://newspack.com/ * License: GPL2 @@ -14,7 +14,7 @@ defined( 'ABSPATH' ) || exit; -define( 'NEWSPACK_PLUGIN_VERSION', '3.6.12' ); +define( 'NEWSPACK_PLUGIN_VERSION', '3.6.13' ); // Load language files. load_plugin_textdomain( 'newspack-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); diff --git a/package-lock.json b/package-lock.json index f8521bfe2b..4635052c12 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "newspack", - "version": "3.6.12", + "version": "3.6.13", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "newspack", - "version": "3.6.12", + "version": "3.6.13", "hasInstallScript": true, "dependencies": { "@babel/plugin-transform-runtime": "^7.24.3", diff --git a/package.json b/package.json index d925c67c56..7e4a918230 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "newspack", - "version": "3.6.12", + "version": "3.6.13", "description": "The Newspack plugin. https://newspack.com", "bugs": { "url": "https://github.com/Automattic/newspack-plugin/issues"