S2Member query filters not working on query inside a shortcode

I’m trying to add S2Member’s query filters to a query that’s contained inside a custom shortcode. Below is the initial part of the query. The rest of the shortcode (not shown here) just displays the custom posts from the query by adding them to the $output variable and then returning $output.

The attach_s2member_query_filters(); isn’t working and all the posts are being displayed by the shortcode to all site visitors regardless of member level. I tried adding attach_s2member_query_filters() to the $query variable but that didn’t work, either. Is there a way to use attach_s2member_query_filters() in this situation? I know it’s a bit unusual.

If not, is there another way to limit a query like this to specific user levels (maybe by adding something to the $args array)? If so, I could run two separate queries, one for users above a certain level, and another for users below that level, and use the [s2If !current_user_can(access_s2member_level)] shortcode on the actual page to display different queries depending on the user’s member level. That would be fine as well.

Thanks in advance for any help or advice!

Here’s the query from the shortcode that isn’t filtering properly:

$args = array(
‘post_type’ => ‘custom_item’,
‘posts_per_page’ => 20,
‘order’ => ‘ASC’

$query = query_posts($args);
$output .= get_the_posts_pagination();
//start loop
if (have_posts($query)) : while (have_posts($query)) : the_post();

Hi Matt,

Does your code work returning posts as expected? (except for excluding the s2 protected pages)

What s2 restriction did you use on the posts/pages? WP Admin > s2Member > Restriction Options

How are you using that code? Could you give me the custom shortcode, or the hack you’re using, to try it myself?


Hi Cristian,
Thanks for the help! Is there a way I can message you with the full shortcode or mark a reply here as hidden? I don’t want to list too many details from the code publicly if possible (it includes some URLs and things from the client’s website).

The page itself will actually have no restrictions. It’s going to be a library of resources, and they want to have some “public” content as a sort of teaser that displays for everyone, but the full content of the library would only display for users above a certain membership level.

It is displaying all the custom posts and fields correctly, just not restricting them by membership level.

Thanks again for your help!

Hi again Cristián,
I’ve cleaned out the potentially sensitive details from the code, but I’m having trouble posting it here. The shortcode displays multiple URLs/anchors for each library item, and it’s saying I can only post two links in a comment. Is there some way I work get around that limitation when posting code?


Did you try putting it inside a code block? You can use three back-ticks at beginning and end of the block. https://markdown.land/markdown-code-block

If that doesn’t work, you can message me here. Click on my name, and then the message button.


Thanks! I’d forgotten about that. Here’s the code (the spacing/tabs didn’t copy over very well–sorry about that!):

function library_list() {
    // query
    $args = array(
        'post_type' => 'library_item',
        'posts_per_page' => 20,
        'order' => 'ASC'

    // attach filter ID for custom search and filter plugin
    if (is_page(99999)) {
        $args['search_filter_id'] = 88888;

    //attach s2member query filter and start loop
    $query = query_posts($args);
    $output .= get_the_posts_pagination();
    $output .= '<br>';
    $output .= '<hr>';
    $output .= '<br>';
    if (have_posts($query)) : while (have_posts($query)) : the_post();
        // set up variables - get content from custom fields
        $category = ice_category_terms('library_category');
        $region = ice_category_terms('regions');
        $classification = ice_category_terms('classifications');
        $topic = ice_category_terms('topics');
        $artistic_domain = ice_category_terms('artistic_domains');
        $description = get_field('description');
        $web_link = get_field('web_link');
        $web_link2 = get_field('web_link2');
        $file = get_field('file');
        $fileLink = $file['url'];
        $archived = get_field('archived');
        $sensitive = get_field('sensitive');
        // languages - one resource language, up to two source languages
        $resourceLanguageId = get_field('resource_language');
        $resourceLanguageTerm = get_term($resourceLanguageId, 'languages');
        $resourceLanguage = $resourceLanguageTerm->name;
        $resourceLanguageLink = "https://www.websitename.com/library/?fwp_item_language=" . $resourceLanguage;
        $sourceLanguageId = get_field('language');
        $sourceLanguageTerm = get_term($sourceLanguageId, 'languages');
        $sourceLanguage = $sourceLanguageTerm->name;
        $sourceLanguageLink = "https://www.websitename.com/library/?fwp_item_language=" . $sourceLanguage;
        $sourceLanguage2Id = get_field('secondary_source_language');
        $sourceLanguage2Term = get_term($sourceLanguage2Id, 'languages');
        $sourceLanguage2 = $sourceLanguage2Term->name;
        $sourceLanguage2Link = "https://www.websitename.com/library/?fwp_item_language=" . $sourceLanguage2;
        $item_title = get_the_title();
        $item_url = get_the_permalink();
        // display posts
        if ($item_title) {
            $output .=	"<span class='fontbold'><a href='$item_url'>$item_title</a></span><br>";
        if($description) {
            $output .= "<span style='text-decoration:underline'>Item Description</span> $description";
        if($web_link) {
            $output .= "<span class='fontbold'>Resource Link: </span><a href='$web_link' target='_blank'> $web_link</a><br>";
        if($web_link2) {
            $output .= "<span class='fontbold'>Secondary Resource Link: </span><a href='$web_link2' target='_blank'>$web_link2</a><br>";
        if($file) {
            $output .= "<span class='fontbold'>File Link:</span> <a href='$fileLink' target='_blank'>$fileLink</a><br>";
        $output .= "<span class='fontbold'>Item Category: </span>$category<br>";
        if($resourceLanguage) {
            $output .= "<span class='fontbold'>Language Described: </span><a href='$resourceLanguageLink'>$resourceLanguage</a><br>";
        if($sourceLanguage) {
            $output .= "<span class='fontbold'>Source Language(s): </span><a href='$sourceLanguageLink'>$sourceLanguage</a>";
        if($sourceLanguage2) {
            $output .= ", <a href='$sourceLanguage2Link'>$sourceLanguage2</a><br>";
        $output .= "<br>";
        if($archived == 'Yes') {
            $output .= '<span style="color: blue; font-weight: bold;">ARCHIVE ITEM: May contain out-of-date information.</span><br>';
        if($sensitive == 'Yes') {
            $output .= "<span style='color: red; font-style: italic; font-weight: bold;'>This item contains potentially sensitive content. Please do not share or reproduce any of the information or files below without permission from the author(s). Contact <a href='mailto:resources@websitename.com' style='color:#BE2200;'>resources@websitename.com</a> for more information.</span><br>";
        $output .= '<br>';
        $output .= '<hr>';
        $output .= '<br>';
        // end loop
        $output .= "nothing found.";
    // add post-loop pagination
    $output .= get_the_posts_pagination();
    // reset query, detach S2member query filters, return $output
    return $output;
add_shortcode('libraryList', 'library_list');

By the way, most of these variables are pulling custom fields we created with ACF. All of that (and the parts displaying the custom fields) could be removed for testing. Mainly just seeing if there’s a way to restrict the posts the query returns by membership level with this kind of loop.

Thanks for the code.


If you use the code in the documentation, do you still get the protected posts in the query? https://www.s2member.com/codex/stable/s2member/api_functions/package-functions/#src_doc_attach_s2member_query_filters()

What is your Alt View restriction configuration? Wp Admin > s2Member > Restriction Options > Alternative View

When you check the page to see the output, are you logged in as admin, or the test user, or logged out?


Hi Cristian,
It turns out this is being caused by the Search/Filter plugin we’re using (Search and Filter Pro: https://searchandfilter.com/). Somehow adding its Filter ID to the query interferes with the S2Member Query Filters function. If I remove that section that adds the search_filter_id, S2Member’s query filters work fine (but, of course, we lose the ability for users to filter library items by category, etc.). I could maybe see if a different custom search/filter plugin would work with S2Member, maybe FacetWP or something.

Thanks again for your help!

1 Like

Thanks for the update!

I see… Maybe that one’s filter overrides s2’s then.

I hope you find how to make it work together with s2, or another one that does.