{"id":136622,"date":"2015-01-25T08:00:07","date_gmt":"2015-01-25T13:00:07","guid":{"rendered":"http:\/\/premium.wpmudev.org\/blog\/?p=136622"},"modified":"2022-02-11T14:49:52","modified_gmt":"2022-02-11T14:49:52","slug":"add-post-filters","status":"publish","type":"post","link":"https:\/\/wpmudev.com\/blog\/add-post-filters\/","title":{"rendered":"How to Add Post Filters to Your WordPress Site Easily"},"content":{"rendered":"<p>A frequent request I come across is the ability to let users filter, or sort, posts on the front-end of their website.<\/p>\n<p>Perhaps users\u00a0want to view posts alphabetically, or maybe see only those posts with thumbnails? This already makes sense for regular posts but can be even more meaningful in the case of products, photos or other content types.<\/p>\n<p>In today&#8217;s Weekend WordPress Project I&#8217;ll give you a quick rundown of how you can implement a feature like this in the Twenty Fifteen theme. Let&#8217;s get cracking!<\/p>\n<ul>\n<li><a href=\"#child-theme\">Creating A Child Theme<\/a><\/li>\n<li><a href=\"#controls\">Creating Controls<\/a><\/li>\n<li><a href=\"#query\">Modifying the Query<\/a><\/li>\n<li><a href=\"#smarter\">Smarter Forms<\/a><\/li>\n<li><a href=\"#behavior\">WordPress Behavior<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<h2 id=\"child-theme\">Creating A Child Theme<\/h2>\n<p>As always, you need a child theme. We have a <a href=\"https:\/\/wpmudev.com\/blog\/how-to-create-wordpress-child-theme\/\" target=\"_blank\">guide to child themes<\/a> right here on WPMU DEV, I recommend giving that a read if you are not familiar with child themes.<\/p>\n<h2 id=\"controls\">Creating Controls<\/h2>\n<p>Let&#8217;s add three controls: one for ordering the posts, one for setting the direction of sorting and one for showing only posts with thumbnails.<\/p>\n<p>The first step is to copy the parent theme&#8217;s <code>index.php<\/code> into our child theme.<\/p>\n<p>Open the <code>index.php<\/code> file in your child theme and paste the following HTML below the main container (which should be on line 20):<\/p>\n<div class=\"gist\" data-gist=\"e12c354bc6c9c95c497d\" data-gist-file=\"filters.html\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/e12c354bc6c9c95c497d.js?file=filters.html\">Loading gist e12c354bc6c9c95c497d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>And here&#8217;s what it looks like on the front-end:<\/p>\n<figure id=\"attachment_136624\" class=\"wp-caption aligncenter\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-136624\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2015\/01\/filters.png\" alt=\"Forms\" width=\"735\" height=\"484\" \/><figcaption class=\"wp-caption-text\">Not so pretty yet but our form is in the right place<\/figcaption><\/figure>\n<p>As you can see we are lacking a bit of styling. Let&#8217;s resolve that by adding some styles to\u00a0the stylesheet:<\/p>\n<div class=\"gist\" data-gist=\"e12c354bc6c9c95c497d\" data-gist-file=\"filter-styles.css\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/e12c354bc6c9c95c497d.js?file=filter-styles.css\">Loading gist e12c354bc6c9c95c497d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<figure id=\"attachment_136625\" class=\"wp-caption aligncenter\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"size-ratio-large wp-image-136625\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2015\/01\/styled-filter-700x449.png\" alt=\"Styled Filter\" width=\"700\" height=\"449\" \/><figcaption class=\"wp-caption-text\">More work could be done but it looks much nicer<\/figcaption><\/figure>\n<p>A reaction I frequently hear from\u00a0newcomers to programming is: &#8220;how did he know that these are the styles that will make it blend into the theme?&#8221;<\/p>\n<p>The solution is pretty simple: I cheat. I\u00a0use\u00a0the developer tools in\u00a0Chrome to\u00a0inspect the regular article elements. In this case, it let me see how the elements\u00a0get their box shadow and their margins and I simply applied these rules to my own element.<\/p>\n<h2 id=\"query\">Modifying the Query<\/h2>\n<p>Let&#8217;s select &#8220;order by title,&#8221; &#8220;ascending&#8221; and &#8220;posts with thumbnails&#8221; and submit the form. You should actually see a change without doing\u00a0anything to the code.<\/p>\n<p>To see why, let&#8217;s inspect the URL. It should be something like this:<\/p>\n<pre>http:\/\/yourdomain.com\/?orderby=post_title&amp;order=DESC&amp;thumbnail=only_thumbnailed\r\n<\/pre>\n<p>The tidbits of information can be recalled in our PHP scripts using the <code>$_GET<\/code> variable. WordPress already knows what the order and orderby parameters mean and it uses them in the default query. As a result, if we only need ordering and order direction we&#8217;re actually all done.<\/p>\n<p>That&#8217;s all great, but again, <em>how<\/em> did I know this? I could have used &#8220;order_by&#8221; as a parameter instead of &#8220;orderby.&#8221; In this case WordPress does not pick up on our intentions. I had a look at\u00a0the <a href=\"http:\/\/codex.wordpress.org\/Class_Reference\/WP_Query\" target=\"_blank\">WP_Query<\/a> documentation in the WordPress Codex\u00a0where there are a bunch of parameters, many of which can be used in URLs.<\/p>\n<p>Now, let&#8217;s implement our post thumbnail parameter. A post has a thumbnail if it has metadata with the key <code>_thumbnail_id<\/code> associated with it. We&#8217;ll need to modify our query to make sure this is taken into account. Let&#8217;s do this now with <code>query_posts()<\/code>.<\/p>\n<p>Paste the following code above the <code>get_header()<\/code> function at the top of the file:<\/p>\n<div class=\"gist\" data-gist=\"e12c354bc6c9c95c497d\" data-gist-file=\"query.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/e12c354bc6c9c95c497d.js?file=query.php\">Loading gist e12c354bc6c9c95c497d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>We merge the parameters of the original query with our own new parameter, which results in a different set of posts. Our form now works but it doesn&#8217;t remember our selections. Let&#8217;s fix that by rewriting our form and using some PHP.<\/p>\n<h2 id=\"smarter\">Smarter Forms<\/h2>\n<p>In addition to listing all the options of the order by selector we need a way to indicate which one is selected. If we were to do this without a loop it would look something like this:<\/p>\n<div class=\"gist\" data-gist=\"e12c354bc6c9c95c497d\" data-gist-file=\"incorrect-selected.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/e12c354bc6c9c95c497d.js?file=incorrect-selected.php\">Loading gist e12c354bc6c9c95c497d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>Do you understand any of that? I don&#8217;t blame you! Within each options we&#8217;re checking if the currently selected value is equal to the value of the option. If it is, we output the selected property. Let&#8217;s make this a lot cleaner with a loop:<\/p>\n<div class=\"gist\" data-gist=\"e12c354bc6c9c95c497d\" data-gist-file=\"orderby-loop.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/e12c354bc6c9c95c497d.js?file=orderby-loop.php\">Loading gist e12c354bc6c9c95c497d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>This is a bit longer but only because we have three options. This is a way better format for managing any kind of selection. Let&#8217;s extend this to the whole form:<\/p>\n<div class=\"gist\" data-gist=\"e12c354bc6c9c95c497d\" data-gist-file=\"form-loop.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/e12c354bc6c9c95c497d.js?file=form-loop.php\">Loading gist e12c354bc6c9c95c497d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>All done. The form should now remember our selections based on the <code>$_GET<\/code> variables in the URL.<\/p>\n<h2 id=\"behavior\">WordPress Behavior<\/h2>\n<p>Remember how I mentioned that I know to use &#8220;order&#8221; and &#8220;orderby&#8221; because I looked at the WP_Query documentation? This is good practice, but it may lead to unexpected results. Find the slug of a category you have, say this category is &#8220;wordpress.&#8221;<\/p>\n<p>Now use the following URL: http:\/\/yourwebsite.com\/?category_name=wordpress. You should see your category archive, listing all your WordPress posts. This is just fine, but we have two problems:<\/p>\n<p>If you have pretty permalinks turned on (which you should), the page has been redirected to a new URL, most probably http:\/\/yourwebsite.com\/category\/wordpress. Our filters will not be visible because the <code>archive.php<\/code> file handles this view, not <code>index.php<\/code>. In addition, our category name is not passed as a URL parameter so we will need to use some additional trickery to make our filters work.<\/p>\n<p>The shortcut way of making this work is to deliberately <em>not<\/em> use the same parameters WordPress uses. You could pass the category name using the <code>catname<\/code> parameter in the URL since WordPress will not pick up on this. You can then feed this to the query using the correct parameter name. Something like this:<\/p>\n<div class=\"gist\" data-gist=\"e12c354bc6c9c95c497d\" data-gist-file=\"category.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/e12c354bc6c9c95c497d.js?file=category.php\">Loading gist e12c354bc6c9c95c497d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>The alternative would be to use a function instead of outputting our form in <code>index.php<\/code> as is. You would need to detect the category from the WordPress query itself and display the current selection based on that.<\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>Adding your own filters is not all that difficult but requires a bit of fiddling. In our case you may want to make sure the pagination is removed when the order is set to random. It could be replaced by a &#8220;show more randomness&#8221; button, which simply reloads the page.<\/p>\n<p>Hopefully this article has given you the basics of how you can accomplish this for yourself and you will be able to build the filters you need.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Adding the ability to sort posts on your site is a neat way to help users sift through your content. Find out how to do it in today&#8217;s Weekend WordPress Project.<\/p>\n","protected":false},"author":344049,"featured_media":199568,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"blog_reading_time":"","wds_primary_category":0,"wds_primary_tutorials_categories":0,"footnotes":""},"categories":[263],"tags":[9798],"tutorials_categories":[],"class_list":["post-136622","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","tag-weekend-wordpress-projects"],"_links":{"self":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/136622","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/users\/344049"}],"replies":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/comments?post=136622"}],"version-history":[{"count":6,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/136622\/revisions"}],"predecessor-version":[{"id":205371,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/136622\/revisions\/205371"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media\/199568"}],"wp:attachment":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media?parent=136622"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/categories?post=136622"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tags?post=136622"},{"taxonomy":"tutorials_categories","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tutorials_categories?post=136622"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}