• Resolved starapple

    (@starapple)


    I stumbled upon the query below while trying to find a way to cause a custom post type to expire on a set date. An expiry date is set only for posts of this custom type but when the function executes it hides ALL posts outside the custom type.

    And rather than hiding the custom posts less than (<) today’s date, it shows them. When the sign is set to greater than (>) the dates are correctly hidden.

    function my_filter_expired_posts( $query ) {
    
        // doesn't affect admin screens
        if ( is_admin() )
            return;
    
        // check for main query
        if ( $query->is_main_query() ) {
            //filter out expired posts
            $today = date('Y-m-d H:i:s');
    
            $metaquery = array(
                array(
                     'key' => 'end_date',
                     'value' => $today,
                     'compare' => '<',
                     'type' => 'DATE'
                )
            );
            $query->set( 'meta_query', $metaquery );
        }
    }
    add_action( 'pre_get_posts', 'my_filter_expired_posts' );

    I read the Codex and tried to use the AND condition to include the custom post type’s key value pair ending with the below function, but that results in all posts types being hidden (posts and custom posts):

    function my_filter_expired_posts( $query ) {
    
        // doesn't affect admin screens
        if ( is_admin() )
            return;
    
        // check for main query
        if ( $query->is_main_query() ) {
            //filter out expired posts
            $today = date('Y-m-d H:i:s');
    
            $metaquery = array(
                array (
                    'key' => 'post_type',
                    'value' => 'jobs',
                    'compare' => '=',
                    'type' => 'CHAR'
                ),
                'relation' => 'AND',
                array(
                     'key' => 'end_date',
                     'value' => $today,
                     'compare' => '<',
                     'type' => 'DATE'
                )
            );
            $query->set( 'meta_query', $metaquery );
        }
    }
    add_action( 'pre_get_posts', 'my_filter_expired_posts' );

    The thing is, I really don’t know how the filter works so I can’t begin to imagine what conditions to set and how.

    I thought limiting the query to the custom post types would be the first and best option rather than checking if ‘end_date’ is empty or somehow using the EXISTS/NOT EXISTS comparisons. See: https://codex.www.ads-software.com/Class_Reference/WP_Meta_Query
    https://codex.www.ads-software.com/Plugin_API/Action_Reference/pre_get_posts

    I’d really appreciate your help.

    Thanks.

    • This topic was modified 7 years, 8 months ago by starapple.
    • This topic was modified 7 years, 8 months ago by bdbrown.
Viewing 7 replies - 1 through 7 (of 7 total)
  • Thread Starter starapple

    (@starapple)

    …And I just realized that ‘post_type’ can have no effect as it’s not a post meta.

    Moderator bcworkz

    (@bcworkz)

    Right, post_type does not belong in meta queries unless you’ve set a custom field called ‘post_type’. You need to set a separate ‘post_type’ query var to what ever post types you want for this query. Perhaps $query->set('post_type', 'jobs'); That constraint will be applied AND the meta query constraint will be applied. Assuming your meta query already works correctly, adding a post_type query_var will further restrict the returns to only that post type.

    Unless you’ve selectively added your callback only under certain conditions, your added restrictions will be applied to ALL post queries, so you need further logic to ensure it’s only applied where you want it. You can either check other query vars for if they are the right value, or selectively call add_action() only under certain circumstances. Naturally you need to do so before the query object makes a WP_Query::get_posts() call.

    Thread Starter starapple

    (@starapple)

    Hi @bcworkz,

    Since I also have a start_date associated with the post type I did the below, but rather than seting a condition before searching end_date I still get what seems to be a query of all meta data, including all post types that have no start_date or end_date:

                array (
                    'key' => 'start_date',
                    'value' => '',
                    'compare' => 'EXISTS',
                    'type' => 'CHAR'
                ),
                'relation' => 'AND',

    In my head what this is saying is: if a start date exists AND there’s an end date, then execute the query.

    I thought of your $query->set('post_type', 'jobs'); but this isn’t a query of wp_posts.

    Moderator bcworkz

    (@bcworkz)

    There’s something wrong with your mental model of what’s going on that may be hindering your success. If you are hooked to “pre_get_posts” action, your query IS a post query using the WP_Query class. Thus setting the ‘post_type’ query var for custom post types IS the correct approach. Chew on that until it makes sense. The meta query array you are defining is not a conditional per se. It is not like if this is true, the query runs. The query ALWAYS runs. You are adding additional qualifications to the query’s WHERE clause.

    Your meta query logic sounds correct. Since I don’t have similar data, I cannot test to confirm your code. If you are getting all posts without qualification, there may be a syntax error in your meta query arrays. Just because it is proper PHP syntax does not make it valid meta query syntax. Check your array structure carefully against the meta query documentation. Avoid adding fields unless they are required. For example, 'value' => '', in your EXISTS argument is requiring the field to exist AND to be an empty string. If any value is acceptable, omit the value argument (post 3.9 anyway).

    Thread Starter starapple

    (@starapple)

    You’re correct about the value. I had commented it out.

    If you have a custom post type (even without the meta fields/key/value I have) you could give it a whirl by trying to exclude based on your existing key/value.

    My installation has the Hello World post and test post and the custom post type has two posts. I set one to an expiry date before today and one to expire in the future.

    The expired custom post does not display when the link is visited but the unexpired one displays. However, Hello World and Test are also hidden.

    Maybe because I only found out about pre_get_posts yesterday, it’s taking me a while to appreciate how to use it. I had before hand, that wrapping the function in a condition for custom post type only would be needed (or set a condition before executing the query) but again it eludes me.

    Thread Starter starapple

    (@starapple)

    Eureka @bcworkz,

    Thanks for the guidance and discussion.

    The answer was not $query->set('post_type', 'jobs'); but if ( $query->query_vars['post_type'] == 'jobs' )

    See: https://devotepress.com/tutorials-hacks/wordpress-coding/when-to-use-pre_get_posts-in-wordpress/

    Fully working function fixed with one line. Thanks

    function my_filter_expired_posts( $query ) {
        // doesn't affect admin screens
        if ( is_admin() )
            return;
    
        // check for main query
        if ( $query->is_main_query() ) {
             //filter out expired posts
            $today = date('Y-m-d H:i:s');
            //$today = date('DD, M dd, yy');
    
            $metaquery = array(
                array(
                     'key' => 'end_date',
                     'value' => $today,
                     'compare' => '>',
                     'type' => 'DATE',
                )
            );
           if ( $query->query_vars['post_type'] == 'jobs' )
            $query->set( 'meta_query', $metaquery );
        }
    }
    add_action( 'pre_get_posts', 'my_filter_expired_posts' );

    Regarding the ‘>’ in the date parameter, it seems the original author made a mistake since “today” needs to be more than (i.e, beyond) the expiry date.

    • This reply was modified 7 years, 8 months ago by starapple.
    Moderator bcworkz

    (@bcworkz)

    Awesome! Date operations can be a little tricky if one doesn’t fully think them through. I have a similar blind spot for time zones and daylight/summer time conversions. I should just do the opposite of whatever I think I should do!

Viewing 7 replies - 1 through 7 (of 7 total)
  • The topic ‘Cause Custom Post Type to Expire by Date’ is closed to new replies.