Skip Navigation

[Resolved] Make Custom Post Types Sticky

This thread is resolved. Here is a description of the problem and solution.

Problem:
The customer asked how to use the sticky posts feature with the custom post types.

Solution:
Guided that WordPress only supports the sticky post feature for the native/built-in "post" type and suggested using a checkbox type custom field as an alternative.

Relevant Documentation:
n/a

This support ticket is created 2 years, 7 months ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Sun Mon Tue Wed Thu Fri Sat
- 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 -
- 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 -

Supporter timezone: Asia/Karachi (GMT+05:00)

This topic contains 14 replies, has 2 voices.

Last updated by Pete 2 years, 6 months ago.

Assisted by: Waqar.

Author
Posts
#2370113

Hi there,

I saw this on Facebook, this without clear thoughts on how to achieve the result.

We have many Legacy Views displaying custom post types, we would like to have some way of making the 'best' stay at the top all the time...sticky.

This i saw:

"Apply an importance field to the CPT then in the view sort by importance descending then post date descending. Anything marked importance high will continue to appear first in the view"

I have tried a few ways however, do you have any advice on what I need to do ref this please?
Or any other way of doing this?

Many thanks.

#2370513
view-ordering-settings.png
sticky-custom-field.png

Hi,

Thank you for contacting us and I'd be happy to assist.

Based on my research, WordPress only supports the sticky post feature for the native/built-in "post" type and not for the custom post types.

In my tests, I was able to achieve the required functionality using a checkbox type custom field.

1. I added a checkbox type custom field "sticky" and set it to store "1" when checked and "0" when unchecked.
( example screenshot: sticky-custom-field.png )

2. After that, in the view's ordering settings, I selected this "sticky" custom field as the primary ordering criteria and the "post date"
as the secondary ordering criteria.
( example screenshot: view-ordering-settings.png )

The "descending" order for the "sticky" custom field will ensure that all the posts where this field is checked (and have "1" as a value) are shown first and the posts where this is unchecked (and have "0" as value) are followed after.

Note: If you already have the existing posts, you'll need to update them all once, so that the correct "0" or "1" custom field values can be updated with them.

I hope this helps and please let me know if you need any further assistance around this.

regards,
Waqar

#2370545

Hi there Waqar,

Thank you for your reply.

This all sounds great however the only worrying issue is:

Note: If you already have the existing posts, you'll need to update them all once, so that the correct "0" or "1" custom field values can be updated with them.

We have over 3000 custom post types, so to manually go in and update them all wouldn't be possible. Also these update regularly as they are added via a data feed. Is there no way of the 'sticky' function being not enabled to everything, only activated if we actually 'select' them?

OR -

Can we order a View based on category?
The custom posts we need are in a different taxonomy?

Thank you

#2370889

Thanks for writing back.

The way custom fields query filter works in WordPress, a post that has no custom field record for the field that is being used for the filtering is ignored. This is why it is important to set '0' for the non-sticky posts, otherwise, the view will simply not show them.

There are a couple of ways you can overcome this:

1. You can make sure that when the posts are added/updated through a data feed, the '0' value is saved for that custom field for non-sticky posts and the "1" value is saved for the sticky ones.

For the posts which have already been added, you can run a custom code once, so that all of them have a "0" value to start with. You'll find an example code and steps for this, in this forum reply:
https://toolset.com/forums/topic/view-query-filter-multiple-conditions-for-the-same-field/#post-1581057

OR

2. If you don't want to maintain a "0" value for the non-sticky posts, you can update the settings of the "sticky" custom field so that it doesn't store "0" when unchecked.

Next, instead of using 1 view, you'll need to use two views on the page. The first one will be for the sticky posts and the second one will be for the non-sticky posts. The two views can be designed in the same way so that on the front-end, the results from both those views, show as one.

OR

3. If you'd prefer to achieve this using taxonomy/category, then you'll have to use the two separate views approach too, because a view's results, can't be ordered by the presence of a taxonomy/category term or not.

The first view will show all posts where the 'sticky' taxonomy term is attached and the second view below it will show all posts where it isn't attached.

#2371579

HI there Waqar,

Thank you for this...appreciate your time.

So this option may be the best:

1. You can make sure that when the posts are added/updated through a data feed, the '0' value is saved for that custom field for non-sticky posts and the "1" value is saved for the sticky ones.

For the posts which have already been added, you can run a custom code once, so that all of them have a "0" value to start with. You'll find an example code and steps for this, in this forum reply:
https://toolset.com/forums/topic/view-query-filter-multiple-conditions-for-the-same-field/#post-1581057

Can I clarify.

1 - If we implement this all custom post types will default to '0'? We wont need to do this manually.

2 - We can then select which we want for 'sticky'?

3 - When the feed is updated they will always default to '0'?
The custom post types that will be 'sticky' are never touched by the feed, we manually add these...only manually added post types will ever be 'sticky'.

Finally, can you copy the exact code I would add please?
I don't know code so would use what you supply 🙂

Thank you.

#2371765

To answer these specific questions, I'll need to understand the exact setup of your website, especially the post addition/update through feeds.

Can you please share temporary admin login details, along with the details of the tool that you're using for the feed import?

