Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm using the following code to do a tax_query and it doesn't seem to work anymore..

At some point it was working and for the life of me it wont, anymore.

<?php

global $pf_override;

class PF_override {

    public $site_terms = array();

    function __construct() {

        // add filters
        add_filter( 'init', array( &$this, 'populates_site_terms' ) );
        add_filter( 'pre_get_posts', array( &$this, 'filter_query' ) );
    }

    function populates_site_terms() {

        // my actual function does some processing and
        // checks caches and combines IDs from multiple
        // different sources here and then sets site_terms 

        $this->site_terms = array( 1, 2, 3 );
    }

    function filter_query( $query ) {

        // not the main query?
        if ( !$query->is_main_query() ) {
            return $query;
        }

        // have terms to filter by?
        if ( !empty( $this->site_terms ) ) {

            // construct tax_query
            $tax_query = array(
                'taxonomy'  => 'site_category',
                'field'     => 'id',
                'terms'     => $this->site_terms,
                'operator'  => 'IN'
                );

            // this needs to be an array of arrays
            $taxquery = array(
                $tax_query
            );

            // set this..
            $query->set( 'tax_query', $taxquery );
        }

        // return new query object
        return $query;
    }
}

// not the admin? init class
if ( !is_admin() ) {
    $pf_override = new PF_override();
}

?>

Taxonomy is added like so:

function PF_register_post_type() {
    $labels = array(
        'name'              => _x( 'Site Category', 'taxonomy general name' ),
        'singular_name'     => _x( 'Site Category', 'taxonomy singular name' ),
        'search_items'      => __( 'Search Site Categories' ),
        'all_items'         => __( 'All Site Categories' ),
        'parent_item'       => __( 'Parent Site Category' ),
        'parent_item_colon' => __( 'Parent Site Category:' ),
        'edit_item'         => __( 'Edit Site Category' ),
        'update_item'       => __( 'Update Site Category' ),
        'add_new_item'      => __( 'Add New Site Category' ),
        'new_item_name'     => __( 'New Site Category Name' ),
        'menu_name'         => __( 'Site Category' ),
    );

    $args = array(
        'hierarchical'      => true,
        'labels'            => $labels,
        'show_ui'           => true,
        'show_admin_column' => true,
        'query_var'         => true,
        'rewrite'           => array( 'slug' => 'sitecat' ),
    );

    register_taxonomy( 'site_category', array( 'post', 'page', 'attachment', 'revision', 'nav_menu_item' ), $args );
}

add_action( 'init', 'PF_register_post_types', 1 );

In my footer.php I add this code:

$GLOBALS['wp_query']->request

I get this as a result when going to mydomain.com/testing:

SELECT wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_name = 'testing' AND wp_posts.post_type = 'post' ORDER BY wp_posts.post_date DESC

The $pf_override variable shows $pf_override->site_terms to be set as an array of

array( [0] => 1, [1] => 2, [2] => 3 )
share|improve this question
add comment

2 Answers

I want give a simple solution.

add_action('pre_get_posts', 'filter_query');

function filter_query( $query ) {
  // **PLEASE NOTE**
  // $this->site_terms refers specifically to logic in the question
  if ( $query->is_main_query() && $query->is_singular && ! empty( $this->site_terms ) ) {
    $site = get_queried_object();
    $terms = wp_get_object_terms($site->ID, 'site_category', array('fields' => 'ids') );
    if ( empty($terms) || empty( array_intersect($terms, $this->site_terms) ) ) {
        $query->set( 'page_id', -1 ); // 404
    }
  }
}

As extra benefit, changing $query->set( 'page_id', -1 ); with the id of a page specifically created is possible redirect visitors to a page you want, instead of force a 404 error.

Hope it helps.

share|improve this answer
    
I think you are missing an add_action to add this to pre_get_posts? –  helgatheviking Jul 24 '13 at 14:33
    
