Add Helper Classes to WordPress Navigation Menus

WordPress automatically outputs many helpful CSS class names for menus. If you use the wp_nav_menu() function to display your menus, as all good themes should do, you don’t have to settle for just the default class names.

The wp_nav_menu() function calls the wp_nav_menu_objects filter, which allows you to manipulate the menu objects before being converted into HTML and displayed on the site. One of the things you can do is add a few custom class names, like this:

This adds a menu-item-first class to the first menu item and a menu-item-last class to the last menu item. These extra utility classes are helpful when styling menus in a custom theme.

Prevent Directory Browsing with .htaccess

Directory browsing allows visitors to your site to see and browse through the contents of folders on your web site. Anyone on the web could potentially visit a directory on your site, see what files exist there and open them at will. Typically, web hosts disable directory browsing for security reasons. However, there are still plenty of web hosts out there that don’t disable it.

Basically, if directory browsing is enabled and you don’t have an index.html or index.php file in a given directory, the web browser will display the contents of the directory along with a link back to the parent directory.

Obviously, revealing the inner workings of your website to the public could entice hackers or at least make their job easier. Hackers can perform Google searches to find sites with directory browsing enabled and then choose sites which have known vulnerabilities based on their findings.

How to Check Your Site

You can check to see if directory browsing is enabled on your site by creating a folder and adding a basic text file. If you visit the directory in your web browser and it displays a link to the text file, then directory browsing is enabled. If you get a ‘Page Not Found’ or ‘Forbidden’ message, then directory browsing is disabled.

Web Host Checklist

If you find that your web host has directory browsing enabled, leave a comment below and we’ll start a running list. Meanwhile, if your web host uses an Apache server, you will want to apply the fix at the end of this article.

Directory Browsing and WordPress

By default, a self-hosted installation of WordPress has a built-in safeguard against directory browsing. A new WordPress installation will contain a blank index.php file in each folder so that a user visiting a folder, such as the plugins directory, will be presented with a blank screen. However, many WordPress plugins don’t do this. This means that hackers can likely see what plugins, and versions of those plugins, that you have installed on your site.

Securing Access to your Directories with .htaccess

The easiest way to disable directory browsing is to add a line to your site’s .htaccess file. Just be aware that this only works for sites running on an Apache web server.

Keep in mind that you can have .htaccess files in multiple locations, but you want to make your change in the .htaccess found in the root directory for your domain. This will cause the change to take place across your entire site.

Here is what you will need to do:

  • Download your .htaccess file and make a copy. You should always keep a copy of your .htaccess file when making changes, for when things don’t work as planned.
  • Add these lines to your .htaccess file:

  • Upload the new .htaccess file and overwrite the existing one.
  • Verify that directory browsing is disabled. You can visit a folder that previously allowed you to view the directory contents and be sure you are getting a ‘Page Not Found’ or ‘Forbidden’ error message.

Browser Caching of 301 Redirects

Many people don’t realize that browsers cache 301 redirects. A 301 redirect is a permanent redirect from one URL to another. It only makes sense that a browser should cache a 301 redirect, after all, it is permanent.

Our natural tendency after setting up redirects is to check and see if they are working properly. However, if you made a mistake and had to tweak one of your 301 redirect rules, guess what is going to happen when you go to test your change? Yep. Your browser is going to send you to the same place it redirected you to last time.

Clear your browser cache each and every time you make a change to a 301 redirect.

If you put a 301 redirect into operation, that redirect will be cached in the browser for any visitor’s on your site. You can’t clear the browser cache for your users, so if you need to change or undo a 301 redirect, the old redirect is still going to be in effect until their cache expires.

Never put a 301 (permanent) redirect in place unless it is truly permanent!

When you are setting up redirects and aren’t sure if they work yet, do you really want them to be permanent? No, you still need to test them! As a best practice, you should always implement 302 (temporary) redirects first. This way you will avoid having to constantly clear your browser cache and you will never have a situation where a subset of your users are constantly redirected into oblivion because their browser cached a bad redirect.

Always implement 302 (temporary) redirects first, then change them to 301 (permanent) redirects once you’ve tested them!

