WordPress.org

Make WordPress Core

Opened 7 years ago

Closed 7 years ago

#7457 closed enhancement (fixed)

Sticky Posts

Reported by: ryan Owned by:
Milestone: 2.7 Priority: normal
Severity: normal Version:
Component: General Keywords: sticky posts blessed
Focuses: Cc:

Description

By popular demand, Sticky Posts.

Suggested design:

  • Have "Stick to front page" checkbox on the edit post page
  • If checked, add the ID of the post to a sticky_posts field in the options table
  • When performing a front page query, move sticky posts to the head of the results. If all sticky posts are not present in the results, do a separate query to fetch the missing ones. Do this only if is_home().
  • Provide is_sticky($post_id) for use by themes.

Attachments (2)

7457.diff (3.5 KB) - added by ryan 7 years ago.
First draft, incomplete
7457.2.diff (5.1 KB) - added by ryan 7 years ago.
Now with UI and one query to fetch the stickies

Download all attachments as: .zip

Change History (34)

comment:1 @ryan7 years ago

Should sticky posts count toward the posts per page limit?

comment:2 @technosailor7 years ago

+1

Would suggest sticky posts should also apply on is_archive(), is_category(), is_tag() and most importantly is_search()...

comment:3 @DD327 years ago

IMO, Yes, Sticky posts should count towards the limit - Still only want 10 per page even if theres a sticky

  • Should Stickies be shown on paged pages as well? Or mearly page 1.
  • Should sticky posts appear on the search results?

IMO, Sticky posts should only appear within their normal listings, So it should appear as sticky on front/archive/category/tag/etc pages, however if a sticky post was found in a search, it should float to the top as expected, But if its not found by the search, IMHO the sticky doesnt belong in that group of posts.

@ryan7 years ago

First draft, incomplete

comment:4 @ryan7 years ago

Here's a first, crude attempt. Stickies are presented only on the home page, stickies do not count toward the per page count, there is no UI, and phpdoc is incomplete.

comment:5 @ryan7 years ago

Stickies that are not in the query results for page 1 don't count toward the per page limit. If they were counted, we'd have to adjust all subsequent pages so that posts bumped off the first page to make room for stickies aren't orphaned.

Showing stickies on pages other than home means we have to check to see if the stickies would be part of the results if the query were unpaged.

Counting stickies towards the page limit and showing stickies on pages other than home could be cans of worms. Should we bother?

comment:6 @DD327 years ago

Counting stickies towards the page limit and showing stickies on pages other than home could be cans of worms. Should we bother?

I see what you mean..

Could the menu_order field be utilised to mark a post as a sticky? It'd also mean that the paging support should work as expected.

AFAIK, the menu_order field is not used by posts at all, Setting it to a >0 value for stickie would allow for the SQL ORDER BY to return Stickies first, followed by non-stickies (menu_order == 0), the SQL LIMIT would then continue working for paging.

The only real downside i can think of is an extra SQL Ordering, which could reduce performance, but i cant see it being any worse than an extra SQL to fetch any stickies. (Note: Theres no index on menu_order, it is however an int(11) though)

comment:7 @ryan7 years ago

We'd definitely need an index on menu_order for the query not to suck. We need an index on it anyway for the page query. We should only add menu_order to the query when there are stickies, so we might still want to store sticky posts in options. stick_post() would add it to options and set menu_order to 1. It's worth a try. Anyone want to try EXPLAINing the posts query with menu_order and different indexes (menu_order, post_date) and see how it performs?

comment:8 @ryan7 years ago

Adding menu_order to the sort is pretty slow. The query to fetch the sticky posts is a const query on a primary key. Very fast. Another alternative would be to UNION the regular post query and the sticky query. Don't know if its worth it though.

@ryan7 years ago

Now with UI and one query to fetch the stickies

comment:9 @ryan7 years ago

Ordering by menu_order DESC, post_date DESC results in filesort. I've tried adding different keys to get rid of it but haven't hit upon a combination that works yet. Using menu_order does make things cleaner, but incurring filesort isn't worth it.

comment:10 @ryan7 years ago

With the current patch, posts on page 2 that are marked as sticky will show at the top of page 1 and again in their original places on page 2. You'll see them twice as you page through. I'm trying to decide whether that's a feature or a limitation. I'm leaning toward feature. I like seeing them in their original place in the timeline. If this is deemed a feature, it is an advantage over the menu_order method.

comment:11 @DD327 years ago

Ordering by menu_order DESC, post_date DESC results in filesort.

Probably because ordering by post_date will result in a filesort regardless?

EXPLAIN SELECT * FROM `wp_posts` ORDER BY menu_order DESC , post_date DESC

id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra 
1	SIMPLE	wp_posts	ALL	NULL	NULL	NULL	NULL	196	Using filesort
EXPLAIN SELECT * FROM `wp_posts` ORDER BY post_date DESC

