• I have created a custom post type with a custom status. The purpose of the custom status is to allow the posts to be seen publicly if you know the URL, but exclude them from archive pages and search.

    Let’s say you have a post type for events. When it’s too late to register for an event you might want to remove it from listings and search but still keep the content public for those who have registered and have the link to the event in an email or similar.

    The code for registering the custom status is something like this:

    register_post_status( 'my-custom-status', [
        'label' => '<The label>',
        'label_count' => '<Label count string here>',
        'public' => true,
        'exclude_from_search' => true,
        'show_in_admin_all_list' => false,
        'show_in_admin_status_list' => true,
    ] );

    The problem is that the “exclude_from_search” does not seem to be used by WordPress. I’ve stepped through the code of class-wp-query.php in a debugger to understand how the query is formed and I believe it’s buggy. I made a simple search for “hello”:

    https://localhost/?s=hello

    On line 2122 the search pattern is parsed and the SQL is formed:

    AND (((wp_posts.post_title LIKE '%hello%') OR (wp_posts.post_excerpt LIKE '%hello%') OR (wp_posts.post_content LIKE '%hello%')))

    Directly afterwards the posts_search filter is executed.

    Way down in the function, on line 2523, the “public states” are added to the query, and this is where things go wrong. The line

    $public_states = get_post_stati( array( 'public' => true ) );

    will return an array containing ‘publish’ and ‘my-custom-status’. These are then added to the database query. I would expect ‘my-custom-status’ not to be included here, since a search is being performed and I’ve specifically set the custom post status to be excluded from search. I think there should be a check to determine if the query is a “search” and if so use something like the following instead:

    $public_states = get_post_stati( array( 'public' => true, 'exclude_from_search' => false ) );

    Before reporting this as a bug on the tracker, I’d appreciate feedback on this.

Viewing 1 replies (of 1 total)
  • Thread Starter Tomas Eklund

    (@tomas-eklund)

    In summary, the query that’s being executed looks something like:

    SELECT SQL_CALC_FOUND_ROWS  wp_posts.* 
    FROM wp_posts  
    WHERE 1=1  
    AND wp_posts.ID NOT IN (19398) 
    AND (((wp_posts.post_title LIKE '%hello%') 
        OR (wp_posts.post_excerpt LIKE '%hello%') 
        OR (wp_posts.post_content LIKE '%hello%')))  
    AND wp_posts.post_type IN ('post', 'page', 'attachment', '<some cpts>') 
    AND (wp_posts.post_status = 'publish' 
        OR wp_posts.post_status = 'my-custom-status' 
        OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private')  
    ORDER BY wp_posts.post_title LIKE '%hello%' DESC, wp_posts.post_date DESC 
    LIMIT 0, 10

    I wish the line OR wp_posts.post_status = 'my-custom-status' would not appear there.

Viewing 1 replies (of 1 total)
  • The topic ‘Possible bug: Custom status exclude_from_search not working’ is closed to new replies.