@helgatheviking I wrote in my answer: "filter_query method in the question can contain..." and filter_query method in question is called on pre_get_posts –  G. M. Jul 24 '13 at 14:41
    
I have edited the answer as @helgatheviking advised, so now my solution can used independently from answer logic. –  G. M. Jul 24 '13 at 14:48
    
My bad, I didn't see it in the OP's question, but I think you're answer is more useful to future readers now. +1 from me, pre_get_posts for the win! –  helgatheviking Jul 24 '13 at 15:02
    
Thanks, W pre_get_posts :) –  G. M. Jul 24 '13 at 15:08
show 6 more comments
up vote 0 down vote accepted

Well it seems after digging in to the code, tax_query is being blocked on single post/page pages which is why I'm running in to this issue.

If you see the ability to run tax_query in all circumstances as beneficial, please voice your opinion on trac.

See ticket here: http://core.trac.wordpress.org/ticket/24819

I managed to get around this by duplicating the core code for singular posts and appending to the join and where clauses. The new code is as follows:

<?php

global $pf_override;

class PF_override {

    public $site_terms = array();

    public $sql_join    = '';
    public $sql_where   = '';

    function __construct() {

        // add filters
        add_filter( 'init', array( &$this, 'populates_site_terms' ) );
        add_filter( 'pre_get_posts', array( &$this, 'filter_query' ) );
        add_filter( 'posts_join', array( &$this, 'filter_join' ) );
        add_filter( 'posts_where', array( &$this, 'filter_where' ) );
    }

    function populates_site_terms() {

        // my actual function does some processing and 
        // checks caches and combines IDs from multiple 
        // different sources here and then sets site_terms 

        $this->site_terms = array( 1, 2, 3 );
    }

    function filter_query( $query ) {

        // not the main query?
        if ( !$query->is_main_query() ) {
            return $query;
        }

        // have terms to filter by?
        if ( !empty( $this->site_terms ) ) {

            // construct tax_query
            $tax_query = array(
                'taxonomy'  => 'site_category',
                'field'     => 'id',
                'terms'     => $this->site_terms,
                'operator'  => 'IN'
                );

            // this needs to be an array of arrays
            $taxquery = array(
                $tax_query
            );

            // set this..
            $query->set( 'tax_query', $taxquery );

            if ( $query->is_singular ) {

                global $wpdb;

                $q = &$query->query_vars;

                $q['suppress_filters'] = false;

                $query->parse_tax_query( $q );

                $clauses = $query->tax_query->get_sql( $wpdb->posts, 'ID' );

                $this->sql_join     .= $clauses['join'];
                $this->sql_where    .= $clauses['where'];
            }
        }

        return $query;
    }

    function filter_join( $join ) {

        if ( !empty( $this->sql_join ) ) {
            $join .= $this->sql_join;
        }

        return $join;
    }

    function filter_where( $where ) {

        if ( !empty( $this->sql_where ) ) {
            $where .= $this->sql_where;
        }

        return $where;
    }
}

// not the admin? init class
if ( !is_admin() ) {
    $pf_override = new PF_override();
}

?>
share|improve this answer
    
Why would you need a tax query on a single post? –  helgatheviking Jul 23 '13 at 1:29
    
My particular WordPress instance is a web application that powers around 18,000 website and the individual posts and pages belong to this "site_category" that individual sites "subscribe" to. If the current site is subscribed to category 1 but not category 2, I don't want to show pages that belong to category 2 for that particular site and they need to return 404. It's basically a different low-overhead version of doing a WordPress MultiSite. –  Dustin Dempsey Jul 23 '13 at 2:04
    
@DustinDempsey, it works, but How much code for a such simple task! There is a simpler solution... –  G. M. Jul 24 '13 at 14:04
    
This solution combines everything in to one query, keeping performance in mind, and uses some nice OOP. Simpler isn't always better. –  Dustin Dempsey Jul 25 '13 at 1:09
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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