{"id":153175,"date":"2016-03-28T11:00:33","date_gmt":"2016-03-28T15:00:33","guid":{"rendered":"http:\/\/premium.wpmudev.org\/blog\/?p=153175"},"modified":"2022-02-07T08:35:32","modified_gmt":"2022-02-07T08:35:32","slug":"building-customized-urls-wordpress","status":"publish","type":"post","link":"https:\/\/wpmudev.com\/blog\/building-customized-urls-wordpress\/","title":{"rendered":"Building Customized URLs in WordPress: Permalinks, Query Vars and URL Rewriting"},"content":{"rendered":"<p>The Rewrite API for WordPress is an important feature that you probably don\u2019t read much about, yet you\u2019re no doubt using without even realizing it. The API provides the functionality for creating your own unique links \u2013 permalinks \u2013 for your website.<\/p>\n<p>In this tutorial, I\u2019ll explain permalinks in-depth \u2013 what they are, why they are permanent, their possible structures, and how you can rewrite them in a form that is intelligible for both humans and machines. I\u2019ll also explain some key concepts behind permalinks in WordPress, first looking at how to add variables to non-optimized URLs and how to use these variables and their values to query your database. Later, we\u2019ll explore URL rewriting and how to build the best structure for pretty permalinks.<\/p>\n<p>What we&#8217;ll cover in this article:<\/p>\n<ul>\n<li><a href=\"#permalinks-and-url-rewriting\">What Are Permalinks? What is URL Rewriting?<\/a><\/li>\n<li><a href=\"#query-vars-and-query-strings\">URLs in WordPress: Query Vars and Query Strings<\/a><\/li>\n<li><a href=\"#public-and-private-query-vars\">Public and Private Query Vars<\/a><\/li>\n<li><a href=\"#custom-query-vars\">Custom Query Vars<\/a><\/li>\n<li><a href=\"#wp-query-class\">WP_Query Class<\/a><\/li>\n<li><a href=\"#custom-field-queries\">Custom Field (Meta) Queries<\/a><\/li>\n<li><a href=\"#listing-posts-by-custom-fields\">Listing Posts by Custom Fields<\/a><\/li>\n<li><a href=\"#pretty-permalinks\">Pretty Permalinks<\/a><\/li>\n<li><a href=\"#adding-rewrite-tags\">Adding Rewrite Tags<\/a><\/li>\n<li><a href=\"#the-query-monitor-plugin\">The Query Monitor plugin<\/a><\/li>\n<\/ul>\n<h2 id=\"permalinks-and-url-rewriting\">What Are Permalinks? What is URL Rewriting?<\/h2>\n<p>URLs are the vehicle used to send HTTP GET requests over the web. More precisely, the GET method submits <code>key=value<\/code> pairs within a URL to get a response from a specified resource (read more about this topic at\u00a0<a href=\"http:\/\/www.w3schools.com\/tags\/ref_httpmethods.asp\" target=\"_blank\">W3Schools<\/a>).<\/p>\n<p>Take the following URL:<\/p>\n<p><em>http:\/\/example.com\/?p=123<\/em><\/p>\n<p>The question mark splits this URL into two parts. The first part is the domain name, the second part is the query string, which is a set of query variables and values determining the resource requested by the user. The query string identifies the resource, but it doesn&#8217;t tell us anything about its contents. We can say that it&#8217;s not semantically meaningful for humans and machines.<\/p>\n<p>Thanks to the Rewrite API, we can translate non-semantic URLs into their <a href=\"https:\/\/en.wikipedia.org\/wiki\/Semantic_URL\" target=\"_blank\">semantic equivalent<\/a> with an operation of URL rewriting. A rewrite rule would translate the preceding URL into the following structure:<\/p>\n<p><em>http:\/\/example.com\/category\/post-title\/<\/em><\/p>\n<p>With the category and post title within the URL, this structure describes more precisely the resource content for both humans and search engines, resulting in a usable, accessible and SEO-friendly URL. It can be bookmarked, shared and stored in a number of ways and it should never change in the long term so that the linked resource could be permanently targeted. This is the reason we call them permalinks.<\/p>\n<h2 id=\"query-vars-and-query-strings\">URLs in WordPress: Query Vars and Query Strings<\/h2>\n<p>We can ask WordPress to retrieve almost anything from a site&#8217;s database. Generally, you query for posts in a specified category, or labeled with a precise tag, or published during a specific period of time. When the user submits a URL, WordPress automatically handles the request and, according to the <a href=\"https:\/\/developer.wordpress.org\/themes\/basics\/template-hierarchy\/\" target=\"_blank\">template hierarchy<\/a> rules, shows the results in a single page or within an archive.<\/p>\n<p>In the first part of this post,\u00a0I&#8217;ll show you how to make use of built-in query string variables and how to register our own custom variables, we&#8217;ll instruct WordPress to get these variables from the URLs and use them to query the database, and then we will output the resulting list of posts into a custom archive page.<\/p>\n<p>In the last part of this post, I&#8217;ll show you the tools WordPress provides us to translate these semantically unintelligible query strings into meaningful, accessible, usable and SEO-optimized permalinks. I&#8217;ll also give you an overview of default and custom permalink structures provided by WordPress, and finally we&#8217;ll build custom pretty permalinks using the Rewrite API.<\/p>\n<h2 id=\"public-and-private-query-vars\">Public and Private Query Vars<\/h2>\n<p>Query vars are the keys that define any SQL query WordPress runs against the database. These variables come in two main categories, depending on the way we can use them. <strong>Private query vars<\/strong> can be only set within a script, while <strong>public query vars<\/strong> can be sent to WordPress with a query string.<\/p>\n<p>Besides public and private variables, WordPress allows us to register our own <strong>custom query vars<\/strong>.<\/p>\n<p>In a URL, public query variables are the keys following the question mark (the query string), and are visible when we&#8217;ve not enabled Pretty permalinks on the\u00a0<a href=\"https:\/\/wordpress.org\/support\/article\/settings-permalinks-screen\/\" target=\"_blank\">Settings \u2192 Permalinks<\/a> admin page. The following URL is an example:<\/p>\n<p><em>example.com\/?author_name=carlodaniele<\/em><\/p>\n<p><code>author_name<\/code> is a public query var telling WordPress that the user is looking for all posts by the user\u00a0<code>carlodaniele<\/code>. We can add a number of public query vars to the query string, as we do in the following URL:<\/p>\n<p><em>example.com\/?author_name=carlodaniele&amp;tag=toolbar<\/em><\/p>\n<p>Now, WordPress will get all posts by <code>carlodaniele<\/code> and tagged as <code>toolbar<\/code>. And we can do even more. The next query string is a combination of a custom post type and a <em>taxonomy-name=taxonomy-term<\/em> pair.<\/p>\n<p><em>example.com\/?post_type=food&amp;food-family=greens<\/em><\/p>\n<p>Unlike public variables, private query vars can be only used within a script. For this reason, I won&#8217;t explore them in this post (you can read more <a href=\"https:\/\/codex.wordpress.org\/WordPress_Query_Vars\" target=\"_blank\">in the WordPress Codex<\/a>). Here, I will simply point out that the following URL won&#8217;t give us the expected result:<\/p>\n<p><em>example.com\/?author__in=2,4,6 <\/em><\/p>\n<p>Here <code>author__in<\/code> is a private query var, and WordPress won&#8217;t show the posts by the specified authors.<\/p>\n<p>Most\u00a0times, thanks to public query vars, we don&#8217;t need to write code to manage a\u00a0user&#8217;s requests, we just need to build the right query strings and WordPress will do the rest.<\/p>\n<p>Now, have a look at the following list of public vars:<\/p>\n<div class=\"gist\" data-gist=\"eb34d6c85bbf95f31839f7a98c1d0951\" data-gist-file=\"public_query_vars.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/eb34d6c85bbf95f31839f7a98c1d0951.js?file=public_query_vars.php\">Loading gist eb34d6c85bbf95f31839f7a98c1d0951<\/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 can retrieve posts by type, author, category, tag, taxonomy, year, month, day, and so on. We have a query var for almost any kind of query. What lacks here, though, is the possibility to build queries based on custom fields (we call them <a href=\"https:\/\/developer.wordpress.org\/reference\/classes\/wp_meta_query\/\" target=\"_blank\">meta queries<\/a>). In fact, WordPress provides the <code>meta_key<\/code> and <code>meta_value<\/code> query vars, but they belong to the private group of variables, so they&#8217;re not available for URL requests, and should be only used in scripts. So, how can we ask for meta queries from URL query strings?<\/p>\n<p>The first step is to register new query vars.<\/p>\n<h2 id=\"custom-query-vars\">Custom Query Vars<\/h2>\n<p>Once registered, these variables can take place in a query string just like any other public query variable. The following function shows us how to add them to the list:<\/p>\n<div class=\"gist\" data-gist=\"b34dfcdb0300b70a8efa450a429c1347\" data-gist-file=\"add-query-vars-php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/b34dfcdb0300b70a8efa450a429c1347.js?file=add-query-vars-php\">Loading gist b34dfcdb0300b70a8efa450a429c1347<\/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 <code>query_vars<\/code> <a href=\"https:\/\/developer.wordpress.org\/reference\/hooks\/query_vars\/\" target=\"_blank\">filter<\/a> allows us to add, remove or edit existing variables before the query runs. Here we&#8217;ve just added two custom variables and, from now on, we can get their values thanks to the <code>get_query_var()<\/code> <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/get_query_var\/\" target=\"_blank\">function<\/a>:<\/p>\n<div class=\"gist\" data-gist=\"31e1b1c5e3d55bffbfb5bf8ef56c8a2a\" data-gist-file=\"get_query_var\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/31e1b1c5e3d55bffbfb5bf8ef56c8a2a.js?file=get_query_var\">Loading gist 31e1b1c5e3d55bffbfb5bf8ef56c8a2a<\/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>Now the query var values are available to build a custom query.<\/p>\n<h2 id=\"wp-query-class\">WP_Query Class<\/h2>\n<p>When the user asks for a specific resource, being it a single page, a search result or a list of posts, WordPress instantiates a new <code>WP_Query<\/code> object, whose methods allow us to manipulate the actual SQL query before its execution.<\/p>\n<p>I will assume you&#8217;re familiar with the <code>WP_Query<\/code> class. If not, before reading over this post take the time to check our <a href=\"https:\/\/wpmudev.com\/blog\/mastering-wp-query\/\" target=\"_blank\">In-depth Guide to Conquering WP_Query<\/a>.<\/p>\n<h2 id=\"custom-field-queries\">Custom Field (Meta) Queries<\/h2>\n<p>We have got a bunch of parameters that allow us to set a <a href=\"https:\/\/developer.wordpress.org\/reference\/classes\/wp_meta_query\/#accepted-arguments\" target=\"_blank\">custom field query<\/a>, like the <code>meta_query<\/code> argument, which is a multi-dimentional array of single meta queries with the following keys:<\/p>\n<ul>\n<li>key (<em>string<\/em>) &#8211; a custom field key<\/li>\n<li>value (<em>string|array<\/em>) &#8211; custom field value<\/li>\n<li>type (<em>string<\/em>) &#8211; custom field type<\/li>\n<li>compare (<em>string<\/em>) &#8211; a comparison operator<\/li>\n<\/ul>\n<p>As an example, we could set the following <code>meta_query<\/code> argument:<\/p>\n<div class=\"gist\" data-gist=\"9e23a51816cc03eba9db89d4a4ee8add\" data-gist-file=\"meta-query-array\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/9e23a51816cc03eba9db89d4a4ee8add.js?file=meta-query-array\">Loading gist 9e23a51816cc03eba9db89d4a4ee8add<\/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><code>'relation'<\/code> is an optional element setting the logic relation between single queries (defaults to <code>'AND'<\/code>).<\/p>\n<p>Outside the WordPress Loop (i.e. in a plugin file), we can pass the array to the <code>set<\/code> method of the <code>$query<\/code> object as follows:<\/p>\n<div class=\"gist\" data-gist=\"ba0050977cd2b36a9daab9c045d89080\" data-gist-file=\"query-set\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/ba0050977cd2b36a9daab9c045d89080.js?file=query-set\">Loading gist ba0050977cd2b36a9daab9c045d89080<\/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 <code>set<\/code> <a href=\"https:\/\/developer.wordpress.org\/reference\/classes\/wp_query\/#methods\" target=\"_blank\">method<\/a> keeps two arguments: the query variable name and its value.<\/p>\n<p>To affect the query, we would change it after the query creation, but before its execution. To accomplish this task, we&#8217;ll hook a callback function to the <code>pre_get_posts<\/code> <a href=\"https:\/\/developer.wordpress.org\/reference\/hooks\/pre_get_posts\/\" target=\"_blank\">action<\/a>.<\/p>\n<p>The following example shows how all this works:<\/p>\n<div class=\"gist\" data-gist=\"5e3da325e66c63733919edd5ecd8677c\" data-gist-file=\"build-custom-query.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/5e3da325e66c63733919edd5ecd8677c.js?file=build-custom-query.php\">Loading gist 5e3da325e66c63733919edd5ecd8677c<\/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>It&#8217;s important to note that the <code>$query<\/code> object is passed to the function by reference, not by value. This means that any changes to the <code>$query<\/code> object affects directly the original query, not just an instance of query. As a consequence, it&#8217;s a good practice to be sure that we&#8217;re editing just the main query (<code>! $query-&gt;is_main_query()<\/code>), and the changes are not affecting admin queries (<code>is_admin()<\/code>). When needed, we could check other conditions to be sure to change the main query exclusively in specific pages (i.e. <code>is_post_type_archive()<\/code>).<\/p>\n<p>Now, let&#8217;s put together all that we&#8217;ve been talking about so far in a working example.<\/p>\n<h2 id=\"listing-posts-by-custom-fields\">Listing Posts by Custom Fields<\/h2>\n<p>Say you want to build a book catalogue with WordPress. With this goal, you may register a custom post type named <code>book<\/code> adding several custom fields, like <code>author_name<\/code>, <code>author_surname<\/code>, <code>publisher<\/code>, and so on. And say you want to provide site users with links to archive pages by <code>author_surname<\/code>.<\/p>\n<p>Now we know what to do. First, we have to register a query var naming it <code>book-author<\/code>:<\/p>\n<div class=\"gist\" data-gist=\"1cd370a7d74ac154b8ae63c9a452d56d\" data-gist-file=\"register-book-author-query-var.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/1cd370a7d74ac154b8ae63c9a452d56d.js?file=register-book-author-query-var.php\">Loading gist 1cd370a7d74ac154b8ae63c9a452d56d<\/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>Note that the custom query variable has been named <code>book-author<\/code> and not <code>author<\/code>, which is a reserved term for post authors (view the full list of reserved terms in <a href=\"https:\/\/codex.wordpress.org\/Reserved_Terms\" target=\"_blank\">the Codex<\/a>). Now WordPress is aware of the query var, and we can get its value from a URL thanks to the <code>get_query_var<\/code> function.<\/p>\n<p>Now consider the following function hooked to <code>pre_get_posts<\/code>:<\/p>\n<div class=\"gist\" data-gist=\"c1ed24c612ccb2f0977011c2193e1ca4\" data-gist-file=\"custom-book-author-query.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/c1ed24c612ccb2f0977011c2193e1ca4.js?file=custom-book-author-query.php\">Loading gist c1ed24c612ccb2f0977011c2193e1ca4<\/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><code>get_query_var()<\/code> gets the value of <code>'book-author'<\/code>. If available, this value is pushed into the <code>$meta_query<\/code> array.<\/p>\n<p>We&#8217;ve set a value for the <code>'relation'<\/code> element, too, just in case we set more than one meta query.<\/p>\n<p>Finally, the <code>set<\/code> method passes the array of parameters to the <code>$query<\/code> object, changing the query before its execution.<\/p>\n<p>Now you can send a URL like the following:<\/p>\n<p><em>http:\/\/example.com\/?post_type=book&amp;book-author=Rowling<\/em><\/p>\n<p>And you&#8217;ll get all books in your archive where the custom field <code>author_surname<\/code> is Rowling.<\/p>\n<p>With a good understanding of <code>WP_Query<\/code> object and query vars, we can get anything from the database just sending the proper URLs. It&#8217;s time to rewrite these URLs into usable, accessible and SEO-friendly structures.<\/p>\n<h2 id=\"pretty-permalinks\">Pretty Permalinks<\/h2>\n<p>WordPress provides three <a href=\"https:\/\/wordpress.org\/support\/article\/using-permalinks\/\" target=\"_blank\">permalink structures<\/a>:<\/p>\n<ul>\n<li>Ugly permalinks<\/li>\n<li>Pretty permalinks<\/li>\n<li>PATHINFO permalinks (index.php appears in the URL)<\/li>\n<\/ul>\n<p>By default, WordPress uses the ugly permalink structure. (i.e. <em>http:\/\/example.com\/?post_type=book<\/em> or <em>http:\/\/example.com\/?p=123<\/em>). But we know how important a pretty permalink structure is (i.e. <em>http:\/\/example.com\/book\/harry-potter-and-the-chamber-of-secrets\/<\/em>), so go to the\u00a0<strong><a href=\"https:\/\/wordpress.org\/support\/article\/settings-permalinks-screen\/\" target=\"_blank\">Settings &gt; Permalinks<\/a><\/strong> admin page of your install and set your favourite structure.<\/p>\n<p>We can check one of the available options, or set a custom structure where we can provide one or more <a href=\"https:\/\/wordpress.org\/support\/article\/using-permalinks\/#choosing-your-permalink-structure-1\" target=\"_blank\">structure tags<\/a>. These tags are keywords we can add to permalinks to give them a specific meaning. As an example, <code>%year%<\/code> would inform the user about the year of publication of a post.<\/p>\n<p>WordPress provides 10 default structure tags, but we can add any number of custom tags, one for each custom query variable we&#8217;ve previously registered.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption aligncenter\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/03\/custom_structure.png\" alt=\"Custom permalink structure\" width=\"735\" height=\"57\" \/><figcaption class=\"wp-caption-text\">With this structure enabled, the post name will be preceded by the year of publication.<\/figcaption><\/figure>\n<\/div>\n<p>That being said, our final task is to register a custom structure tag and instruct WordPress on how to use it.<\/p>\n<h2 id=\"adding-rewrite-tags\">Adding Rewrite Tags<\/h2>\n<p>Let&#8217;s hook the following function to the <code>init<\/code> action:<\/p>\n<div class=\"gist\" data-gist=\"4c4ea491486ebaca8d9502b847549758\" data-gist-file=\"add-rewrite-tag.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/4c4ea491486ebaca8d9502b847549758.js?file=add-rewrite-tag.php\">Loading gist 4c4ea491486ebaca8d9502b847549758<\/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 <code>add_rewrite_tag<\/code> <a href=\"https:\/\/codex.wordpress.org\/Rewrite_API\/add_rewrite_tag\" target=\"_blank\">function<\/a>, registers a new structure tag. The function keeps three arguments: the tag name, a regex to match the tag name, an optional query (not set here).<\/p>\n<p>Now WordPress is aware of the tag. We just need to register the rewrite rule that tells WordPress how to make use of it. Here is the code:<\/p>\n<div class=\"gist\" data-gist=\"f364d707472739bdf61b9ad7f0d61707\" data-gist-file=\"add-rewrite-rule.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/f364d707472739bdf61b9ad7f0d61707.js?file=add-rewrite-rule.php\">Loading gist f364d707472739bdf61b9ad7f0d61707<\/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 <code>add_rewrite_rule()<\/code> <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/add_rewrite_rule\/\" target=\"_blank\">function<\/a> will do the magic here:<\/p>\n<ul>\n<li>The first argument is a regular expression to match against the requested URL;<\/li>\n<li>The second argument is the URL to fetch when the regex is matched; and<\/li>\n<li>The last argument is a string whose value can be either <code>'top'<\/code> or <code>'bottom'<\/code> (<code>'top'<\/code> will take precedence over existing rules).<\/li>\n<\/ul>\n<p>Note that when we register a custom post type, we have to call the <code>flush_rewrite_rules()<\/code> on plugin activation, otherwise the new rewrite rules won&#8217;t work (read more in <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/register_post_type\/#flushing-rewrite-on-activation\" target=\"_blank\">the Codex<\/a>)<\/p>\n<p>Now a URL like the following:<\/p>\n<p><em>http:\/\/example.com\/?post_type=book&amp;book-author=Tolkien<\/em><\/p>\n<p>would be rewritten in the following pretty permalink:<\/p>\n<p><em>http:\/\/example.com\/book\/book-author\/Tolkien\/<\/em><\/p>\n<p><em>Note: Always save Permalink settings when you add or edit rewrite tags and rules, even if you did not change the permalink structure, otherwise tags and rules won&#8217;t take effect.<\/em><\/p>\n<h2 id=\"the-query-monitor-plugin\">The Query Monitor Plugin<\/h2>\n<p>A great developer tool to check the query vars is a free plugin called\u00a0<a href=\"https:\/\/wordpress.org\/plugins\/query-monitor\/\" target=\"_blank\">Query Monitor<\/a>. This plugin shows matched rewrite rules and query strings, query vars, database queries, hooks and much more. It&#8217;s definitely worth a look.<\/p>\n<div  class=\"wpdui-pic-regular  \">\n<figure class=\"wp-caption aligncenter\" data-caption=\"true\"><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/03\/query_monitor.png\" alt=\"Query Monitor\" width=\"666\" height=\"539\" \/><figcaption class=\"wp-caption-text\">Query Monitor adds a menu in WordPress Toolbar<\/figcaption><\/figure>\n<\/div>\n<h2>Wrapping Up<\/h2>\n<p>In this post we looked at how to query the WordPress database, passing values from URL query strings using public and custom query variables. We also explored permalinks with a focus on custom structures. Finally, we added new rewrite tags and rules, and built user and SEO-friendly URLs.<\/p>\n<p>I hope you&#8217;ve found this tutorial helpful and you can now customize your own URL structure to suit your needs.<\/p>\n<p><strong>Have you dealt with permalinks in WordPress? Share your experiences, examples and questions in the comments below.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Rewrite API for WordPress is an important feature that you probably don\u2019t read much about, but you\u2019re no doubt using without even realizing it. In this post, we&#8217;ll take a look at how to build highly customized permalinks for your website.<\/p>\n","protected":false},"author":387958,"featured_media":153239,"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":[557],"tags":[10045,245],"tutorials_categories":[],"class_list":["post-153175","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","tag-customization","tag-permalinks"],"_links":{"self":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/153175","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\/387958"}],"replies":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/comments?post=153175"}],"version-history":[{"count":45,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/153175\/revisions"}],"predecessor-version":[{"id":206226,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/153175\/revisions\/206226"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media\/153239"}],"wp:attachment":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media?parent=153175"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/categories?post=153175"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tags?post=153175"},{"taxonomy":"tutorials_categories","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tutorials_categories?post=153175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}