WooCommerce with Paid Membership Pro – only show allowed products

With Paid Membership Pro (PMPro) plugin, you can restrict certain products for certain membership levels. But by default, when a member visits shop, they can still see those restricted products, which they were not supposed to see. We will avoid that using woocommerce_product_query action hook, by modifying the default WooCommerce query.

 * Get all page/post/custom post type ID based on pmpro membership level
function careless_get_pmpro_member_pages( $user_level ) {
    global $wpdb;
    $page_ids = array();

    $sql = "SELECT page_id FROM $wpdb->pmpro_memberships_pages WHERE membership_id = $user_level";

    $results = $wpdb->get_results( $sql, ARRAY_A );

    if ( $results ) {
        foreach ( $results as $result ) {
            $page_ids[] = $result['page_id'];

    return $page_ids;

 * Modify default WooCommerce query
function careless_maintain_membership_restriction_for_woo_products_shop_page( $query ) {
    //avoid for admin users - admin should have access to all - if you don't need this, simply remove this portion 
    if( current_user_can( 'manage_options' ) ){
        return $query;

    //get membership level of current user
    $membership_level = pmpro_getMembershipLevelForUser();

    if ( !$membership_level ) {//doesn't have any active membership level
        $page_ids = array( 1 );//set some unavailable id as product id, to show no product at all
    } else {//user is active member
        //get page (page/post/product) ids for the membership level of current user
        $page_ids = careless_get_pmpro_member_pages( $membership_level->ID );

    //modify woocommerce query - to only show products for current user membership level
    $query->set( 'post__in', $page_ids );
    $query->set( 'ignore_sticky_posts', true );//avoid sticky posts!
add_action( 'woocommerce_product_query', 'careless_maintain_membership_restriction_for_woo_products_shop_page' );

Code goes in the functions.php file of your active theme.