i have this custom post_type: tvr_apartment

function custom_post_apartment() {
        $labels = array(
            'name'                => 'Apartments',
            'singular_name'       => 'Apartment',
            'add_new'             => 'Add New',
            'add_new_item'        => 'Add New Apartment',
            'edit_item'           => 'Edit Apartment',
            'new_item'            => 'New Apartment',
            'all_items'           => 'All Apartments',
            'view_item'           => 'View Apartment',
            'search_items'        => 'Search Apartments',
            'not_found'           => 'No apartments found',
            'not_found_in_trash'  => 'No apartments found in trash',
            'parent_item_colon'   => '',
            'menu_name'           => 'Apartments'

        $args = array(
            'labels' => $labels,
            'public' => true,
            'query_var' => true,
            'rewrite' => true,
            'capability_type' => 'post',
            'has_archive' => true,
            'hierarchical' => false,
            'menu_position' => null,
            'taxonomies' => array('rf_apartment_feature'),
            'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt' )

        register_post_type( 'tvr_apartment', $args );

And I would like to enable the sticky post functionality to it,

enter image description here

I searched here: http://codex.wordpress.org/Function_Reference/post_type_supports

But i it seems is not the way to go, any ideas?


5 Answers 5


According to extensive and long running trac ticket #12702, custom post types don't (and likely won't) support sticky functionality.

It's probably not impossible to reuse it (with unholy amount of copy paste and edge cases) for CPT in custom site, but in my opinion custom solution (probably custom fields based) would be more practical and clean approach.


Edit 2022: You can use the plugin mentioned in @Ray's answer now! Tested and seems to save the sticky attribute in a native way, so you can use e.g. ignore_sticky_posts

Original Answer:

As none of the currently existing plugins for this purpose supports WP5, a simple (but not great) solution is to use a new metabox. In your CPT's plugin:

add_meta_box('pseudosticky', 'Is sticky', 'addbox', 'YOUR CUSTOM POST TYPE SLUG HERE', 'normal', 'high');

function addbox($post, $metabox) {  
 $entered = get_post_meta($post->ID, 'pseudosticky', true);
    <label><input name="pseudosticky" type="checkbox"<?if($entered=="on")echo' checked="checked"';?>> Is sticky</label>

Then in the query

  'meta_query' => array(
            'key' => 'pseudosticky',
            'value' => "on",
            'compare' => '='
        //more meta conditions can be added here as arrays

I've managed to get the following to work. Let me describe the technique so that you can decide whether or not to use it.

  1. the code uses two hooks, one fired just before the "side" meta boxes get placed, and another immediately after the "date/time" section in the publish meta box.

  2. the first hook (before) records the original post type, and then switches it to "post", wordpress thinks it's a post and sets the default fields specific to the "post" post type.

  3. the second hook (after) will reset the post type back to the original.

If anyone runs into any issues or can come up with any unforeseen use cases where this technique may fail, please do reply.

// see /wp-admin/edit-form-advanced.php .. since wp 2.5.0
add_action( 'submitpost_box', function() {
    // fyi .. unable to use "post_submitbox_minor_actions" action (/wp-admin/includes/meta-boxes.php) because $post_type is set early
    global $post;
    if ( isset( $post->post_type ) && in_array( $post->post_type, array( 'post_type_1', 'post_type_2' ) ) ) {
        echo 'before'; // debug
        $post->post_type_original = $post->post_type;
        $post->post_type = 'post';
} );

// see /wp-admin/includes/meta-boxes.php .. since wp 2.9.0
add_action( 'post_submitbox_misc_actions', function() {
    global $post;
    if ( isset( $post->post_type_original ) && in_array( $post->post_type_original, array( 'post_type_1', 'post_type_2' ) ) ) {
        echo 'after'; // debug
        $post->post_type = $post->post_type_original;
        unset( $post->post_type_original );
} );

Note: the above takes care of adding the option to the UI, you would still need to check-for and work-with sticky posts in you templates/output .. something like the following (just without the plugin):



For those looking, I can confirm this plugin works as of WP version 5.9: https://wordpress.org/plugins/sticky-posts-switch/


I was surprised to find out that this feature is still not available.

I was hoping at least in the WP_Query we may get something like sticky_posts and then you pass the IDs into that, but that wasn't there.

So I did something like this:


$args = array( 'post_type' => 'some_post_type', 'posts_per_page' => 20 , 'orderby' => 'title', 'order'   => 'ASC');

$loop = new WP_Query( $args );

$sticky_posts = array( 11462 ); // post ids for the posts you want to make sticky goes here

// Also need to show the sticky
while ( $loop->have_posts() ) : $loop->the_post(); 
  if ( in_array($post->ID, $sticky_posts) ):
    echo "I am STICKY!";

while ( $loop->have_posts() ) : $loop->the_post(); 
  if ( !in_array($post->ID, $sticky_posts) ):
      echo "I am not sticky :( ";

Of course this isn't the best solution, it has multiple caveats, but it worked for my simple requirement where I had just one post I want to stick to the top.


  • You have to modify the block of code where you have queries, and add multiple loops.
  • You can't order them custom.
  • Only posts in the current query will show up, so if you have a sticky post beyond the set posts per page limit then that post won't be sticky, at least on that page.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.