Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add option to display subscriptionless memberships #3058

Merged
merged 16 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 132 additions & 2 deletions includes/reader-revenue/my-account/class-woocommerce-my-account.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

}
}

Expand Down Expand Up @@ -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
laurelfulford marked this conversation as resolved.
Show resolved Hide resolved
$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' );
Expand Down Expand Up @@ -514,6 +522,128 @@ public static function show_message_after_logout() {
WooCommerce_Connection::add_wc_notice( __( 'You have successfully logged out.', 'newspack-plugin' ), 'success' );
}
}

/**
* Adds option to display memberships without subscriptions on the Subscriptions tab of My Account..
*
* @param array $settings WooCommerce Memberships settings.
* @return array
*/
public static function option_display_memberships_without_subs( $settings ) {
$settings[] = array(
laurelfulford marked this conversation as resolved.
Show resolved Hide resolved
'name' => __( 'Newspack Reader Activation', 'newspack-plugin' ),
'type' => 'title',
'id' => 'wc_memberships_show_unsubbed_memberships',
);

$settings[] = array(
'type' => 'checkbox',
'id' => 'wc_memberships_show_unsubbed_memberships',
'name' => __( 'Memberships without subscriptions', 'newspack-plugin' ),
'desc' => __( 'Display memberships that don\'t have active subscriptions on the My Account Subscriptions tab.', 'newspack-plugin' ),
'default' => 'no',
);

$settings[] = array(
'type' => 'sectionend',
);

return $settings;
}

/**
* 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 );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this is not currently throwing any errors for me, but it's something we've run into occasionally, so this is a good practice to get into the habit of:

Suggested change
$memberships_info = wc_memberships_get_user_active_memberships( $customer_id );
$memberships_info = \wc_memberships_get_user_active_memberships( $customer_id );

If you're working in a PHP file that has a namespace (as this one does), when calling any global function, it's a good idea to prefix it with \. This tells PHP to look for this function in the global namespace. If you don't include the \ prefix, then PHP will first look for the function in the current namespace and then fall back to global if it doesn't exist in the current namespace. I've seen instances where this can cause fatal errors, so adding the \ sidesteps that whole issue and also makes the code a little clearer in a namespaced file (even if it's not required to avoid errors like in this case).

The exception to this rule is internal PHP functions, so if you can find the function in the PHP manual, you don't need to specify a namespace (global or otherwise) for it. In my code editor internal PHP functions are helpfully highlighted in a different color than other functions:

Screenshot 2024-04-16 at 1 03 47 PM

You also don't need to prefix the function name when checking whether it exists (like function_exists) as this will check for the function in every namespace including the global one, unless you pass a specific namespace.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL -- nice! I didn't realize the purpose of the \, I figured it had something to do with namespaced/not namespaced, but didn't realize what it actually did under the hood.

$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 ) ) {
laurelfulford marked this conversation as resolved.
Show resolved Hide resolved
$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 ( 'no' === get_option( 'wc_memberships_show_unsubbed_memberships', 'no' ) ) {
laurelfulford marked this conversation as resolved.
Show resolved Hide resolved
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 '<div class="woocommerce-memberships-without-subs">';
echo '<h2>' . esc_html__( 'Active Memberships', 'newspack-plugin' ) . '</h2>';
echo '<p>' . 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' ) . '</p>';
wc_get_template(
'myaccount/my-memberships.php',
array(
'customer_memberships' => $memberships_without_subs,
'user_id' => get_current_user_id(),
laurelfulford marked this conversation as resolved.
Show resolved Hide resolved
)
);
echo '</div>';
}
}

/**
* 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 ( 'no' === get_option( 'wc_memberships_show_unsubbed_memberships', 'no' ) ) {
laurelfulford marked this conversation as resolved.
Show resolved Hide resolved
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 ) {
unset( $actions['cancel'] );
laurelfulford marked this conversation as resolved.
Show resolved Hide resolved
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 ) {
unset( $columns['membership-next-bill-on'] );
laurelfulford marked this conversation as resolved.
Show resolved Hide resolved
return $columns;
}
}

WooCommerce_My_Account::init();
39 changes: 39 additions & 0 deletions includes/reader-revenue/my-account/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down