The Problem
Avada is a popular wordpress theme that offers a lot of features and pre-built websites, which helps people to rapidly build their own website right out of the box. Though it’s not as popular as before, mainly due to performance reason, Avada still has consistent support and large enough communities which still makes the theme an attractive choice.
Avada offers Portfolio feature which creates its own type of post and renders the post in a specific way. In WordPress point-of-view, this portfolio is a custom post type that differentiates itself from other default post types like: Posts, Pages, Attachments, etc. This way, Avada is able to make portfolio post type to behave and render in specific way.
The first problem with portfolio feature is, although regular posts and portfolio posts are two different types of post, they are sharing a same permalink structure. This results in:
The /cases/
slug can be configured in Avada option.
Both of them are stemming from /blog/
slug because Setting -> Permalink -> Common Settings -> Custom Structure is /blog/%postname%/
.
The ideal structure would be:
The second problem, which is a following problem after the first one, is that custom post type slug and custom taxonomy slug can’t share a same prepending slug (in this case /cases/
). Avada, by default, attaches 3 taxonomies to portfolio post type: category, skill, and tag. If any of these taxonomies has cases
as their starting custom bases in Setting -> Permalink -> Optional, it will be directed to 404 Page Not Found page.
I want all portfolio related elements (posts, taxonomies) to stem from /cases/
.
The ideal structure would be:
Solution: First Problem
The reason why portfolio posts prepends custom permalink structure is because that’s the default setting when registering a new post type. Portfolio post type and taxonomy registration happens at /wp-content/plugins/fusion-core/includes/class-fusioncore-plugin.php
.
When Avada registers portfolio post type, it does not explicitly set with_front
to false
, but just leave it empty which defaults to true
.
To disable $front
prepending the permastruct:
But be advised that source code should not be edited directly. It will easily be overwritten when there’s an update and it will cause unexpected problems.
Fortunately, WordPress provides hooks that is suitable for this kind of job. There are several hooks that can do the job, and register_post_type_args
is the one that’s most appropriate for this task.
Where can hooks be used then?
Creating a custom plugin
When site-wide modification is made, it’s often recommended to make changes with theme’s function.php
or create a custom plugin. However, making changes in function.php
is not recommended as theme updates will overwrite the file. So unless the website uses its own developed theme, it is recommended to make changes through a custom plugin.
This article will not cover much on the topic of custom plugin, but just show how to make a quick custom plugin. For more details, you can follow WordPress Plugin Development Guide.
To create a custom plugin, go to /wp-content/plugins/
and create your own folder named after your plugin. In this example, the folder will be named portfolio-slug
and its plugin file will be named porfolio-slug.php
.
Open /wp-content/plugins/portfolio-slug/portfolio-slug.php
(the file you just created) with preferred text editor and copy and paste the code below:
The Plugin Name
is the only required header field, so you can erase rest of the field if you want to. However, it’s strongly recommended to fill out Description
field and Author
field for readability.
Save the file and go to WordPress admin page -> Plugins, and you’ll see your custom plugin among other plugins like the picture below.
Activate the plugin, and you’re ready to use hooks!
Using hooks
There are two types of hooks: Action and Filter. Again, this article is not going to cover great detail on this topic. For more information, take a look at WordPress Plugin Developer Handbook.
The hook register_post_type_args
is a filter type that can alter the arguments when registering a post type. To add filter, simply use add_filter
function.
The add_filter
function will take the name of the filter hook as first argument, function to execute when triggered (callback function) as second, filter execution priority as third, and the number of arguments of callback function as fourth.
Open plugin-slug.php in text editor and add a line:
This means that filter has been added to register_post_type_args
hook and it will execute a function called change_avada_portfolio_slug
. The filter has a priority of 10 (lowest) and change_avada_portfolio_slug
function will take 2 arguments.
change_avada_portfolio_slug
function has not been declared yet. Declare a function before/after add_filter
line:
The function has two parameters, $args
and $post_type
.
$args
contains all the arguments when new post type is registered like in /wp-content/plugins/fusion-core/includes/class-fusioncore-plugin.php
, and it has rewrite
property that needs to modified.
$post_type
tells which post type is being registered.
There are many other post types being registered when WordPress is running and this hook will run every time when such post types are being registered. if
statement is required to restrict the function to only work on avada_portfolio
post type.
The function is basically saying, “If the post being registered is called avada_portfolio
, set the property with_front
of rewrite
in $args
to false
. Then return $args
for WordPress to carry on with its work.”
Save the file and go to Admin page -> Settings -> Permalink.
Without making changes in settings, click Save Changes. This will refresh the permastructure.
Create a new portfolio post and you’ll see the result of your work:
Solution: Second Problem
Let’s cut to the chase here. it is possible for posts and taxonomies to use a same slug. However this has to be done in very specific way.
When a custom post type and its custom taxonomies are registered, taxonomies have to be registered first and then a custom post type in order to let them share a slug.
The problem is, when Avada registers its portfolio post type, it registers a post type first and then its taxonomies, as shown below:
There are filters and actions that can alter the values being passed, but there’s no such hooks that can alter the sequence of registration.
Here is how this article will tackle this problem:
- Instead of trying to change the outcome during registration process, wait for all the registrations to finish.
- Unregister the registered post type and taxonomies.
- Re-register the post type and taxonomies in specific order.
1. Wait for registrations to finish
WordPress hooks don’t just randomly fire any time they want. They have an acceptable sequence. For example, muplugins_loaded
is one of the earliest fired hook that runs when must-use plugins are loaded. To wait out for fusion-core plugin to finish its registration, init
hook (fires when WordPress is initialized) is not enough.
wp_loaded
hook fires once WordPress, all plugins, and the theme are fully loaded and instantiated. To setup the hook, open portfolio-slug.php
with a text editor and add a line:
wp_loaded
is an action type hook that can be added with add_action
function.
Declare unregister_and_reregister_avada_portfolio
function.
2. Unregister the post type and taxonomies
To unregister a post type, use unregister_post_type
function.
To unregister a taxonomy, use unregister_taxonomy
function.
But before unregisteration, post type and taxonomy should be stored as an object so that it can be used when re-registering.
To get existing post type as an object, use get_post_type_object
function.
To get existing taxonomy as an object, use get_taxonomy
function.
3. Re-register the post type and taxonomies
To register a post type, use register_post_type
function.
To register a taxonomy, use register_taxonomy
function.
Fortunately, these functions can receive objects saved by get_post_type_object
and get_taxonomy
functions.
Register taxonomies first, and then a post type.
There is a side effect though, Featured Image setting disappears.
In order to enable it, and prevent other possible side effects, add a line before registering the custom post type.
Finally, filter taxonomy slugs like it’s done in first solution.
To filter arguments when taxonomies are registered, use register_taxonomy_args
hook.
with_front
property is set to false when Avada registers the taxonomies so there’s no need to set to false again.
Remember to save the file, go to Admin page -> Settings -> Permalink, and click Save Changes, as this will refresh the permastructure.
Conclusion
So far, there doesn’t seem to be additional observable side effects. As long as you don’t create a portfolio post called ‘categories’, ‘skills’, or ‘tags’, it’s not going to break the website.
The solution provided could seem hacky or unorthodox, but this solution is quite update-proof unless wordpress deprecates provided hooks.
For any suggestions/corrections, please email here.
Thank you :)