0

I am attempting to filter results based on what the user has inputted.

function custom_archive() {
    if ( is_post_type_archive( 'profiles' ) ) {
        // if we are on a profiles archive page, edit the query according to the posted data.
        $data = $_POST['networks'];

        if ( isset( $data ) ) {
            //count the array
            if ( count( $data ) > 1 ) {
                $data = implode( ',', $data );
            } else {
                //$data = $data[0];
            }    

            //set the query to only search for whatever the user wants, eg news
            $wp_query->set( 'tax_query', array(
                array(
                    'taxonomy' => 'networks',
                    'field'    => 'id',
                    'terms'    => $data,
                    'operator' => 'IN',
                ),
            ) );
        }
    }
}
add_action( 'pre_get_posts', 'custom_archive' );

I have debugged my code and the data get's inputted correctly. Although, I get no posts back.

Are there any problems with this code? I believe the error may be elsewhere in my theme, but I do wish to check out this code so I can take it out of the equation. Cheers!

EDIT: One thing I should mention is that I have a version of this code working for my Blog page. I am trying to now get this code working for an archive, and for it to return the correct posts still within the archive page, but instead it redirects me to a Search page.

  • How does $_POST['networks'] get set? Do you have a form? Is it a select field or multi-select field? Are the values IDs or slugs? – Jacob Peattie Jul 5 '17 at 10:00
  • Yes, I have a form. The values of the checkboxes are IDs. It's a multi-select field - hence why I validate if $data is an array (to comma-separate it). – Josh Murray Jul 5 '17 at 10:02
1

So there's a few things wrong with the code:

  1. You're not using the query object that's passed to the pre_get_posts hook, so you're not modifying the actual query.
  2. Field is set to id instead of term_id.
  3. If you're using IN as the operator, pass an array to terms.
  4. You're not sanitizing the value of $_POST['networks']. You might be ok without it, since WordPress shouldn't let anything too nasty happen, but it's a good idea to at least ensure that the values are the correct type.

This version of the function addresses these issues:

function my_query_by_selected_networks( $query ) {
    if ( is_admin() ) {
        return;
    }

    if ( $query->is_main_query() && $query->is_post_type_archive( 'profiles' ) ) {
        if ( isset( $_POST['networks'] ) ) {
            if ( is_array( $_POST['networks'] ) ) {
                $networks = array_map( 'intval', $_POST['networks'])
            } else {
                $networks = array( intval( $_POST['networks'] ) );
            }

            $tax_query = $query->get( 'tax_query' ) ?: array();

            $tax_query[] = array(
                'taxonomy' => 'networks',
                'field'    => 'term_id',
                'terms'    => $networks,
                'operator' => 'IN',
            );

            $query->set( 'tax_query', $tax_query );
        }
    }
}
add_action( 'pre_get_posts', 'my_query_by_selected_networks' );

Note:

  1. The function accepts the $query variable and uses that the update the query.
  2. It uses term_id as the value for field.
  3. $networks, the value passed to the tax query is left as an array, or made an array if $_POST['networks'] isn't already an array.
  4. It sanitizes the value of $_POST['networks'] with intval, making sure that $networks is an array of integers, which is what the tax query expects.

Additionally, I modified the tax_query code so that it doesn't entirely replace any tax queries that could be made by other plugins. It does this by checking if there's already a tax query and adding on to it if there is. This is probably unnecessary, but it's a habit of mine.

EDIT: As per Tom's suggestion I've added in $query->is_main_query(), to make sure that we're only modifying the main loop, so this doesn't go and affect things like widgets and menus etc. I also added a bit at the top to bail if we're in the admin, since we don't want to modify back-end queries.

Also, custom_archive is a very generic name for a function, and could easily be shared by other plugins or WordPress itself. It's a good idea to be more descriptive, but most importantly, you should prefix functions with something unique to your theme or plugin to avoid conflicts. In my example it's just my_. I suggest replacing it, since my_ is a common example prefix.

  • 2
    I'll give you an upvote if you throw in an $query->is_main_query() check, bonus points if you mention the super generic function name and adding a prefix – Tom J Nowell Jul 5 '17 at 11:16
0

You should provide an array of id's to the tax_query - like here in the example from the docs:

'tax_query' => array(
    array(
        'taxonomy' => 'actor',
        'field'    => 'term_id',
        'terms'    => array( 103, 115, 206 ),
        'operator' => 'NOT IN',
    ),

So you could and should sanitize the values from $_POST['networks'] but shouldn't do implode which turns the array into a flat string.

  • Thank you for your help - although, this solution never worked in my case. I have changed my question by adding more information. – Josh Murray Jul 5 '17 at 10:24
  • 1
    I would note that you should always query for what you want, querying for what you do not want is slow/expensive and involves full table scans – Tom J Nowell Jul 5 '17 at 11:14

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.