0

I have created a rather complex WP_Query, I need to restrict the arguments that are used within the query dependant on the users inputs.

I appreciate I can wrap the whole argument in an IF statement, however if I try add an IF statement within the arguments, it breaks the website claiming there is a critical error in the code.

As I am using multiple variables I wish to check for before adding these into the arguments list, I would hope I could use the following code:

$paged              = $_POST['page'];
$display_count      = $_POST['display_count'];
$direction          = $_POST['direction'];
$search_term        = $_POST['search_term'];
$search_tags        = $_POST['search_tags'];
$search_categories  = $_POST['search_categories'];
$search_relation    = $_POST['search_relation'];

if ($direction      == 'prev') :
    $offsetcalc         = (( $paged - 2 ) * $display_count);
elseif ($direction  == 'next') :
    $offsetcalc         = ($paged * $display_count);
elseif ($direction  == 'last') :
    $offsetcalc         = (( $paged - 1 ) * $display_count);
else :
    $offsetcalc         = 0;
endif;

$args = array(
    'post_type'         => 'product',
    'post_status'       => 'publish',
    'orderby'           => 'menu_order',
    'order'             => 'ASC',
    'posts_per_page'    => $display_count,
    'page'              => $paged,
    'offset'            => $offsetcalc,

    if ($search_term != '') :
        's'                 => $search_term,
    endif;

    'tax_query'         => array(
        'relation'          => $search_relation,

        if ($search_tags != '') :
            array(
                'taxonomy'          => 'product_tag',
                'field'             => 'slug',
                'terms'             => array($search_tags),
                'operator'          => $search_relation
            ),
        endif;

        if ($search_categories != '') :
            array(
                'taxonomy'          => 'product_cat',
                'field'             => 'slug',
                'terms'             => array($search_categories),
                'operator'          => $search_relation
            )
        endif;
    )
);

$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) :

However, this returns this error:

There has been a critical error on your website.

You can be sure the variables used are all correct, this is working code without the use of if statements inside the $args.

I have also tried creating variables outside the args array like so:

$paged              = $_POST['page'];
$display_count      = $_POST['display_count'];
$direction          = $_POST['direction'];
$search_term        = $_POST['search_term'];
$search_tags        = $_POST['search_tags'];
$search_categories  = $_POST['search_categories'];
$search_relation    = $_POST['search_relation'];

if ($search_term != '') :
    $search_term_not_blank = "'s' => $search_term,";
endif;

if ($direction      == 'prev') :
    $offsetcalc         = (( $paged - 2 ) * $display_count);
elseif ($direction  == 'next') :
    $offsetcalc         = ($paged * $display_count);
elseif ($direction  == 'last') :
    $offsetcalc         = (( $paged - 1 ) * $display_count);
else :
    $offsetcalc         = 0;
endif;

$args = array(
    'post_type'         => 'product',
    'post_status'       => 'publish',
    'orderby'           => 'menu_order',
    'order'             => 'ASC',
    'posts_per_page'    => $display_count,
    'page'              => $paged,
    'offset'            => $offsetcalc,
    echo $search_term_not_blank;
    'tax_query'         => array(
        'relation'          => $search_relation,
        array(
            'taxonomy'          => 'product_tag',
            'field'             => 'slug',
            'terms'             => array($search_tags),
            'operator'          => $search_relation
        ),
        array(
            'taxonomy'          => 'product_cat',
            'field'             => 'slug',
            'terms'             => array($search_categories),
            'operator'          => $search_relation
        )
    )
);

$the_query = new WP_Query( $args );
if ( $the_query->have_posts() ) :

Again the same error is produced:

There has been a critical error on your website.

I believe it does work if the IF statement wraps around the whole args array, however as I am checking for multiple variables it is quite bulky to have if, elseif, elseif, elseif, else with such a large wp_query. I would need it to be:

if (searchterm != '' & tags != '' & categories != '')
elseif (searchterm == '' & tags != '' & categories != '')
elseif (searchterm != '' & tags == '' & categories != '')
elseif (searchterm != '' & tags != '' & categories == '') 
elseif (searchterm == '' & tags == '' & categories != '') 
elseif (searchterm != '' & tags == '' & categories == '') 
elseif (searchterm == '' & tags != '' & categories == '') 
else (searchterm == '' & tags == '' & categories == '')

EDIT (I have also now tried the long method, the if, elseif, else):

$paged              = $_POST['page'];
$display_count      = $_POST['display_count'];
$direction          = $_POST['direction'];
$search_term        = $_POST['search_term'];
$search_tags        = $_POST['search_tags'];
$search_categories  = $_POST['search_categories'];
$search_relation    = $_POST['search_relation'];

if ($direction      == 'prev') :
    $offsetcalc         = (( $paged - 2 ) * $display_count);
