How to filter backend post list showing only posts having a shortcode

I need to filter the Posts and Pages tables in the Admin panel by certain shortcodes. In my plugin, I have added a column for shortcodes to the Posts and Pages views that works like the “Categories” and “Tags” columns, displaying a listing of shortcodes that are used in each post. Now I want to be able to click on one of the shortcodes in the column and have it filter the list of posts or pages to just the ones that use that shortcode.

In my custom column, I am outputting this: <a href="?shortcode=my-shortcode-1">[my-shortcode-1]</a>, <a href="?shortcode=my-shortcode-2">[my-shortcode-2]</a>, ...

Read More

I just need a filter that will make ?shortcode=... work. Here’s basically what I have in mind, but I need to know what hook I could use to accomplish this:

add_filter( 'manage_posts_row', 'filter_by_shortcode' ); // I made up this filter

function filter_by_shortcode(){

    global $post; // Get the current post

    if(!empty($_GET['shortcode']){ // Check for ?shortcode=...

        // Check if given shortcode is used in the post
        if( has_shortcode( $post->post_content, $_GET['shortcode'] )
            return $post; // Return post if shortcode is found

        // Return nothing if shortcode is not used

    }else{
        return $post; // Return post if ?shortcode=... argument is not used
    }

}

Is there a hook that fires for each row of the show all Posts/Pages table in the Admin panel? Or is there another filter I can tie into for this?

Related posts

2 comments

  1. AFAIK that sort of hook does not exists. You have 2 choiches:

    1. use 'post_class' filter hook, check if in admin and if the query string contain a shortcode and if so and if the post has not that shortcode add hidden class that via core admin CSS is set to display: none. In this way the posts without shortcode are retrieved, but hidden.
    2. Second solution is to use a filter on 'posts_where' and add a SQL where clause using REGEXP MySQL function in this way post are not retrieved

    I prefer the second solution, that seems to me more elegant and performant, however, maybe the core has_shortcode function is more reliable than a simple SQL regex.

    Solution 1

    add_filter( 'post_class', 'filter_posts_by_shortcode_css', 10, 3 );
    
    function filter_posts_by_shortcode_css( $classes, $class, $postid ) {
      if ( is_admin() ) {
        $screen = get_current_screen();
        $sh = filter_input( INPUT_GET, 'shortcode', FILTER_SANITIZE_STRING );
        if ( ! empty( $sh ) && $screen->base === 'edit' ) {
          $post = get_post( $postid );
          if( ! has_shortcode( $post->post_content, $sh ) ) {
            $classes[] = 'hidden';
          }
        }
      }
      return $classes;
    }
    

    Solution 2

    add_action('posts_where', 'filter_posts_by_shortcode');
    
    function filter_posts_by_shortcode( $where ) {
      if ( is_admin() ) {
        $screen = get_current_screen();
        $sh = filter_input( INPUT_GET, 'shortcode', FILTER_SANITIZE_STRING );
        if ( $screen->base === 'edit' && ! empty( $sh ) && shortcode_exists( $sh ) ) {
          $where .= " AND post_content REGEXP '\[([[:blank:]]*)$sh([^\[]*)\]'";
        }
      }
      return $where;
    }
    

    Please note that to make both solution work, the shortcode(s) must be registered via add_shortcode, so if the shortcode(s) is(are) registered by yourself or by a third party plugin/theme, be sure that it/they is/are registered in admin screens and before the query happen.

Comments are closed.