In this session we show how to change the sort order of specific category and tag archive pages using the WordPress pre_get_posts () filter which intercepts the query after it’s formed but before it is executed and gives the opportunity to change named query variables. We write a code to limit the scope of change to the main query to appropriate categories, tags and exclude all admin pages.
What I’m going to start off with is something that I tried to do but failed this morning and that is setting up the code for changing the display order for specific categories of posts. Now, what we’re working on here is this site, The Cheesemonger’s Table and we have set up categories for these various cheeses as cheeses by region. And the way it works right now is, just like every other WordPress site, the cheeses layout as the latest cheese that was added to the site to the earliest cheese that was added to the site, just like a blog post. But that’s not meaningful in this context. And so what we want to do is we want to change this organization to alphabetical by title.
The same thing is true with our tags. We’re using tags to distinguish between cow’s milk cheese, goat’s milk cheese and sheep’s milk cheese. And if you click on cow’s milk cheese and what we want to do is also take the cheeses and organize them by title rather than by when they were posted.
So that’s the task at hand and what we’re going to be using is the WordPress Pre Get Posts filter. Now what the Pre Get Posts filter does is it intercepts the query after it’s formed but before it’s executed. So for example, when we clicked on cow’s milk cheeses, when we clicked on this thing, a query was created that said get all of the posts that are in the tag “cow milk” or that are tagged with “cow milk”. And so it searched the database, searched through all the posts and extracted all the posts that are tagged “cow milk”. That was the query, all the posts with the tag “cow milk”.
What Pre Get Posts does is that it intercepts it after that query is formed but before it actually selects all the posts. And it gives you an opportunity to change named query variables. And so when we look at this, down here is an example of the wp query object which is where all these named query variables are. And query vars represents the query variables and so you have this long list of potential query variables that you can use. And in fact, there is more of them than this because you can use essentially, anything that’s inside of wp query. Let’s look at wp query for example. You can use any of the… essentially the tags inside of wp query to modify. And so because there are a bunch of tags in wp query that actually don’t exist or don’t show up here in this example of a query object. So any of the tags that show up under this class reference wp query are query variables that can be set.
Now when you use the Pre Get Posts filter, it is executed on every single loop on a given page. So if for example, we look at this page you know, I have 3 loops on this page. I have the main loop which gives me this live answers and this paragraph of text. I have a secondary loop which is the loop that is displaying these live answer teasers. And I have another secondary loop over here which is this live answer topics. This topic list is created with a secondary loop and were I to actually use Pre Get Posts filter on this, it would apply to all 3 of these loops.
Okay so what we need to do then is we need to make sure that we limit the scope of our definition so that it only applies to the specific condition that we’re working in. And that includes whether or not we’re looking an admin page or not because this Pre Get Posts filter also exists on our administrative pages. So in some cases, we want this… we may want this secondary loop only to apply to the main query. In some cases, we may want this Pre Get Posts filter to apply only to a specific secondary loop and so it’s important to be able to scope that.
And so we’re going to start off by writing some code and ultimately, our code is going to limit the scope of our change to the main query to appropriate categories to appropriate tags. And it’s going to exclude all admin pages. I mean, that is the way it is going to be ultimately but what we’ll do is we’ll do this iteratively.
So at first, what we’ll do is we’ll just set up the Pre Get Posts filter so that it organizes everything alphabetically. So we’ll just bring that bar… file here and we’ll say function list posts alphabetically. List posts alphabetically… cheese, okay. And we’re going to start off with a very simple thing.
Now this is a filter and because it’s a filter, we have to bring the content that we are filtering into the function. And so we do that by giving it a name. We’re going to call it query. You could call it anything you want. You could call it fishsticks if you want, as long as you’ve got a variable in here because the Pre Get Posts filter is going to grab the query and is going to put it in whatever variable name you put in here. We’ll go ahead and put in query but actually you know… yeah, we’ll go ahead and put in query but you can put anything in there. And this is a mistake I made this morning. I forgot to include a name for the query variable.
And so now what we’re going to do is scpe the change that we’re going to make to the query variable and we’re going to start off with a real simple scope and we’re going to use the if is archive conditional tag. If is archive will apply to all archives. And so that’s category, tag, archives. It’ll also apply to date archives and author archives. So this is not really the perfect solution to this but it is the simplest solution at first which is just to take if it’s an archive page then apply it.
Now… and we also want to make sure that it only applies to the main query so we’re going to use the new template tag is main query. This template tag is new in 3.4. Okay so if it’s the archive and if it is the main query then do this to it. And then what we’re going to do is specify the query variables and what we want to set them to because right now, the query variable for order by is order by date and the query variable for order is descending. And if we come over and take a look at our… come over and take a look at the… if we look at our order parameters for a second, it’s the order paramaters descending order or the order default descending and the order by defaults to date so that’s what those are right now. By default, the archive page orders by date in a descending order. We’re going to change this to be by title in an ascending order so that brings us back over to this. And we’re going to identify the first query variable and we need to reference the variable that we put here because we put the entire query into this variable called query. So now we’re going to use… make reference to that query and then the specific part of the query variable that we’re going to reference is query vars. And then query vars is the internal variable and then what we’re going to do is add the part of the associative array. And the part of the associative array is going to be order by and then we’re going to give it that a value, order by equals title.
So query here is this is a content of the query variable. Again, if this was fishsticks then this would be fishsticks. Query vars is part of… is one of the elements of this query variable. If we come over and take a look at that here, that represents this, the query vars. And then we’re looking at query vars and then order by and you can see order by doesn’t exist here but it is, in fact, part of this so we can still go ahead and use it. But that query vars value comes form this. This is an ordinary part of the query variable and it’s got the queried object, has query vars. It has tax query and then it’s got a bunch of other stuff in here as well and then it’s got a queried object. So there are a bunch of different things you can grab with this but we are grabbing the query vars. Query vars order by equals title and then we’re just going to say exactly the same thing except… instead of order by, it’s just going to be order and we’ll say ASC in all caps. So if it’s the archive and if it’s the main query then look at the query variables order by, title, and order ascending. And so that’s what’s it’s going to do. It’s going to replace those variables with these new values and otherwise, leave the query alone. That’s why you use the Pre Get Posts filter because all it does is select the specific part of the query and change it.
Okay and so then we’re going to just say add filter and Pre Get Posts and then the newer function. Now this is a special kind of filter and it does not require you to say, after this, return query. Now you could say return query because that’s what’s you’re used to doing with filters. Ordinarily, with filters, you say… when you add a filter, you’ll take this query variable. You will modify that query… you’ll take this value, whatever happens to be inside the filter. You’ll modify that value and then you will return the modified value. In the case of the Pre Get Posts filter, that’s not necessarily. It’s implicit. It automatically happens.
So we’ll go ahead and save this and we’ll upload it. And you can see right now you know, it’s not ordered alphabetically, right? Petit Blue, Chimay Bierre, Pleasant Ridge Reserve, Vella Dry Jack, Sierra Nevada Cream Cheese… this is all by cow, right? If we refresh this, now it’s all alphabetical. So it’s Aged Emmenthaler, Aged Gouda, Bayley Hazen, Beecher’s Reserve. It’s all alphabetical. And if we come over and take a look at our cheeses by region, the same thing is true. It’s laid out alphabetically. If we go to the Washington cheese, they are laid out alphabetically, okay?
So that seems like it’s doing what we want it to do and it seems that way until you have some kind of a system whereby you use a you know, a date archive or an author archive. Those kinds of archives, of course, do not wish to be modified that way. And so in fact, it turns our there are other things that are like that too in this. For example, Cheese of the Month Membership. Well, that’s a category. These are posts and so now what has happened is these have been organized alphabetically which actually is probably just fine under the circumstance because it’s… ultimately, you’ve got the dollar amount in there as well. And so you know, that might be okay but then you have gifts of cheese. Those are also going to be… oh isn’t that interesting? Gifts of cheese did not end up… I’m guessing that Cheesemonger’s Choice got selected as a… has a sticky post which is why it’s up at the top here rather than being down below. Let’s just look at that because that is an interesting question. No, it’s not. Cheesemonger’s Choice… oh, there’s the space in there which you know, as soon as you delete this space, that changes the title. If we update it now, that’s crazy because it looked like it was supposed to be that way. But if we change it now and go back to gifts of cheese, Cheesemonger’s Choice isn’t at the top anymore. It was at the top because it had a space in front of the title.
Okay so anyway, that’s not really… they don’t really want to do it that way. They want it for gifts of cheese. So we’re not going to use this if is archive. What we’re going to do then is we’re going to make this a little bit more specific. And we’re going to use the is category system and in fact, the other thing we want to do is we want to change the posts per page. Because right now, what’s happening is with these cheeses, because we have our system set up to display only 10 posts, it shows the 10 posts. But with cheeses in particular, we want to show absolutely every cheese at the same time. And so I’m going to do one more thing here and that is we’re going to add this query vars and we’re going to change the posts per page to -1. And when it says… when we say -1, that means it’s going to show all of the posts that qualify for this.
Now the other thing we’re going to do here is we’re going to make sure that we’re not on an admin page. So… and is admin except we don’t want is admin so we have to wrap is admin inside of a set of parentheses and then put the not in front of it or the exclamation point. So if it’s an archive, if it’s the main query but if it’s not admin, now this is going to run.
Now we’re not going to use is archive. We’re going to actually use… we only want this to apply first to category archive pages so if is category. And then we only want it to apply to a specific group of categories. Now that group of categories is all of the regions. So if we come back over here and look ato ur categories, we don’t want this to apply to the cheese of the month. We don’t want it to apply to gifts of cheese or uncategorized for that matter. We only want this to apply to the cheese by region so we need all of their ids. So if you hover over cheeses by region and then look down that lower right hand corner, you can see down here, if you look down here you know, this is category id 39. This is 38. This is 27. This is 48. So it’s all those different ones. Well, I figured this out in advance and so I’m just going to paste that in the appropriate place. So iff is category and then all of the category ids so if is category array 12, 14, 15, 16, 17, 18 so on and so forth. These are all the categories that we want this to apply to and we don’t want it to apply to any other categories. So if it’s in one of those categories, if it’s the main query and if it’s not admin then follow this system.
So we’ll go ahead and save the document, upload the document and now let’s take a look at it. So gifts of cheese is now no longer going to be laid out alphabetically. Now gifts of cheese is laid out when it was placed. If we go to cow’s cheese, this is no longer laid out alphabetically. But if we go to France, it is laid out alphabetically. Not only is it laid out alphabetically but you can see way more than 10 cheeses that show up because we have… we’ve said show every cheese in this category of France. Same thing is true here with the types of cheese. Actually, cheese by region, this actually has every single cheese they’ve got on the site because cheese by region is the parent category. And so they’re all organized alphabetically and keep on scrolling down, you can see there’s lots more than just 10 here, right?
Okay so that works just fine except that we also want to do this to types of cheeses. We want to show all the cow’s milk cheeses. We don’t want to have a previous entries thing here and we want them to be organized alphabetically. So the next thing we have to do with that then is to add the tags into that. So if is category and what we’re going to do next is select this whole thing. If is category and put it in parenthesis and then we’re going to add an or, the logical operator or. So if it’s in category array or is tag… now the funny thing about tag is you can’t put a tag id number in there. I don’t know why but you can’t. So what we’re going to do is say array is tag and instead of parenthesis… and then we’re just going to put the tag slugs in so cow milk goat and sheep.
Okay so now what happens here is if it’s either the category or a tag and it’s either one of these categories or one of these tags and if it’s the main query and if it is not admin then do this to it. Oay so now we come back over here and hit save the document. We’ll upload it and we’ll test it. Here we are, cow’s milk… now we have cow’s milk organized alphabetically and we can scroll all the way down here and see that it just keeps on going. We don’t stop showing cow’s milk cheeses just because we’ve got an arbitrary number which shows every single one of the posts in that. But if we go to… if we go back to cheeses by region you know, it works just like that. If we go to France, it continues to work just fine. If we go to Washington state, my hometown, all of the cheeses in Washington show up there and they’re all organized alphabetically.
Okay so that’s what we were trying to do. We were trying to change the query for specific categories and specific tags so that it would display you know, the posts in a different way than it displays by default. And we did that with the Pre Get Posts filter and fairly simple substitute of the query.