Code WooCommerce WordPress

How to Restrict Page Access Based on Purchased Products in WooCommerce

If you’re running a WooCommerce store, you may want to restrict access to certain pages based on the products a user has purchased. For example, you might offer exclusive content or services to customers who have bought specific products. This tutorial will guide you through the process of restricting access to pages based on a user’s purchase history using WooCommerce and some custom code.

Step-by-Step Guide

1. Overview of the Code

The code below does two main things:

  • Checks if a user is logged in and has bought the required product. If not, they are redirected to the login page or the product page.
  • Adds a link to the user’s WooCommerce account dashboard showing which pages they can access based on their purchases.

2. Restricting Page Access Based on Product Purchases

First, we need to restrict access to specific pages depending on whether the user has purchased a product. If they haven’t, they will be redirected to either the login page (if not logged in) or the product page (if they haven’t bought the product).


/**
 * Check if user is logged in and bought the product. If not, redirect to login page.
 */
function sajdoko_to_login_if_not_customer() {
    global $post;

    // Get the current user ID and user object
    $user_id = get_current_user_id();
    $current_user = wp_get_current_user();
    $customer_email = $current_user->user_email;

    // Mapping of restricted pages to their corresponding product IDs
    $relation_page_product = [1439 => 1211, 1431 => 1210, 1441 => 1214, 1440 => 1212]; //page => product

    // Check if the current page is one of the restricted pages
    if (isset($relation_page_product[$post->ID])) {
        // If user is logged in, check if they have bought the product
        if (is_user_logged_in()) {
            // If user has not bought the product, redirect to the product page
            if (!wc_customer_bought_product_paid($customer_email, $user_id, $relation_page_product[$post->ID])) {
                wp_redirect(esc_url(get_permalink($relation_page_product[$post->ID])));
                exit;
            }
        } else {
            // If user is not logged in, redirect to the login page
            wp_redirect(esc_url(wp_login_url()), 307);
            exit;
        }
    }
}
add_action('wp', 'sajdoko_to_login_if_not_customer');

This function works as follows:

  1. It checks whether the user is logged in.
  2. If logged in, it verifies if the user has purchased the required product for the page they are trying to access.
  3. If they haven’t bought the product, they are redirected to the product page.
  4. If not logged in, the user is redirected to the login page.

3. Showing Accessible Pages on the User’s Dashboard

Next, we’ll show users links to pages they can access based on the products they’ve bought. This is done by adding a list of accessible pages to the user’s WooCommerce dashboard.


function sajdoko_show_link_page_to_dashboard() {
    // Get the current user ID and user object
    $user_id = get_current_user_id();
    $current_user = wp_get_current_user();
    $customer_email = $current_user->user_email;

    // Mapping of product IDs to their corresponding page IDs
    $relation_product_page = [1211 => 1439, 1210 => 1431, 1214 => 1441, 1212 => 1440]; //product => page

    // Get the list of products bought by the user
    $bought_products = sajdoko_get_bought_products();

    // If the user has bought products, display them
    if (!empty($bought_products)) {
        echo '<h3>' . sprintf(__('Paketat aktive: %s', 'woocommerce'), count($bought_products)) . '</h3>';
        echo '<ul>';
        foreach ($bought_products as $product_id) {
            // Check if the user has bought and paid for the product
            if (wc_customer_bought_product_paid($customer_email, $user_id, $product_id)) {
                $page_id = $relation_product_page[$product_id] ?? null;
                if ($page_id) {
                    $link = esc_url(get_permalink($page_id));
                    echo "<li><a href="$link">" . get_the_title($page_id) . "</a></li>";
                }
            }
        }
        echo '</ul>';
    }
}
add_action('woocommerce_account_dashboard', 'sajdoko_show_link_page_to_dashboard', 10);

This function:

  • Retrieves the list of products the user has bought.
  • Maps each product to a corresponding page.
  • Displays links to these pages on the user’s WooCommerce dashboard.

4. Helper Functions

The two helper functions below handle checking if the user has purchased and paid for a product and retrieving the list of purchased products.

Checking If a Product Is Bought and Paid


/**
 * Check if the product is bought and paid.
 */