Web Redirects and the Law of Specificity

A common mistake when setting up multiple redirects for a website is failing to put them in the correct order. Typically, the person setting them up realizes that order is important; but it isn’t always clear how the redirects should be ordered.

Let’s take a look at a simple use case where there are multiple redirects:

The first redirect can actually live anywhere in the file since there is no competing rule.

However, the other two redirects are competing rules. You can easily find competing rules by finding any redirects where the ‘from’ portion of the path is the same.

In our example, the second redirect will pick up a request for /our-team/john-doe and send it to /about/john-doe. Since a redirect triggers immediately once a matching rule is found, our last redirect is never hit.

The Law of Specificity

The Law of Specificity states:

Web redirects should always be ordered by specificity. The most specific redirect rules should always come first and the more general rules should come last.

Let’s reorder our previous example according to this new insight:

As you can see, now that we’ve placed the more specific rule first, the /our-team/john-doe request will get forwarded to /john-doe as expected and any other requests to the /our-team path will be appropriately redirected within the /about path.

On a side note, I’ve decided to separate all of my non-competing rules from my competing rules. For competing rules, I like to group them based on their shared ‘from’ path.

WWW Redirects with .htaccess

Determining whether to use www in your canonical URLs is an important decision and should be reinforced by redirects to prevent duplicate content from an SEO perspective.

Definition of a WWW Redirect

A www redirect is a rule on your web server that forwards all traffic from the non-www version of your domain to the www version, or vice versa.  

For example, lets say your web address is and someone types in into their browser.  The browser will send them to  When that request hits your web server, the redirect will tell the browser that the correct web address is actually and will send the user there instead.  You can also setup redirects that work the other way around and send users from to

If you are trying to decide whether to use a naked domain or a www subdomain in your canonical URLs, be sure to read the article “Why use WW?“.

The HTTP protocol used on the web has a numerical system for identifying the status of page requests.  The 301 status code indicates that the page or resource requested has ‘moved permanently’.  When implementing your www redirect it is important that you return a 301 status code so that search engines are clear which URL should be indexed.

Avoiding Duplicate Content with Redirects

Every website has what is called the ‘site root’.  That is the main directory on your web host that is publicly available when a user goes to your domain.  By default, this directory can be accessed by typing in the root domain one of two different ways or  This means that for every page on your website, it can be accessed via two different URLs: the www version and the non-www version.  When search engines, such as Google, come along to crawl and index your site, they may come to the same page via the two different versions of the URL.  When a search engine finds the same content at different URLs, it is called duplicate content.

Duplicate content is an issue because it puts your own site in competition with itself.  A page that might normally have great rankings in search now has another copy of itself in the search index.  When a user types in a keyword, how does the search engine know which page to display? Is one copy better than the other?  To find the answer, search engines will look at off-page factors such as the number of incoming links.  If you have links pointing to just one of the pages, then that one will probably be selected. If not, then that means you have users linking to two different URLs for the same content.  Imagine how much better you would rank in search if all those links were for the same page.  Allowing the same content to be accessed via multiple URLs dilutes your SEO efforts and devalues your content in the eyes of search engines.  The fix is to simply redirect everyone, search engines included, to the desired URL using 301 redirects.

Locating and working with your .htaccess file

If you aren’t using an Apache server, then what I am about to tell you won’t work.  If you are, then you will need to find or create an .htaccess file at your site’s root directory.  

The .htaccess file may, or may not, be visible when viewing your site’s file structure through cPanel or your favorite FTP editor.  If you don’t see an .htaccess file, look around for an option that will allow you to see hidden files.  If you still don’t see it, then go ahead and create a new file named .htaccess.  If you have to create one, you may have to upload an empty text file and rename it to .htaccess (not .htaccess.txt).  Once you have found or created your .htaccess file, then you just need to place your redirect rules within it.

If your .htaccess file already has stuff in it, make a copy and save it somewhere in case you have to revert back! There is nothing worse than breaking your entire site because you messed up an important file and didn’t save a backup.

Implementing the WWW Redirect

First, make sure that mod_rewrite is enabled.  Just make sure that this line appears somewhere in your .htaccess file above the rule that we are about to add:

