In-Depth Look at WordPress Permalinks and URL Rewriting
- Category : WordPress
- Posted on : Apr 04, 2018
- Views : 1,557
- By : Kapueo I.
In today’s post we are going to take an in-depth look at WordPress permalinks and URL rewriting. According to a 1999 post by Jacob Nielsen, a usable website requires:
- a domain name that is easy to remember and easy to spell
- short URLs
- easy-to-type URLs
- URLs that visualize the site structure
- URLs that are “hackable” to allow users to move to higher levels of the information architecture by hacking off the end of the URL
- persistent URLs that don’t change
A URL should never change, as it can be stored and shared in many ways. That’s the reason why we call them permalinks. Furthermore, a URL should be semantic, in the sense of being immediately and intuitively meaningful to non-expert users (more about Semantic URLs on Wikipedia).
In a static web, a URL identifies a resource by its name, as shown in the following example:
http://example.com/path/to/resource/wordpress-permalinks.html
In order to have well structured URLs we just need a well-structured file system and properly named resources.
But the web is dynamic, and we are used to manage websites using database driven CMSs, and URLs will contain a number parameters whose values determine the query to be run against the database. Consider the following example:
http://example.com/?key1=val1&key2=val2
In this URL you’ll notice a separator (the question mark), and a set of key/value pairs (separated by ampersand) which constitute the query string. The URL does not meet usability and accessibility requirements as specified above, and should be converted into a more meaningful and SEO-friendly permalink.
The way these »ugly» URLs are converted into optimized permalinks depends on your web server. If you are an Apache user, you’ll be required to add a set of rewrite directives into the root folder’s .htaccess file. If you are a Nginx user, you’d add a try_files directive into the main configuration file (read more about this topic on Nginx blog).
But don’t worry! Most of the times you won’t be required to configure line by line the web server, because the most popular CMSs allow users to manage the permalink structure easily and securely from the back end. And WordPress is no exception. Admin users will be able to set their custom rewrite rules quickly and easily from the admin panel. Advanced users and developers could get even more thanks to the WordPress Rewrite API, which provides functions and hooks that bring permalink customization to a higher level.
URLs determine the query to be run against the database. For this reason, our first step will be a short introduction to WordPress queries.
- An Overview of WordPress Queries
- Ugly WordPress Permalinks and Query Vars
- Pretty WordPress Permalinks and Structure Tags
- Custom Query Vars and Advanced Permalink Customization
- Let’s Make Them Pretty
An Overview of WordPress Queries
With the specific purpose of building the query, execute it and store results from the database, WordPress provides the WP_Query
class. Thanks to this class we don’t need to care about the query because WP_Query
will automatically handle the request, build the query and execute it. Then, according to the template hierarchy, WordPress will return the requested resource.
Out the box WordPress admits requests for single posts, pages, post types as well as for a number of archives ordered by category, tag, date, author, and more. Moreover, if default functionalities wouldn’t be enough, developers can build custom queries by creating new instances of the WP_Query
class (the query object) or passing specific parameters to an existing instance of the query before its execution.
The query parameters are named query variables and are divided into three groups.
Public query vars: these variables are public in the sense that they are available to be used in public requests (i.e. the URLs).
Thanks to these variables, we can ask for posts by authors:
?author=12 ?author_name=mickey
By category or tag:
?cat=4,5,6 ?category_name=CMS ?tag=wordpress
By date and time:
?monthnum=201601 ?year=2015 ?w=13 ?day=31
By post or page:
?p=123 ?name=hello-world ?page_id=234
And much more.
Private query variables: these variables are not meant to be added to URL query strings. They can be used to affect queries just within a script (a plugin or a theme’s functions.php file).
The following query string would not return the expected result:
?meta_key=city&meta_value=london
meta_key
and meta_value
are private query variables not to be defined in query strings. They should be passed to an instance of the query object, as I will show you later.
See the full list of public and private query variables in the Codex.
Custom query variables: these user-defined variables can be passed via URL query strings much like public query vars. The main difference between public and custom variables is that WordPress won’t handle custom vars on its own, and we should get their values from a plugin to customize queries.
That being said, let’s get back to permalinks.
Ugly WordPress Permalinks and Query Vars
Ugly Permalinks show up the query string, i.e. the part of the URL containing a set of query variables (the query string) that will determine the returned resource.
As an example, consider the following URLs:
http://example.com/?cat=5 http://example.com/?cat=5,7,9
In response to these URLs, WordPress would return the archive of posts belonging to the specified categories.
We are not limited to just one parameter per URL. In the following examples we’re building more complex queries:
?author_name=lucy&category_name=WebDev ?tag=wordpress&m=201606
In the first query string, author_name
and category_name
will require all posts by the specified author in WebDev category. In the second query string, tag
and m
will require all posts tagged as wordpress and published on June 2016.
As you can see, we can set more than one query variable and force WordPress to run advanced queries just adding the appropriate key=value pairs to query strings.
Pretty WordPress Permalinks and Structure Tags
By enabling Pretty Permalinks we set a usable, accessible and SEO-friendly URL structure. Let’s compare the following URLs:
http://example.com/?p=123 http://example.com/wordpress-permalinks/
In this example, the ugly permalink shows the p variable and its value (the post ID), while the pretty URL shows the post slug.
WordPress provides four Pretty Permalink formats we can choose from in Permalink Settings Screen, as shown in the image below.
But we are not limited to default formats, as WordPress allows users to customize the pretty permalink format by setting one or more structure tags.
These tags are specific keywords wrapped within % character. WordPress provides the following tags:
- %year%
The year of post-publication (four digits) - %monthnum%
The month of publication (two digits) - %day%
The day of publication (two digits) - %hour%
The hour of publication (two digits) - %minute%
The minute of publication (two digits) - %second%
The second of publication (two digits) - %post_id%
The post unique ID (integer) - %postname%
The post slug (i.e. the sanitized string representing the title of the post) - %category%
The category slug - %author%
The author slug
Let’s check the Custom structure radio button and add one of the following strings into the text field:
/%author%/%postname%/ /%year%/%postname%/ /%category%/%postname%/
Any of these strings generates a different pretty permalink with specific semantic values, as shown below:
http://example.com/mickey/wordpress-permalinks/ http://example.com/2016/wordpress-permalinks/ http://example.com/CMS/wordpress-permalinks/
In the first example, the resulting URL highlights the authors of the posts. The other two formats point out the year of publication and the post category respectively. It’s up to you to choose the format that suits to you best.
Custom Query Vars and Advanced Permalink Customization
In addition to public and private query vars, WordPress allows developers and advanced users to define their own custom query vars. Once registered, these variables can be added to query strings, just like public query vars, and their values can be used to affect queries as well.
From now on, I will show you how to build a custom meta query (i.e. a query that retrieves posts by custom field) taking advantage of custom query vars.
In order to accomplish this goal, we will develop a plugin from which to register custom variables, get their values and change the query accordingly.
In the main file of a plugin add the following code:
/**
* Register custom query vars
*
* @param array $vars The array of available query variables
*/
function myplugin_register_query_vars( $vars ) {
$vars[] = 'city';
return $vars;
}
add_filter( 'query_vars', 'myplugin_register_query_vars' );
/**
* Build a custom query
*
* @param $query obj The WP_Query instance (passed by reference)
*
*/
function myplugin_pre_get_posts( $query ) {
// check if the user is requesting an admin page
// or current query is not the main query
if ( is_admin() || ! $query->is_main_query() ){
return;
}
$city = get_query_var( 'city' );
// add meta_query elements
if( !empty( $city ) ){
$query->set( 'meta_key', 'city' );
$query->set( 'meta_value', $city );
$query->set( 'meta_compare', 'LIKE' );
}
}
add_action( 'pre_get_posts', 'myplugin_pre_get_posts', 1 );
Lets’ dissect this code. First we’ve registered a query var named city
:
function myplugin_register_query_vars( $vars ) {
$vars[] = 'city';
return $vars;
}
add_filter( 'query_vars', 'myplugin_register_query_vars' );
The query_vars
filter allows to add, remove or change public query vars before the query execution. The callback function in the example keeps as argument an array of the available variables, adds a new variable and returns the same array.
Following, we’ve used the value of the variable to change the query:
function myplugin_pre_get_posts( $query ) {
// check if the user is requesting an admin page
// or current query is not the main query
if ( is_admin() || ! $query->is_main_query() ){
return;
}
$city = get_query_var( 'city' );
// add meta_query elements
if( !empty( $city ) ){
$query->set( 'meta_key', 'city' );
$query->set( 'meta_value', $city );
$query->set( 'meta_compare', 'LIKE' );
}
}
add_action( 'pre_get_posts', 'myplugin_pre_get_posts', 1 );
The pre_get_posts
action hook is triggered after the query is created but before it’s executed. So we can hook a callback function to this action to make our changes to the query before it runs. That’s what happens:
- The callback function keeps an instance of the
$query
object, which is passed by reference, not by value. This means that any changes to the query object affects the original query and not a copy of it. For this reason, we have to be sure of which query is going to be executed (the main query). - Later, we get the
city
value from the current query string thanks to theget_query_var
function. - Finally, if
$city
is not empty, we can set the meta query elementsmeta_key
,meta_value
andmeta_compare
. These latter are private query vars not available for public requests. Their values can only be set from within the script.
Now activate the plugin, add the city
custom field to a number of posts, and check URLs like the following:
http://example.com/?city=London
In response to this request WordPress would return all posts where the city
field value is London
.
Let’s Make Them Pretty
Our last task is to convert the ugly URL of the example above in a pretty permalink structure. Let’s add the following function to our plugin:
/**
* Add rewrite tags and rules
*/
function myplugin_rewrite_tag_rule() {
add_rewrite_tag( '%city%', '([^&]+)' );
add_rewrite_rule( '^city/([^/]*)/?', 'index.php?city=$matches[1]','top' );
}
add_action('init', 'myplugin_rewrite_tag_rule', 10, 0);
add_rewrite_tag
and add_rewrite_rule
functions are part of the Rewrite API. add_rewrite_tag
makes WordPress aware of the city
query var, while add_rewrite_rule
specifies a new rewrite rule. Both functions should be hooked to the init
action. Thanks to new tag and rule, we can send the following URL:
http://example.com/city/London/
WordPress will return an archive of posts where the city
custom field value is London
.
Note: anytime a new rewrite rule is added, WordPress permalinks have to be refreshed from Permalinks Screen under Settings admin menu.
Summary
WordPress provides a full-fledged system to manage permalinks. Most functionalities are available out of the box, and are accessible from the admin panel. But if we’d require a deeper control over permalinks, a whole set of hooks and functions allows us to add variables to the query strings, and to rewrite URLs into accessible and SEO-friendly WordPress permalinks.
Categories
Subscribe Now
10,000 successful online businessmen like to have our content directly delivered to their inbox. Subscribe to our newsletter!Archive Calendar
Sat | Sun | Mon | Tue | Wed | Thu | Fri |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
Recent Articles
-
Posted on : Jul 25
-
Posted on : Jul 07
-
Posted on : Apr 07
-
Posted on : Mar 19
Optimized my.cnf configuration for MySQL 8 (on cPanel/WHM servers)
Tags
- layer 7
- tweak
- kill
- process
- sql
- Knowledge
- vpn
- seo vpn
- wireguard
- webmail
- ddos mitigation
- attack
- ddos
- DMARC
- server load
- Development
- nginx
- php-fpm
- cheap vpn
- Hosting Security
- xampp
- Plesk
- cpulimit
- VPS Hosting
- smtp
- smtp relay
- exim
- Comparison
- cpu
- WHM
- mariadb
- encryption
- sysstat
- optimize
- Link Building
- apache
- centos
- Small Business
- VPS
- Error
- SSD Hosting
- Networking
- optimization
- DNS
- mysql
- ubuntu
- Linux