function wc_customer_bought_product_paid($customer_email, $user_id, $product_id) {
    global $wpdb;

    // Apply filters to check if the product is bought
    $result = apply_filters('woocommerce_pre_customer_bought_product', null, $customer_email, $user_id, $product_id);

    if (null !== $result) {
        return $result;
    }

    // Generate a transient name for caching
    $transient_name = 'wc_cbp_' . md5($customer_email . $user_id . WC_Cache_Helper::get_transient_version('orders'));

    // Check if the result is cached
    if (false === ($result = get_transient($transient_name))) {
        $customer_data = array_filter(array_unique([$user_id, $customer_email]));

        // Sanitize and filter customer data
        $customer_data = array_map('esc_sql', $customer_data);
        $statuses = array_map('esc_sql', wc_get_is_paid_statuses());

        // If no customer data is available, return false
        if (empty($customer_data)) {
            return false;
        }

        // Query the database to check if the product is bought and paid
        $result = $wpdb->get_col("
            SELECT im.meta_value FROM {$wpdb->posts} AS p
            INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
            INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id
            INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id
            WHERE p.post_status IN ('wc-" . implode("','wc-", $statuses) . "')
            AND pm.meta_key IN ('_billing_email', '_customer_user')
            AND im.meta_key IN ('_product_id', '_variation_id')
            AND im.meta_value != 0
            AND pm.meta_value IN ('" . implode("','", $customer_data) . "')
        ");
        $result = array_map('absint', $result);

        // Cache the result
        set_transient($transient_name, $result, DAY_IN_SECONDS * 30);
    }
    return in_array(absint($product_id), $result);
}
  

Getting the List of Bought Products


function sajdoko_get_bought_products() {
    // Get the current user object
    $current_user = wp_get_current_user();

    // Check if the user is valid
    if (0 == $current_user->ID) {
        return [];
    }

    // Create arguments array for querying orders
    $args = [
        'numberposts' => -1,
        'meta_key' => '_customer_user',
        'meta_value' => $current_user->ID,
        'post_type' => wc_get_order_types(),
        'post_status' => array_keys(wc_get_is_paid_statuses()),
    ];

    // Get the list of customer orders
    $customer_orders = get_posts($args);

    // If no orders are found, return
    if (!$customer_orders) {
        return [];
    }

    // Loop through the orders and collect product IDs
    $product_ids = [];
    foreach ($customer_orders as $customer_order) {
        $order = wc_get_order($customer_order->ID);
        foreach ($order->get_items() as $item) {
            $product_ids[] = $item->get_product_id();
        }
    }

    return $product_ids;
}
  

How to Implement This Code on Your Existing Website

To implement this functionality on your WooCommerce site, follow the steps below:

1. Add the Code to Your Theme’s Functions.php File

The easiest way to add this custom code is by placing it inside your theme’s functions.php file. Here’s how:

  1. Log into your WordPress dashboard.
  2. Navigate to Appearance > Theme File Editor.
  3. In the file list on the right, find and click on functions.php under your active theme.
  4. Paste the provided code at the end of the file.
  5. Click Update File to save your changes.

Note: Make sure to back up your site before making any modifications to your theme files.

2. Use a Custom Plugin

If you prefer to keep your theme files untouched, creating a small custom plugin for this functionality is a more modular solution. Here’s how you can do it:

  1. In your WordPress dashboard, go to Plugins > Add New and click on Create a Plugin (or use a plugin like Code Snippets).
  2. Create a new plugin file by navigating to wp-content/plugins/ on your server using an FTP client or file manager.
  3. Create a folder for your custom plugin (e.g., sajdoko-restrict-access) and add a .php file within it.
  4. Paste the code into this file, starting with a plugin header like:
    
        /*
        Plugin Name: Sajdoko Restrict Access by Product Purchase
        Description: Restricts access to pages based on WooCommerce product purchases.
        Version: 1.0
        Author: Your Name
        */
        
  5. Once you’ve saved the file, navigate back to the WordPress dashboard and activate your new plugin under the Plugins section.

3. Test the Functionality

After implementing the code, test it by logging into your website with a user account that has and hasn’t purchased the required products. Try accessing restricted pages and verify that users are properly redirected based on their purchase status. Also, check the user’s WooCommerce account dashboard to ensure the correct links appear for purchased products.

Make sure to clear your site’s cache if you’re using a caching plugin to see the changes immediately.

Chat on WhatsApp Chat on WhatsApp