To redirect from non-www to the www version of your site, use the following rule:

To redirect from www to the non-www version of your site, use the following rule:

Make sure that you replace with your real domain!

Simple Redirects with .htaccess

Anytime you migrate a web site, or even just move a single page to a new URL, redirects make sure that your users don’t get lost in the shuffle. Search engines also use redirects to aid in properly indexing your site’s content.

It is important to understand the distinction between the two most common types of redirects:

  • Permanent redirect — A permanent redirect, or 301 redirect, should be used anytime you permanently move a page, directory or website.
  • Temporary redirect — A temporary redirect, or 302 redirect, should be used if you want to temporarily point a user to another location.

If you are running an Apache server, then you can create a file named .htaccess in any directory to be able to locally override certain server configurations. It is very common for an .htaccess file to exist at the root directory of a website. You can use a very simple syntax within an .htaccess file to setup page, directory and site-wide redirects. While you can get quite advanced with URL redirects, we are going to get started with the simplest use cases.

There are three common use cases when setting up redirects:

  • Redirect a single page to a new page
  • Redirect a whole directory to a new directory
  • Redirect an entire site to a new site

Redirect Syntax

This is the basic syntax for redirects written using the mod_alias redirect directive in Apache:

  • Make sure you capitalize the R in Redirect or it won’t work. Everything is case sensitive.
  • The status is optional and is usually a number indicating the HTTP status code you want to deliver to the browser. You can use the word permanent in the place of 301, or temp in the place of 302. If not provided, then 302 will be used as the default.
  • The URL-path is required and is always a path relative to the site root, not the location of the .htaccess file.
  • The URL is required and is either a path relative to the site root, assuming the redirect is within the same site, or an absolute URL if the redirect points to another site.

Redirect a Single Page

Let’s start with a simple redirect where you want to point one page to another page:

As you can see, we are doing a 301 (permanent) redirect from a page on the current site, to another page on the same site.

If the new page is located at another domain, or even subdomain, then here is how you would write the redirect:

It is perfectly acceptable to use this method even if the page is on the same site. It never hurts to be more explicit and use an absolute URL.

Consider how the last example plays out with a few different URL variations:

# Target URL Destination URL


  • Redirect #1 — Takes a page on an old domain to a new page on a new domain.
  • Redirect #2 — Does the same thing as the first redirect, but demonstrates that any URL GET parameters are passed along as part of the redirect.
  • Redirect #3 — An example of redirecting from the current domain to a subdomain.
  • Redirect #4 — Demonstrates a redirect that takes place on the same (sub)domain.

Redirect a Whole Directory

Here is an example of how you would redirect from one directory to another:

Again, let’s take a close look at how this example can play out:

# Target URL Destination URL


  • Redirect #1 — Takes a directory on an old domain to a new directory on a new domain.
  • Redirect #2 — Shows that any individual pages within the old directory are automatically redirected to the same location in the new directory.
  • Redirect #3 — Shows that any subdirectories within the old directory are automatically redirected to the same location within the new directory.
  • Redirect #4 — Illustrates the recursive nature of the redirect.
  • Redirect #5 — Does the same thing as the first redirect, but demonstrates that URL GET parameters are always passed along as part of the redirect.

The assumption with this type of redirect is that the contents of the directory are exactly the same on the destination URL as they previously were on the target URL. In other words, only the directory name has changed.

It is possible to combine a directory redirect and a few single page redirects, like this:

This example shows that order is important. When a redirect rule is hit, it happens immediately. The rest of the file is not processed for redirect rules. If our single page redirects are not hit, then the generic directory redirect will happen. This is the proper way of handling a redirect where the contents of the directory are exactly the same on the destination URL as they previously were on the target URL, except for the about.html and contact.html pages.

Redirect an Entire Website

Here is an example of how you would redirect an entire site:

As you can see, this redirect assumes that everything on the new site is in the same place as it was on the old site:

# Target URL Destination URL


  • Redirect #1 — The old root domain redirects to the new root domain.
  • Redirect #2 — GET URL parameters are always passed along.
  • Redirect #3 — Single pages are redirected to the same location on the new domain.
  • Redirect #4 — Directories are redirected to the same location on the new domain.
  • Redirect #5 — Child pages are redirected to the same location on the new domain.
  • Redirect #6 — Subdirectories are redirected to the same location on the new domain.

Let me know if you found these examples helpful!

Hide WordPress Plugin Deactivation Links

You can prevent WordPress users from being able to deactivate plugins by hiding the ‘Deactivation’ links.


At first glance, it doesn’t make much sense to prevent users from disabling plugins within the WordPress admin. You certainly wouldn’t want to release a public plugin that prevents users from turning it off, especially since you have to deactivate a plugin before you can delete it. Let’s argue it out.

Me: “I think it would be appropriate to disable plugin deactivation when you have a plugin that is integral to the site and shouldn’t be disabled.”

You: “Yeah, but why not just use a must use plugin?!?”

Me: “If it is a custom plugin, absolutely. However, must use plugins don’t check for or show available updates.”

You: “Oh, so instead of having to manually update a must use plugin, if I disable deactivation for a public plugin then the user can’t disable it and can still see when updates are available.”

Me: “Right. You will also be able to update the plugin from the admin area, which you can’t do with a must use plugin.”

You: “It sounds like this would work well for publicly available plugins because they automatically check for updates. If I have a custom plugin that is set up to automatically check for updates, then this could be a great way to manage integral plugins across multiple client sites!”

Me: “Absolutely!”


The code below can be placed in a custom plugin. If you’ve wired the plugin for update checks, then you will get the benefits of easy updates without the downside of a client being able to disable or delete the plugin.

If you want to disable deactivation of a third-party plugin, then you will want to drop this code in a file in the mu-plugins directory and instead of using plugin_basename( __FILE__ ) you will want to hardcode the plugin basename.

WordPress Must Use Plugins

WordPress must use plugins are plugins that are always loaded and cannot be deactivated within the WordPress admin.


A bit of a hidden feature, must use plugins require a little setup initially:

  • First, you will need to create an mu-plugins directory within the WordPress content directory. The mu-plugins directory will sit alongside your normal plugins directory, normally at wp-content/mu-plugins unless you’ve moved or renamed the WordPress content directory.
  • Then, any files you upload into that directory will be loaded automatically. Just be aware that dropping a folder into mu-plugins won’t do anything, only standalone files will load.

The Pros

  • Must use plugins are always on and cannot be disabled within the admin area.
  • Must use plugins load before normal plugins.

The Cons

  • Must use plugins will never check for or show available updates.
  • Must use plugins do not trigger plugin activation hooks.

Tips & Tricks

  • Dropping a file into the mu-plugins directory means that code runs automatically, without having to log into the admin. This comes in handy when you need to do things like force a WordPress admin user.
  • If you want to load a normal plugin as a must use plugin, just drop the plugin folder into the mu-plugins directory and then create a plugin-loader.php file (any name will do) that does a require for the main plugin file.
  • Files in the mu-plugins directory load alphabetically. If you need to manually control the load order, you can simply rename the files.
  • You can move or rename the mu-plugins directory by setting these constants in your wp-config.php file:

Exclude a Plugin or Theme from WordPress Updates

Exclude a Plugin

I’ve occasionally run into the situation where I’ve implemented a custom plugin for a client and given it a unique name. Then, someone else releases a plugin by the same name and now there is an ‘update’ for my plugin. The client goes in and updates the plugin only to find that they have lost the custom functionality I implemented for them.

If you create a custom plugin for a client, be sure to disable plugin updates!

Just place the code above in the main file of your plugin and WordPress will never show that it has an update.

Exclude a Theme

Another situation I’ve run into is where a new client comes to me and has a WordPress theme that was directly modified. Since they aren’t using a child theme, updating the theme would cause them to lose all the original customizations.

If you modify a publicly released theme, be sure to disable theme updates!

Note: This only works if the theme is active! If you want to prevent updates even if the theme is inactive, then you will need to add the code to a plugin and use hardcoded values instead of get_option( 'template' ) and get_option( 'stylesheet' ).

Both of the code snippets above are an updated version of the code originally posted by Mark Jaquith.