Note: Your next reply will be private and though no changes will be made on your website, it is recommended to make a complete backup copy, before sharing the access details.

#2372715

Thank you for sharing these details.

I noticed that your website is using the "All Import" plugin for the feed import. The plugin offers a hook "after_xml_import" which can be used to execute a custom code after an import has been completed:
hidden link

You can use this hook to execute a custom function that cycles through all the published portfolio posts and sets the "sticky" custom field value to "0" if it is not already set:


function after_xml_import( $import_id, $import ) {

	$target_post_type = 'portfolio';
	$target_field_slug = 'sticky';
	$value_to_set = 0;

	$args = array(
		'post_type'        => $target_post_type,
		'posts_per_page'   => -1,
		'post_status'      => 'publish'
	);
	
	$posts_array = get_posts( $args );

	// loop through those posts 1 by 1
	foreach ($posts_array as $post) {
		// get current value of the field
		$current_value = get_post_meta( $post->ID, 'wpcf-'.$target_field_slug, true );

		// if it is empty set the provided default value
		if( empty($current_value) || !isset($current_value) ) {
			update_post_meta( $post->ID, 'wpcf-'.$target_field_slug, $value_to_set );
		}
	}

}
add_action( 'pmxi_after_xml_import', 'after_xml_import', 10, 2 );

The above code snippet can be included through either Toolset's custom code feature ( ref: https://toolset.com/documentation/adding-custom-code/using-toolset-to-add-custom-code/ ) or through the active theme's "functions.php" file.

The rest of the steps would be the same as shared in my first reply in this thread.
( ref: https://toolset.com/forums/topic/make-custom-post-types-sticky/#post-2370513 )

As a result, all imported posts will have the 'sticky' field set to '0' and you'll have the ability to set the selective manual ones to "1".

#2372763

Hey Waqar,

Wow! Thanks for that. My lack of understanding code and the fact that All Import is a new plugin meant I wouldn't know where to start ref looking for this. Thank you.

To to be clear:

I do this as you suggested earlier:

In my tests, I was able to achieve the required functionality using a checkbox type custom field.

1. I added a checkbox type custom field "sticky" and set it to store "1" when checked and "0" when unchecked.
( example screenshot: sticky-custom-field.png )

2. After that, in the view's ordering settings, I selected this "sticky" custom field as the primary ordering criteria and the "post date"
as the secondary ordering criteria.
( example screenshot: view-ordering-settings.png )

The "descending" order for the "sticky" custom field will ensure that all the posts where this field is checked (and have "1" as a value) are shown first and the posts where this is unchecked (and have "0" as value) are followed after.

Then add the exact code you supplied above to with Toolset Custom Code (which we already have used), or in the Code Snippets plugin which we already use?

So, when we run a refresh import every custom post type will have a '0' automatically added?
This important as it would need to happen on import.

Then any other custom post type we have added '1' too will remain untouched (as these do not come from the feed)
...and these will position at top of all grids?

If this is the case I'll sort this over the weekend.

#2373351

Hi there Waqar,

I have followed your steps in:
The rest of the steps would be the same as shared in my first reply in this thread.
( ref: https://toolset.com/forums/topic/make-custom-post-types-sticky/#post-2370513 )

Added the the code in Toolset Custom Code.

A ran the import for all French homes.

On the France page: hidden link
I have ticked only one custom post:
hidden link

However this home is still towards the bottom of page 3....not the top of page 1.

I also noticed at the bottom of your code, ID's so I also added the import ID's...this made no difference either:
add_action( 'pmxi_after_xml_import', 'after_xml_import', 10, 2, 38, 39, 37 );

Any thoughts what I'm doing wrong?

Thank you.

#2374139

Thanks for writing back.

I noticed that the '0' value was saved as expected for the portfolio post's "sticky" field, which confirms that the custom code after the import is running and performing its part, correctly.

The post order in the view was getting affected by the third-party plugin "Post Types Order". I've disabled the option "Auto Sort" from WP Admin -> Settings -> Post Types Order and the sticky post "Le Sud" is now showing as the first result.

#2374181

Hi there Waqar,

Many thanks for looking into this for me.

I did see for a short while (0) beside each property title on the Toolset grids. This now gone.

The sticky works great however disabling the option "Auto Sort" now means we can't reorder Posts at all...this has no effect.
Not ideal, is this what you would expect disabling this?

#2374321

The challenge is that the "Auto Sort" option from the "Post Types Order" plugin automatically changes the order by criteria for all WordPress queries (including the queries for the views) to 'menu_order'.

When this option will be checked, your order by settings from the view will be overridden too. You can get in touch with the "Post Types Order" plugin to see if they offer any hook/filter to disable this option for certain cases/queries.

#2374489

I see, its not a huge issue however what you've done essentially disables all manual sorting or 'posts'.

We may as well remove the plugin altogether as now, we need to order posts by date and time....so disabling 'auto sort' renders the plugin useless.

We'll have to decide which function has the greater priority, which of course isn't your issue 🙂

#2374501

Thank you for your understanding and glad I could help.

You're welcome to mark this ticket as resolved and start a new one for each new question or concern.

#2374507

My issue is resolved now. Thank you!