elseif ($direction  == 'next') :
    $offsetcalc         = ($paged * $display_count);
elseif ($direction  == 'last') :
    $offsetcalc         = (( $paged - 1 ) * $display_count);
else :
    $offsetcalc         = 0;
endif;

if (isset($search_term) && isset($search_tags) && isset($search_categories)) :

    $args = array(
        'post_type'         => 'product',
        'post_status'       => 'publish',
        'orderby'           => 'menu_order',
        'order'             => 'ASC',
        'posts_per_page'    => $display_count,
        'page'              => $paged,
        'offset'            => $offsetcalc,
        's'                 => $search_term,
        'tax_query'         => array(
            'relation'          => $search_relation,
            array(
                'taxonomy'          => 'product_tag',
                'field'             => 'slug',
                'terms'             => array($search_tags),
                'operator'          => $search_relation
            ),
            array(
                'taxonomy'          => 'product_cat',
                'field'             => 'slug',
                'terms'             => array($search_categories),
                'operator'          => $search_relation
            )
        )
    );

elseif (empty($search_term) && isset($search_tags) && isset($search_categories)) :

    $args = array(
        'post_type'         => 'product',
        'post_status'       => 'publish',
        'orderby'           => 'menu_order',
        'order'             => 'ASC',
        'posts_per_page'    => $display_count,
        'page'              => $paged,
        'offset'            => $offsetcalc,
        'tax_query'         => array(
            'relation'          => $search_relation,
            array(
                'taxonomy'          => 'product_tag',
                'field'             => 'slug',
                'terms'             => array($search_tags),
                'operator'          => $search_relation
            ),
            array(
                'taxonomy'          => 'product_cat',
                'field'             => 'slug',
                'terms'             => array($search_categories),
                'operator'          => $search_relation
            )
        )
    );

elseif (isset($search_term) && empty($search_tags) && isset($search_categories)) :

    $args = array(
        'post_type'         => 'product',
        'post_status'       => 'publish',
        'orderby'           => 'menu_order',
        'order'             => 'ASC',
        'posts_per_page'    => $display_count,
        'page'              => $paged,
        'offset'            => $offsetcalc,
        's'                 => $search_term,
        'tax_query'         => array(
            'taxonomy'          => 'product_cat',
            'field'             => 'slug',
            'terms'             => array($search_categories),
            'operator'          => $search_relation
        )
    );

elseif (isset($search_term) && isset($search_tags) && empty($search_categories)) :

    $args = array(
        'post_type'         => 'product',
        'post_status'       => 'publish',
        'orderby'           => 'menu_order',
        'order'             => 'ASC',
        'posts_per_page'    => $display_count,
        'page'              => $paged,
        'offset'            => $offsetcalc,
        's'                 => $search_term,
        'tax_query'         => array(
            'taxonomy'          => 'product_tag',
            'field'             => 'slug',
            'terms'             => array($search_tags),
            'operator'          => $search_relation
        )
    );

elseif (empty($search_term) && empty($search_tags) && isset($search_categories)) :

    $args = array(
        'post_type'         => 'product',
        'post_status'       => 'publish',
        'orderby'           => 'menu_order',
        'order'             => 'ASC',
        'posts_per_page'    => $display_count,
        'page'              => $paged,
        'offset'            => $offsetcalc,
        'tax_query'         => array(
            'taxonomy'          => 'product_cat',
            'field'             => 'slug',
            'terms'             => array($search_categories),
            'operator'          => $search_relation
        )
    );

elseif (isset($search_term) && empty($search_tags) && empty($search_categories)) :

    $args = array(
        'post_type'         => 'product',
        'post_status'       => 'publish',
        'orderby'           => 'menu_order',
        'order'             => 'ASC',
        'posts_per_page'    => $display_count,
        'page'              => $paged,
        'offset'            => $offsetcalc,
        's'                 => $search_term
    );

elseif (empty($search_term) && empty($search_tags) && empty($search_categories)) :


    $args = array(
        'post_type'         => 'product',
        'post_status'       => 'publish',
        'orderby'           => 'menu_order',
        'order'             => 'ASC',
        'posts_per_page'    => $display_count,
        'page'              => $paged,
        'offset'            => $offsetcalc
    );

endif;

$the_query = new WP_Query( $args );

if ( $the_query->have_posts() ) :

This method works, excluding when the relation 'OR' is selected, this always returns all products as is continues to search for the search term of blank. Is there a work around for this? If it is blank it is told to not include the args['s']

Last note, I am working within WordPress's functions.php file. This is a function I call upon search.

Surely there is a way to achieve this?

Massive thanks to contributors, Jason.