Managing WordPress Automatic Updates

WordPress will, by default, automatically update itself when there are security releases. It can also update themes and plugins automatically if necessary. From a security perspective, this is great. However, automatic updates can also present complications.

For example, if you’ve modified your theme, you don’t want it auto updating or you will lose all of those customizations. Perhaps you don’t want to update plugins automatically so you can test for potential conflicts with other plugins. Maybe you don’t want to update WordPress core because you are intentionally running an older version, as is often the case with large companies. The list of reasons goes on and on, so let’s just get to the code already.

Here is a list of what can be automatically updated:

  • WordPress core
  • Plugins
  • Themes
  • Translations

WordPress Core Updates

By default, WordPress will automatically update core if:

  • A new version is available and you are running a development version of WordPress.
  • A new version is available and it is a minor release.

WordPress, by default, won’t automatically update if:

  • A new version is available and it is a major release.
  • Version control is detected

WordPress has a constant called WP_AUTO_UPDATE_CORE which dictates how automatic updates to core are handled. Here are the possible values that can be set:

  • false — Prevents any automated updates to WordPress core.
  • minor — Allows updates to development versions and minor releases. This is the default.
  • true — Allows WordPress core to automatically update anytime there is a new version, whether it be a development, minor or major release.

To disable all automatic updates to WordPress core, you could just add this line to your wp-config.php file:

After WordPress checks the value of the WP_AUTO_UPDATE_CORE constant, there are three filters that let you control whether or not automated updates happen, depending on the scenario:

  • allow_dev_auto_core_updates — Controls whether or not WordPress updates to a development release.
  • allow_minor_auto_core_updates — Controls whether or not WordPress updates to a minor release.
  • allow_major_auto_core_updates — Controls whether or not WordPress updates to a major release.

You can use the filters above to disable a specific type of update like this:

If you want to enable a specific type, just replace __return_false with __return_true. Just in case you were wondering, these are functions that WordPress provides so you can easily set a callback that will return true or false.

Finally, there is one last filter that is run: auto_update_core. This controls whether or not core updates of any kind are run and defaults to the value determined after the WP_AUTO_UPDATE_CORE constant is checked and the aforementioned filters are run.

You can use this filter to disable core updates like this:

Plugin Updates

By default, WordPress plugins will only auto-update if the API response from passes an non-empty autoupdate property. This will only happen if the WordPress team makes the decision to update a plugin and ensures that the API response issues an auto-update command.

If you want to prevent this, there is only one filter that will allow you to do that:

Theme Updates

Like plugins, WordPress plugins will only auto-update if the API response from passes an non-empty autoupdate property because the core team decided to issue an auto-update command.

To prevent this, just use this filter:

Translation Updates

WordPress translations are managed separately and are automatically updated by default. If you want to prevent this, just use this filter:

All WordPress Updates

If you aren’t trying to selectively enable / disable specific types of updates and would rather just disable automatic updates of any kind, then you can use the AUTOMATIC_UPDATER_DISABLED constant in your wp-config.php file to do just that:

Setting the value to true will disable all automatic updates. The default value is false.

After the constant is checked, a filter by the same name is called: automatic_updater_disabled. This filter is your last chance to override the defaults, or any value that may have been set via the constant.

You can disable all automatic updates using the filter, like this:

There is one other, slightly nuclear, way to disable automatic updates: DISALLOW_FILE_MODS. When set to true this constant will do the following:

  • Disable automatic updates of any kind.
  • Disable the theme editor.
  • Disable the plugin editor.
  • Disable the ability to install themes or plugins.
  • Prevent all users from being able to update WordPress core, themes or plugins from the admin.
  • Hide all update notifications for themes and plugins.
  • Will prevent any and all the constants and filters mentioned earlier in this article from having any effect.

This doesn’t really make sense to use unless a site is completely managed by a professional developer or team of developers and there are systems in place where all updates are handled external to the production code base.

If you know what you are doing and want to go this route, just add this to your wp-config.php file:

Note: The WordPress core update nag will still display, but it will simply tell users to notify the site administrator. So, if you do choose to go this route, you will probably want to disable that nag as well.