id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra 
1	SIMPLE	wp_posts	ALL	NULL	NULL	NULL	NULL	196	Using filesort

I cant find any form of index which helps the 2nd query let alone the first, I might be barking up the wrong tree though.

I'm leaning toward feature. I like seeing them in their original place in the timeline. If this is deemed a feature, it is an advantage over the menu_order method.

I guess that can be seen as a feature, It depends on what users of the functionality are using it for, They may only want the sticky to be shown as a sticky, Others would be using it to pin a post in place, yet still want it to show in the natural order of posts.

comment:12 @ryan7 years ago

SELECT SQL_CALC_FOUND_ROWS wp_trunk_posts.* FROM wp_trunk_posts WHERE 1=1 AND
 wp_trunk_posts.post_type = 'post' AND (wp_trunk_posts.post_status = 'publish') ORDER BY
 wp_trunk_posts.post_date DESC LIMIT 0, 10

I get "Using where" with that. Adding menu_order to the mix brings on filesort.

comment:13 @DD327 years ago

I get "Using where" with that. Adding menu_order to the mix brings on filesort.

Ah, I was getting filesort from { AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') ; So yes, You are right.

comment:14 @ryan7 years ago

Yeah, you get that if you are logged in. Would be nice to get rid of that, but at least regular users aren't hit with it.

comment:15 @DD327 years ago

Adding menu_order to the type_status_date key and ordering it the same as the query removes the need for a filesort:

EXPLAIN SELECT SQL_CALC_FOUND_ROWS wp_posts . * 
FROM wp_posts
WHERE 1 =1
AND wp_posts.post_type = 'post'
AND (
wp_posts.post_status = 'publish'
)
ORDER BY wp_posts.menu_order DESC , wp_posts.post_date DESC 
LIMIT 0 , 10

id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra 
1	SIMPLE	wp_posts	ref	type_status_date_order	type_status_date_order	124	const,const	49	Using where

Key:

ALTER TABLE `wp_posts` DROP INDEX `type_status_date` ,
ADD INDEX `type_status_date_order` ( `post_type` , `post_status` , `menu_order` , `post_date` , `ID` )

It appears that unless the order by keys are in the order index in the same order that they're used, MySQL cannot rely on the key for the sort.

comment:16 @ryan7 years ago

Changing post_status_date makes the non-menu_order query use filesort though. I think we'd need to keep type_status_date and add type_status_order_date.

comment:17 @ryan7 years ago

(In [8546]) Sticky Posts, firct cut. see #7457

comment:18 @ryan7 years ago

I committed what I had for folks to play with. I'll tidy up and attach my menu_order patch for comparison. Each approach has its merits. It's a toss up.

comment:19 @markjaquith7 years ago

At the least, this should require publish_post capabilities. You don't want contributors checking that box and then having their post be sticky when it is eventually published. There's a decent argument to be made that this should require the edit_others_posts capability, since this is more of an editorial decision.

comment:20 @ryan7 years ago

The checkbox is only shown if publish_posts, but we might need some checks on the POST side.

comment:21 @ryan7 years ago

edit_others_post sounds good, or maybe a new cap entirely.

comment:22 @markjaquith7 years ago

Adding new capabilities is problematic. We essentially have to marry the new capability to an old capability on upgrade, and it's not built for cap2role and cap2person lookup. I think promotion of a post to "sticky" status is similar enough to the scope of responsibility that comes with being able to edit other people's posts.

comment:23 @markjaquith7 years ago

(In [8576]) Give separate paragraphs to the private/sticky checkboxen (heh) and give them distinct IDs for plugin CSS-hiding purposes. see #7457

comment:24 @markjaquith7 years ago

(In [8577]) Use the edit_others_posts capability for controlling sticky checkbox display and usage. see #7457

comment:25 @jacobsantos7 years ago

  • Type changed from defect to enhancement

comment:26 @ryan7 years ago

(In [8637]) Add sticky_class() template tag. see #7457

comment:27 @ryan7 years ago

(In [8638]) Add post_class() template function for emitting standard classes for post div. see #7457

comment:28 @ryan7 years ago

(In [8639]) phpdoc fix up for post_class(). see #7457

comment:29 @ryan7 years ago

(In [8641]) Add more classes to post_class(). see #7457

comment:30 @ryan7 years ago

(In [8642]) Initialize classes array. see #7457

comment:31 @ryan7 years ago

(In [8643]) get_post_class() from mdawaffe. see #7457

comment:32 @ryan7 years ago

  • Resolution set to fixed
  • Status changed from new to closed

(In [8795]) Suppress query filters when called from get_posts(). fixes #7326 #7457 for 2.6

Note: See TracTickets for help on using tickets.