5

On my site several filters should be applied if the user is viewing the static home page. My understanding is that is_front_page() should determine if that is indeed the case.

However, whenever I use the function I find that sometimes it returns true (e.g. posts_orderby) but mostly it returns false (e.g. pre_get_posts, posts_fields, posts_join and posts_where). Regardless of the result though, I always recieve the following notice -

Trying to get property of non-object in {my_path}\wp-includes\query.php on line 4373

The method containing the offending line is WP_Query::is_front_page() -

public function is_front_page() {
    // most likely case
    if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
        return true;
    /** The offending line */ elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
        return true;
    else
        return false;
}

To combat this issue I have created my own function, as below, but it seems "dirty" to have had to do so. So my question is thus - is there a better way to do this?

function fgw_is_front_page($q){

    if(!is_a($q, 'WP_Query'))
        return false;

    return (get_option('show_on_front') == 'page' && get_option('page_on_front') && $q->get('page_id') == get_option('page_on_front'));

}

Edit

Afer further investigation it seems that the offending line is actually 4369 (wp-includes/querey.php) - $page_obj = $this->get_queried_object();

$page_obj is being returned as null, meaning that check for $q->is_front_page() fails. This seems wrong, and unless anyone is able to explain how this could in any way be expected behaviour I'll look at opening a ticket on Trac.


Update

I have now amended the above function. Making use of the second argument passed to all of the filters that I am using (the WP_Query instance), as mentioned by @birgire, has allowed me to do away with the global.

However, taking the below example, I am still receiving the aformentioned notice (and result of false) when checking $q->is_front_page() -

add_filter('posts_fields','fgw_index_posts_fields', 10, 2);
function fgw_index_posts_fields($fields, $q){

    global $wpdb;

    if(!is_admin() && is_main_query() && (is_home() || $q->is_front_page($q)))
        $fields.= $wpdb->prepare(', %1$s.name as category_name', $wpdb->terms);

    return $fields;

}

Replacing $q->is_front_page() with fgw_is_front_page($q) works, but again it feels dirty to have to use a custom solution when seemingly there is one that already exists.

5

Regarding the posts_orderby, posts_where, posts_join and posts_clauses hooks, the current \WP_Query object is available through the second input argument.

These are the relevant parts from the \WP_Query class:

$orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
$where   = apply_filters_ref_array( 'posts_where', array( $where, &$this ) );
$join    = apply_filters_ref_array( 'posts_join', array( $join, &$this ) );
$clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );

all using the apply_filters_ref_array function and &$this is the current \WP_Query instance. The Codex says the following about this function:

This function is identical to apply_filters, but the arguments passed to the functions hooked to $tag are supplied using an array.

You can access the second argument with for example:

add_filter( 'posts_where', function( $where, \WP_Query $q )
{
    if( $q->is_front_page() ) <-- This method won't work here with a static front-page!!!
    {
        // ...
    }
}, 10, 2 );

so you don't have to rely on the global $wp_query object.

After tracing this inside WP_Query, we've found the reason why calling the is_front_page() method doesn't work inside these filter callbacks. There problem lies within the is_page() method that tries to use the get_queried_object() method that still hasn't got an object to return.

The is_home() method works on the other hand, and it isn't calling the is_page() method.

Update:

There seems to be at least two Trac tickets, #27015 and #21790, that related to this problem.

In #27015 there's a suggested patch by @mattonomics, that modifies the queried_object object within the parse_query() method.

So why not try these modifications in our case, but through the parse_query hook instead:

/**
 * A workaround for the is_front_page() check inside pre_get_posts and later hooks.
 *
 * Based on the patch from @mattonomics in #27015
 *
 * @see http://wordpress.stackexchange.com/a/188320/26350
 */

add_action( 'parse_query', function( $q )
{
    if( is_null( $q->queried_object ) && $q->get( 'page_id' ) )
    {
        $q->queried_object    = get_post( $q->get( 'page_id' ) );
        $q->queried_object_id = (int) $q->get( 'page_id' );
    }
} );

We should be able to add further changes this way, from that patch.

  • Thanks for this. I've now added the second argument (kind of embarrased I missed that!), meaning I can do away with the global in my fgw_is_front_page() function. However, trying to use $q->is_front_page(), as in your example, still results in the notice posted in my question (this time for all of my filters though) and the result of false. – David Gard May 14 '15 at 14:15
  • Try to use $q as much you can instead of the global $wp_query, so try for example: if( ! is_admin() && $q->is_main_query() && ( $q->is_home() || $q->is_front_page() ) ) in your code example. – birgire May 14 '15 at 14:42
  • But $q->is_front_page() doesn't work, it always returns a notice and false, no matter what page I am on. And for using $q against the other examples, presumably that is desirable because the core functions is_home(), etc. use the global $wp_query, rather than it being my code that uses an undesirable global? – David Gard May 14 '15 at 15:51
  • 1
    I updated the answer with an idea from the suggested patch, but using the parse_query filter instead. @DavidGard – birgire May 14 '15 at 18:12
  • 2
    Good find, that does indeed work. Hopefully the WP powers-that-be will listen and make the minor adjustments necessary to include this functionality. – David Gard May 14 '15 at 19:00
0

instead of

$query->is_front_page()

try using

$query->get('page_id') == get_option('page_on_front')

(in context:)

function custom_pre_get_posts( $query ) {
    if ( $query->get('page_id') == get_option('page_on_front') ) {
        // do stuff
    }
}
add_action('pre_get_posts', 'custom_pre_get_posts');

This solution is from here: https://core.trac.wordpress.org/ticket/21790#comment:11

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.