SkyVerge WooCommerce Extensions

We got an interesting question this week from a developer: Is there a way to show Membership Plan Names in a “content restricted” notice instead of products to buy?

In this case, the site wasn’t selling Memberships, but rather taking applications for them, so the plan names made more sense.

This question can show us a couple interesting concepts today to look at: (1) creating a helper method to get plans that restrict a product, and (2) how to filter restriction messages to add your own merge tag.

This tutorial requires intermediate to advanced PHP and WordPress development skills to implement.

WooCommerce Memberships Restriction Notices: An Overview

Memberships has several times of “content restricted” notices, which are configurable in the plugin settings. However, these notices are all filterable so you can dynamically change these messages further as needed.

There are filters for each message type that can be used to add a new merge tag for membership plan names.

We’re going to go through a quick guide to replace a {plan_names} merge tag in “product restricted” messages today.

Get Plans That Restrict a Product

First, when we looked at the filters we’ve linked above, we have the post ID / product ID as a parameter with which we can alter the message, but we don’t know the membership plans that are protecting those pieces of content. We’ll need a helper function that allows us to work backwards to get the plan(s) that are restricting the content.

I’m going to use only products in this example as we said above. Since there could be multiple plans to which this product belongs, we’ll need to take this approach:

  1. Get all membership plans
    ( wc_memberships_get_membership_plans() is helpful)
  2. Loop through them and get their product restriction rules
    ($plan->get_product_restriction_rules() is helpful)
  3. Check if the current product is restricted by the plan, and save the plan name if so

This helper function will give us a list of all plans that restrict access to the product. Here’s what the finished method will look like:

/**
 * Helper function to get membership plans that restrict access to a product
 *
 * @param int $product_id the product ID being viewed
 * @return array $product_plans plans that restrict access to the product
 */
function sv_wc_memberships_get_plans_for_product( $product_id ) {

    $all_plans     = wc_memberships_get_membership_plans();
    $product_plans = array();

    foreach ( $all_plans as $plan ) {

        $restriction_rules = $plan->get_product_restriction_rules();
        $product_cats      = get_the_terms( $product_id, 'product_cat' );

        // Just in case :)
        if ( is_wp_error( $product_cats ) || ! $product_cats ) {
            $product_cats = array();
        }

        // give us just an array of IDs for the product categories, thx
        $categories = wp_list_pluck( $product_cats, 'term_id' );

        foreach ( $restriction_rules as $rule ) {

            // rule can be either a product or term restriction, let's see which type
            // then use that to compare against our current product
            switch ( $rule->get_content_type_name() ) {

                case 'product_cat':

                    // check for at least one match
                    // if we find one, break out of the rules foreach, we're done
                    if ( count( array_intersect( $rule->get_object_ids(), $categories ) ) > 0 ) {
                        $product_plans[ $plan->get_slug() ] = $plan->get_name();
                        break 2;
                    }

                break;

                case 'product':

                    // check to see if the product is restricted directly
                    // break completely out if so (this is intentionally not strict)
                    if ( in_array( $product_id, $rule->get_object_ids() ) ) {
                        $product_plans[ $plan->get_slug() ] = $plan->get_name();
                        break 2;
                    }

                break;
            }
        }
    }

    return $product_plans;
}

We’ve first gotten plans and we start to loop through them. We get the product restriction rules for each plan, then check these restriction rules to see if the current product is restricted by the plan we’re looping.

Since plans can have taxonomy or product rule types, we need to check for both (which is why you see both a category and product ID check above). Finally, once I find any rule that confirms this plan restricts the product, I break out completely and save its name into my plans array.

Now let’s use this helper function.

Notice Merge Tag Replacement

Now that we can get plans from the product / product ID, we can grab them with this helper function, and do a string replacement for our merge tag with the list of plans. Memberships has a built-in helper you can use that will turn an array of plans into a human readable list: wc_memberships_list_items( $array )

Let’s get plans, use that to create a list, then replace our {plan_names} merge tag with this list.

/**
 * Allows for replacing {plan_names} merge tag in product restriction messages
 *
 * @param string $message the restriction message
 * @param int $product_id the ID of the product currently being viewed
 * @return string the message with the merge tag replaced
 */
function edit_purchasing_restricted_message( $message, $product_id ) {

    $plans      = sv_wc_memberships_get_plans_for_product( $product_id );
    $plans_list = wc_memberships_list_items( $plans );

    return str_replace( '{plan_names}', $plans_list, $message );
}
add_filter( 'wc_memberships_product_purchasing_restricted_message', 'edit_purchasing_restricted_message', 10, 2 );
add_filter( 'wc_memberships_product_viewing_restricted_message',    'edit_purchasing_restricted_message', 10, 2 );

That part is much easier 🙂 Now you can insert {plan_names} sort of like the {products} merge tag, and this will list the plans that have access to the restricted product.

Putting it Together: WooCommerce Memberships Restriction Notice Merge Tags

I used a slight variation of the full snippet to add my own “list items for humans” function (since I’m an Oxford comma purist). The function is essentially the same, but it will Oxford-comma and bold items in the list.

You can view that full snippet here. Once it’s added to the site, you can use the {plan_names} merge tag as outlined in your product messages:

WooCommerce Memberships: Use new merge tag

Which can now output a list of plan names for access instead of products to purchase:

WooCommerce Memberships: New merge tag on frontend

You could take this further to add different merge tags, or filter other restriction message types to use this merge tag in other places!

Published by Beka Rice

Beka leads product direction for SkyVerge and technical documentation. She spends a lot of time on research and interviews, but likes to write so she has an excuse to spend more time jamming out to anything from The Clash to Lady Gaga.