EDIT (Responding to Antti's answer):

I have tried inserting your code where applicable, here it is in all its glory:

$paged              = ! empty( $_POST['page'] )                 ? $_POST['page']                : 1;
$display_count      = ! empty( $_POST['display_count'] )        ? $_POST['display_count']       : 9;
$direction          = ! empty( $_POST['direction'] )            ? $_POST['direction']           : '';
$search_term        = ! empty( $_POST['search_term'] )          ? $_POST['search_term']         : '';
$search_tags        = ! empty( $_POST['search_tags'] )          ? $_POST['search_tags']         : '';
$search_categories  = ! empty( $_POST['search_categories'] )    ? $_POST['search_categories']   : '';
$search_relation    = ! empty( $_POST['search_relation'] )      ? $_POST['search_relation']     : 'AND';

$offset_modifier = 0;
if ( $direction         === 'prev' ) :
    $offset_modifier        = $paged - 2;
elseif ( $direction     === 'next' ) :
    $offset_modifier        = $paged;
elseif ( $direction     === 'last' ) :
    $offset_modifier        = $paged - 1;
endif;
$offsetcalc = $offset_modifier * $display_count;

if ( $search_term ) {
    $args['s'] = $search_term;
}

if ( $search_tags ) {
    $args['tax_query']['product_tag'] = array(
        'taxonomy'          => 'product_tag',
        'field'             => 'slug',
        'terms'             => array($search_tags),
        'operator'          => $search_relation
    );
}

if ( $search_categories ) {
    $args['tax_query']['product_cat'] = array(
        'taxonomy'          => 'product_cat',
        'field'             => 'slug',
        'terms'             => array($search_categories),
        'operator'          => $search_relation
    );
}

if ( $search_tags && $search_categories ) {
    $args['tax_query']['relation']                  = $search_relation;
    $args['tax_query']['product_tag']['relation']   = $search_relation;
    $args['tax_query']['product_cat']['relation']   = $search_relation;
}

$args = array(
    'post_type'         => 'product',
    'post_status'       => 'publish',
    'orderby'           => 'menu_order',
    'order'             => 'ASC',
    'posts_per_page'    => $display_count,
    'page'              => $paged,
    'offset'            => $offsetcalc,
    'tax_query'         => array(),
);

This loads the page fine, however the search results do not change if any variant of filters are selected.

EDIT (Response to Antti Part 2):

$paged              = ! empty( $_POST['page'] )                 ? $_POST['page']                : 1;
$display_count      = ! empty( $_POST['display_count'] )        ? $_POST['display_count']       : 9;
$direction          = ! empty( $_POST['direction'] )            ? $_POST['direction']           : '';
$search_term        = ! empty( $_POST['search_term'] )          ? $_POST['search_term']         : '';
$search_tags        = ! empty( $_POST['search_tags'] )          ? $_POST['search_tags']         : '';
$search_categories  = ! empty( $_POST['search_categories'] )    ? $_POST['search_categories']   : '';
$search_relation    = ! empty( $_POST['search_relation'] )      ? $_POST['search_relation']     : 'AND';

$offset_modifier    = 0;
if ( $direction         === 'prev' ) :
    $offset_modifier        = $paged - 2;
elseif ( $direction     === 'next' ) :
    $offset_modifier        = $paged;
elseif ( $direction     === 'last' ) :
    $offset_modifier        = $paged - 1;
endif;
$offsetcalc = $offset_modifier * $display_count;

$args = array(
    'post_type'         => 'product',
    'post_status'       => 'publish',
    'orderby'           => 'menu_order',
    'order'             => 'ASC',
    'posts_per_page'    => $display_count,
    'page'              => $paged,
    'offset'            => $offsetcalc,
    'tax_query'         => array()
);

if ( isset($search_term) ) :
    $args['s'] = $search_term;
endif;

if ( $search_tags ) :
    $args['tax_query']['product_tag'] = array(
        'taxonomy'          => 'product_tag',
        'field'             => 'slug',
        'terms'             => array($search_tags),
        'operator'          => $search_relation
    );
endif;

if ( $search_categories ) :
    $args['tax_query']['product_cat'] = array(
        'taxonomy'          => 'product_cat',
        'field'             => 'slug',
        'terms'             => array($search_categories),
        'operator'          => $search_relation
    );
endif;

if ( $search_tags && $search_categories ) :
    $args['tax_query']['relation']                  = $search_relation;
    $args['tax_query']['product_tag']['relation']   = $search_relation;
    $args['tax_query']['product_cat']['relation']   = $search_relation;
endif;

$the_query = new WP_Query( $args );

if ( $the_query->have_posts() ) :

this now works beautifully for the relation 'AND'. It will allow the search of just the title, the title plus a tag or category, both tag and category, or a single tag or category. However it doesn't work for the relation 'OR' unless the search term is populated...

In fact it doesn't actually acknowledge the 'OR' relation at all, it only works towards the search term.

1

If you haven't done so already, I would recommend you to turn on debug logging in wp-config.php as it makes it easier to trace the error in your code.

// added to wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true ); // find error.log in /wp-content, shows backtrace for errors
define( 'WP_DEBUG_DISPLAY', false ); // true if you want errors to be shown on screen

The second thing you could do is to check for the $_POST parameters with ternary operator ( $condition ? true : false; ) and set any required default values. As this prevents any invalid key errors, if for some reason the keys you're expecting aren't present in $_POST.

$paged              = ! empty( $_POST['page'] ) ? $_POST['page'] : '';
$display_count      = ! empty( $_POST['display_count'] ) ? $_POST['display_count'] : 5; // set default value as the "else" case
$direction          = ! empty( $_POST['direction'] ) ? $_POST['direction'] : '';
$search_term        = ! empty( $_POST['search_term'] ) ? $_POST['search_term'] : '';
$search_tags        = ! empty( $_POST['search_tags'] ) ? $_POST['search_tags'] : '';
$search_categories  = ! empty( $_POST['search_categories'] ) ? $_POST['search_categories'] : '';
$search_relation    = ! empty( $_POST['search_relation'] ) ? $_POST['search_relation'] : '';

Above empty() checks that the key exists in $_POST and there's some value assigned to it. If so, the value is set to the variable, else the variable will get an empty string or some default value as its value.

Personally I don't use the alternative if syntax unless I'm adding php into longer segments of html. This looks a little cleaner to me, but this is just a matter of preference.

$offset_modifier = 0;
if ( 'prev' === $direction ) {
  $offset_modifier = $paged - 2;
} else if ( 'prev' === $direction ) {
  $offset_modifier = $paged;
} else if ( 'last' === $direction ) {
  $offset_modifier = $paged - 1;
}
$offsetcalc = $offset_modifier * $display_count;

You can set your default $args before any of those if statements to reduce the number of repeated lines.

$args = array(
  'post_type'         => 'product',
  'post_status'       => 'publish',
  'orderby'           => 'menu_order',
  'order'             => 'ASC',
  'posts_per_page'    => $display_count,
  'page'              => $paged, // maybe protect against negative numbers with ternary operator?
  'offset'            => $offsetcalc, // maybe protect against negative numbers with ternary operator?
  'tax_query'         => array(),
);

With the search related variables set at the beginning of your code, you can trust that the variables will always be set and they are either empty, have some default value, or contain the user submitted value. You can do simple checks with the variables and add any required parameters to the default $args.

if ( $search_term ) {
  $args['s'] = $search_term;
}

if ( $search_tags ) {
  $args['tax_query']['product_tag'] = array( // named keys are allowed, if I remember correctly
    'taxonomy'          => 'product_tag',
    'field'             => 'slug',
    'terms'             => array($search_tags),
  );
}

if ( $search_categories ) {
  $args['tax_query']['product_cat'] = array(
    'taxonomy'          => 'product_cat',
    'field'             => 'slug',
    'terms'             => array($search_categories),
  );
}

if ( $search_tags && $search_categories ) {
  $args['tax_query']['relation'] = $search_relation;
  $args['tax_query']['product_tag']['relation'] = $search_relation;
  $args['tax_query']['product_cat']['relation'] = $search_relation;
}

You can also overwrite the default values later, if needed.

if ( $some_condition ) {
  $args['post_type'] = 'another_post_type';  
}
10
  • Thanks for bringing your wisdom. I believe I still require the relation to be presented within the tax queries for when only one of the two 'categories' or 'tags' is used. That can be achieved by simply adding " 'operator' => $search_relation " back into these two corresponding if statements? Feb 24 '20 at 14:22
  • Further to this, when a user choses to search using the 'OR' relation. Then they only use the tags and categories filters, leaving the search term blank. This returns all posts. I need to prevent the wp_query from searching through the products for a blank string. Can you assist me with this, this is the biggest challenge I have faced! Feb 24 '20 at 14:25
  • I have added an extra edit to my question regarding your answer. Cheers, J. Feb 24 '20 at 14:35
  • 1
    @JasonIsMyName Yes, if you want to set the term relation explicitly, then just add the relation parameters back to the arrays. Also the default $args array should be before the if statements. Otherwise you first set the parameters in the ifstatements and then overwrite them by setting $args with the default values. Feb 24 '20 at 15:14
  • 1
    @JasonIsMyName To exclude the search string from arguments when OR relation is selected, just modify the if condition. E.g. if ( $search_term && 'OR' !== $search_relation ) { $args['s'] = $search_term; }. Feb 24 '20 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.