Sticky Custom Post Types WordPress Plugin

2011-08-20 5:47pm by Ann

I needed sticky custom post types for a client project but found out that WordPress doesn’t support this out of the box. Luckily it turned out to be pretty simple to add in that functionality with just a little bit of code… which I have turned into a plugin for everyone to use! YAY!

Installation/instructions:

1. Download the plugin from wordpress.org.

2. Upload sticky-custom-post-types.php to the /wp-content/plugins/ directory.

3. Select custom post types you want to enable with the sticky function on the ‘Settings → Reading’ page. Unless you’re using custom queries to display your sticky posts, you probably also want to check the option to display selected post types on the blog home.

4. When adding/editing a custom post type, check the “Stick this to the front page” checkbox if you want to stick that custom post to the front page.

And that’s it!

Unfortunately there’s no way to put the “Stick this…” checkbox in the same place as it is on the built-in “Posts” add/edit page (to do so would require modifying core code), but I think that having it display immediately is actually a lot more straightforward than having to click through the visibility setting edit link to get to it.

38 Responses to “Sticky Custom Post Types WordPress Plugin”

  1. Ashu says:

    Hello,
    I have created 3 custom post types for my client, now my client want sticky post feature for the custom post type. He wants to show custom post type post by tags, categories and sticky. Am using custom query code to display the post list by categories and tags but not able to get this sticky feature. So can you please help me out with code.
    Any help much appreciated.
    Thanks a lot in advance,
    Ashu

    • Ann says:

      $query = new WP_Query(array('post__in' => get_option('sticky_posts')));

      • Victor says:

        Hello! Great job with this plugin and thanks for sharing this code. I’m working with a client that would like to display a custom post type in a jquery slider. I have that working just fine, but now they would like to only display sticky’s from the same custom post type. So I installed your plugin and altered my code to this (part of the function):

        $globalSlider = new WP_Query ( array (
        ‘post_type’ => $postType,
        ‘category_name’ => $catName,
        ‘posts_per_page’ => $postNum,
        ‘post__in’ => get_option( ‘sticky_posts’ )
        ));

        I checked a couple posts created with the custom post type it is still displaying non-sticky posts. Any ideas or suggestions would be really appreciated. Thanks.

  2. thomas says:

    Hi, this is a great plugin. One question how do I stop the custom post from also displaying in the loop? Im trying to use post__not_in but its not working
    code:
    $wp_query = new WP_Query();
    $wp_query->query( array( ‘post__not_in’ => get_option( ‘sticky_posts’ ) ));

    • Ann says:

      You need to set the ‘post_type’ argument to ‘post’ in your query. I just checked in a new version of the plugin that will optionally enable adding checked custom post types to the home loop (sticky posts are enabled only when is_home and on the first page) so please update and let me know if you’re still having problems.

  3. Tim says:

    Hi there,
    Plugin is great worked fine.. ..and then boom. An update to another plugin ‘Advanced Custom Fields’ (http://wordpress.org/extend/plugins/advanced-custom-fields/) has knocked it out and loops involving sticky posts dont work at all.

    Now I know that issues with other plugins isnt your responsibility and I dont mind, I just wondered if there was any obvious reasons as to why they dont play together..

    ..But anyhow, plugin on its own works fine!

    Thanks.

    • Ann says:

      I can’t think of why that plugin would affect mine… However I did recently update my plugin and by default it won’t include custom post types (sticky and normal) in the home loop anymore unless you enable that setting. Could that be your issue?

  4. Matt Jarvis says:

    Hi – thanks for this plug in, however with wordpress 3.1 and trying to list all posts in a custom post_type, it seems to interfere and bring in some very random results (not just stick posts). Was driving me a bit crazy as I couldn’t understand it, even using

    $show_query = new WP_Query( array (“post_type” => “sl_shows” , ‘ignore_sticky_posts’=> 1, ‘post_status’ => ‘publish’, ‘orderby’ => ‘title’, ‘order’ => ‘ASC’, ‘posts_per_page’ => 5 ) );

    brought in 2 other post_types (ignore_sticky_posts did seem to work, maybe there is some id overlap?)

    best wishes
    Matt

    • Ann says:

      Hey Matt, are you saying that your query is still bringing in random non-sticky posts of post types other than the one you specified? If so, are there any other filters that might be affecting query results? Did you try adding the suppress_filters parameter to your custom query?

  5. Vanessa says:

    Hi Ann, thanks for this plugin. Question: I created a custom post type and am displaying the posts via archive-posttype.php. It seems your plugin does not stick the posts in the archive page. Will your plugin work within an archive display? Thanks!

    • Ann says:

      Hi Vanessa, unfortunately the plugin doesn’t currently add sticky posts to the custom post type archive pages, although this function is something I would likely add down the line.

  6. Hi – nice plugin – works with the default WP frontpage default posts listing. Hoever I am having trouble getting it to work when I do a custom loop (of the Delight theme):

    
        $sticky = get_option('sticky_posts'); // my new code
        $args=array(
        'post__in'  => $sticky, // my new code
        'ignore_sticky_posts' => 1, // my new code
        'gallery'  => $cat_selected,
        'post_type' => 'portfolio',
        'posts_per_page' => $posts_per_page,
        'paged' => $paged
      );
      $my_query = null;
      $my_query = new WP_Query($args);
      $i=0; while ( $my_query->have_posts() ) : $my_query->the_post();
    

    any suggestions?
    many thanks,
    Mike

    • Ann says:

      If you look at wp-includes/query.php line 2683, you’ll see that all the logic for splicing sticky posts in at the top and removing them from the flow is only going to be run if is_home is true. So you could either set the home flag or copy the logic from the core to get your custom query to return the posts you’re looking for. Neither are really great solutions for sticky posts IMO, so perhaps the right thing to do would be to submit a suggestion to trac to expand on this limitation.

  7. Toine Kamps says:

    Hi Ann,

    Thanks for this plugin, I was looking for this!
    I was experiencing the same problems as Matt Jarvis, on a completely different page in a different loop suddenly other custom post types were showing up, even when post_type was set to ‘post’ like this:
    ‘post_type’ => ‘post’

    The suppress filters parameter in this loop did the trick though:
    ‘suppress_filters’ => true

    I discovered a second problem though if your’re using the very useful posts-to-posts plugin from scribu: http://scribu.net/wordpress/posts-to-posts

    If I want 2 out of my 6 custom post types to be enabled for sticky support on the homepage, I check these post types on the ‘Settings -> Reading’ page, as well as the ‘Display selected post type(s) on: home’.
    I discovered that the other 4 post types lose their connection from the posts-to-posts plugin if you do this, or at least they don’t show up anymore.

    If I check all 6 of the custom post types on the ‘Settings -> Reading’ page the problem is solved, but then anyone could make any of the custom posts sticky on the homepage. Is there are a fix for this?

    Thanks!

    • Ann says:

      Unfortunately I’m not familiar with that plugin… but I’m guessing that what you mean is that it’s already displaying custom post types you want on your home page, though not as sticky posts. Basically, I think the problem is that my plugin takes those backend settings and tells the home page to filter out all the custom post types that are unchecked… and it uses the same settings to determine which custom post types to add that sticky option checkbox to.

      To get around this, the easiest thing to do would probably be to disable my plugin’s home page posts filter and write your own. So in your functions.php file:

      
      function my_sticky_posts_filter($query) {
        if($query->is_home && !$query->get('suppress_filters')) {
          $post_types = get_post_types(array('_builtin' => false, 'public' => true), 'names');
          $query->set('post_type', $post_types);
        }
        return $query;
      }
      remove_filter('pre_get_posts', 'super_sticky_posts_filter');
      add_filter('pre_get_posts', 'my_sticky_posts_filter');
      

    • The ‘suppress_filters’ => true did the trick for me too!

      thanks

  8. Toine Kamps says:

    Thanks for you reply!
    Well, altough it’s a bit tricky that users can make any post type sticky now, I think I’ll stick to keeping the post_types checked for now.
    Setting that ‘suppress_filters’ is vital by the way, because it’s messing up almost all my other loops in my site.
    Cheers

  9. Igor says:

    Hello, Ann! Thank you for this clear plugin. I wonder if it’s possible or not, to get (with it’s help) a list of sticky posts of specific custom post type: not in the loop (where you can apply filter), but outside, for example in the sidebar.

    I use this common way:

    $sticky_ids = get_option(‘sticky_posts’);
    $sticky_posts = get_posts( ‘include’ => $sticky_ids )

    The problem is: there are ids of posts of all types, not only needed in every special case.

    • Ann says:

      Hi Igor,

      You should be able to specify the post types you want get_posts() to return. For example, say you just want to display two custom post types, “events” and “books”:

      
      $sticky_posts = get_posts(array(
           'post__in' => get_option('sticky_posts'),
           'post_type' => array('events', 'books')
           ));
      

  10. Antuan says:

    No funciona en WP 3.3.1

  11. Toine says:

    Hi again,
    Unfortunately your plugin is causing troubles with the plugin SlideDeck: http://www.slidedeck.com
    The slides are not showing up at all… I confirmed it’s caused by this plugin.
    Any ideas on how to fix this?
    Thanks!

  12. Toine says:

    To be more specific, it’s line 94 in your sticky-custom-post-types.php code:
    add_filter(‘pre_get_posts’, ‘super_sticky_posts_filter’);
    ‘pre_get_posts’ conflicts in someway….

    I really need both of these great plugins to work together :(

  13. Toine says:

    Hi Ann, thanks for getting back to me!
    Unfortunately that doesn’t change anything… It’s the following line:
    $query->set('post_type', $post_types);
    that messes everything up somehow (even my menus dissapear all of a sudden).
    How should my custom query look like when I remove your filter?
    Now it looks like this (it checks if there are any stickies otherwise it will show my latest post):

    $sticky = get_option(‘sticky_posts’); // Get sticky posts
    $tmp = array(‘post__in’ => $sticky, ‘post_status’ => ‘publish’); // Get published sticky posts
    $stickypublish = new WP_Query($tmp);
    $totalstickies = count($stickypublish); // Get total of published sticky posts

    $notsticky = get_posts(array(‘posts_per_page’ => 1)); // Get featured posts
    $total = count($notsticky); // Get total of featured posts

    if ($sticky) {   // If there are sticky posts
      $supress = false;
    } else { // If there are no sticky posts
      $supress = true;
    }
    $args = array(
      'suppress_filters' => $supress,
      'posts_per_page' => 1,
      'post__in'  => $sticky,
      'post_status' => 'publish',
      'ignore_sticky_posts' => 1
    );
    query_posts($args); // Show newest published sticky post  
    
    if (have_posts()) :
      while (have_posts() ) : the_post(); ?>
        // Display post
      <?php endwhile;
    endif;
    wp_reset_query(); ?>

    Any thoughts of what might go wrong?
    Thanks!

    • Ann says:

      Did you ever figure out these issues? Does the slidedeck plugin use custom post types for anything? Is something getting messed up on the blog home only or are other pages affected?

  14. Toine says:

    Hi Ann,
    Jup SlideDeck uses a custom post type for it’s slides, but almost al of the plugins do. Actually nothing got messed up, but the SlideDeck instances simply didn’t show up. In the end I think the problems were caused by the SlideDeck plugin itself.
    I ended up using a different plugin called ‘AnythingSlider’ http://wordpress.org/extend/plugins/anythingslider-for-wordpress/
    which works perfectly in combination with your plugin :)
    Thanks!

  15. Tom says:

    Hello,
    First, great plugin !
    The backoffice part is perfect.

    For the front, I have to write two custom queries (bad perf.) rather than patch with this : http://core.trac.wordpress.org/ticket/12702
    (and commented your plugin filter , ‘pre_get_post’)
    here is my loop query :

    $sticky = get_option(‘sticky_posts’);
    $shows = (int)get_option(‘force_home_display’);
    $args = array(
    ‘post_type’ => ‘product’,
    ‘post__in’ => $sticky,
    ‘posts_per_page’ => $shows
    );

    $loops_sticky = query_posts($args);
    // here I could count the size of first loop and redifine second loop count // something like $shows = $shows – sizeof($loops_sticky )
    $args_no_sticky = array(
    ‘post_type’ => ‘product’,
    ‘post__not_in’ => $sticky,
    ‘posts_per_page’ => $shows
    );
    $loops_no_sticky = query_posts($args_no_sticky);
    // need more if($loops_no_sticky) /else test
    $loops = array_merge($loops_sticky,$loops_no_sticky);
    // debug
    //print_r($loops);

    Note : I don’t understand why there is a else case, in the pre_get_posts filter
    else
    $query->set(‘post_type’, ‘post’);
    I think it could be suppressed to avoid a lot of issues (custom queries, ..)

    • Ann says:

      Hi Tom, thanks for commenting on my plugin!

      For stuff like sticky archive pages on the front end I’ve also done it that way myself with a couple of loops (I like to use the the_posts filter in my functions.php file so I can keep my template files clean). Last time I looked, the sticky posts code in query.php had a hard-coded check for is_home, but you could also copy and paste the code from there for your custom query.

      The way this plugin works is pretty simple — I just add in the checkbox backend ui on the edit page for custom post types so that they can be selectively added to the global sticky_posts array. The reason the else case in pre_get_posts is there is to filter out all the custom post types from the sticky posts array in the case where a person might not want to display those on the home page, but still might want to use the backend ui to set some custom posts to sticky (for custom loops or something).

  16. mike says:

    Hi Ann – this plug-in is great and does almost exactly what I need. The only thing is, when I activate it, it’s making ALL of my custom post types appear on my home page, not just the ones marked ‘sticky’. Is that intended?

    • Ann says:

      Yep. If you just want sticky custom posts to show, you can remove the pre_get_posts filter:

      remove_filter(‘pre_get_posts’, ‘super_sticky_posts_filter’);

      • mike says:

        thanks for the reply. I’m not quite sure I understand, though. I thought the point of the plugin was that it would only show posts which were selected as sticky, so why do i need to edit PHP to make it do that as opposed to showing all custom posts? if so, where would i find that line?

        • mike says:

          Hi Ann – nevermind, I figured it out. (I’m good at CSS, but a total noob at PHP.) Works perfectly now. Not sure I understand why the intended behavior would be to display posts that are not marked as sticky, but no worries now – this plug-in is a real life-saver and should probably have been part of the actual WP release.

          • Ann says:

            People will generally want to supplement their home page with custom post types both sticky and non, to be shown alongside regular posts. To have a mix of custom and regular post types at the top followed by regular posts only is less in line with most use cases.

            You can actually add the remove_filter line to your theme’s functions.php file. This way you can leave the plugin code intact.

  17. Scott says:

    Hi,

    Thanks for such a handy plugin!
    I am having a small issue with it. The posts I mark as sticky appear at the top of the first page as expected but when navigating to page 2 of posts, they also appear at the top there. Is that intended? It would be great if they only appeared at the top of page 1.

    Thanks!

    • Ann says:

      Hi Scott,

      Hmm, that isn’t the way the plugin works on the default home loop… Are you using any custom loops or post filters in your theme, or using any other plugins that might be altering your home loop?

      • Scott says:

        Hey,

        Perfect time to reply! I just looked into it a bit more and it was probably coincidence because it wasn’t actually repeating them on page 2. Instead, they all naturally appeared at the top of page 2 and I assumed it was the plugin causing it but was just where they were in the loop.

        I figured when I set them to ‘sticky’ it would remove them from their ‘expected’ position and only show them at the top of page 1 (nowhere else) but instead they get shown twice (at the top of page 1 and once in the position they would appear had they not been made sticky).

        Unfortunately not ideal for what I need, but a great plugin none-the-less!

        • Ann says:

          I think something else might still be affecting the query… the way it works is the same way the WordPress home loop does, so sticky posts do get pulled out of the regular flow.

Leave a Reply