Apr 4, 2013
Tip and Trick Editorial

How to Hide the Fact of Using WordPress (Remove Identity & Traces of WordPress)

Beginning as a blogging platform, WordPress has developed into a full-featured and easy to use content management system (CMS). But for many webmasters and web developers, who are told to or want to hide the fact that a website is using WordPress as the platform, the tasks may not be easy because WordPress comes with some unique naming convention and directory structure, and includes some common elements in HTML output. In addition, some may also want to hide the identity and traces of WordPress in to enhance the security, in what known as security by obscurity. Security by obscurity works by hiding the identity of platform used in the hope that attackers and hackers couldn’t exploit vulnerability and login path common to the software.

Though the effectiveness of security by obscurity is doubted by many, but it may still help when targeted by poorly-scripted automated attacks. Hiding the fact that a site is using WordPress can also allow the website to look more professional, improve the branding and perception, which are important especially for business websites.

Here’s a few steps that you can take to remove all the references that giving away the clues that the website is running on WordPress. The methods do not actually prevent sophisticated hackers and attackers to find out that it’s WordPress, so it does not actually make the site more secure. It just attempts to hide and remove as many clues that link to WordPress as possible.

1. Remove meta data profile

Most WordPress theme includes a profile attribute for the HEAD element which specifies the location of a meta data profile. Though it’s not WordPress-specific, but the default themes and most third-party themes for WordPress do include an identical value for meta data profile attribute in HEAD.

So, look the following line in the active theme’s header.php:

<head profile=”http://gmpg.org/xfn/11″>

And replace with just:

<head>

Head element without meta profile

Some themes that complied with HTML5 no longer append meta data profile attribute in HEAD element, where the support has been dropped. Instead, they may be using LINK element with rel attribute, as shown below:

<link rel=”profile” href=”http://gmpg.org/xfn/11″ />

Remove this line completely if found.

2. Remove WordPress meta tags output by wp_head() in header

WordPress automatically generates many links such as RSS feeds, start post, adjacent post, parent post, short URL and etc. in the header. In addition, it also adds an meta tag for generator which reveals itself as which version of WordPress is installed.

For example:

<link rel="alternate" type="application/rss+xml" title="Tip and Trick » Feed" href="https://www.tipandtrick.net/feed/" />
<link rel="alternate" type="application/rss+xml" title="Tip and Trick » Comments Feed" href="https://www.tipandtrick.net/comments/feed/" />
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://techque.com/xmlrpc.php?rsd" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://techque.com/wp-includes/wlwmanifest.xml" />
<link rel='prev' title='Previous Page' href='https://www.tipandtrick.net/' />
<link rel='next' title='Next Page' href='https://www.tipandtrick.net/' />
<meta name="generator" content="WordPress 3.5.1" />
<link rel='index' title='Tip and Trick' href='https://www.tipandtrick.net/' />
<meta name="generator" content="WordPress 3.1-alpha" />

These links and meta tags are automatically inserted via wp_head() action hook within the <head></head> section.

To remove these links and meta tags, add the following line of code to the active theme’s functions.php:

remove_action('wp_head', 'feed_links', 2);
remove_action('wp_head', 'feed_links_extra', 3);
remove_action('wp_head', 'rsd_link');
remove_action('wp_head', 'wlwmanifest_link');
remove_action('wp_head', 'index_rel_link');
remove_action('wp_head', 'start_post_rel_link', 10, 0);
remove_action('wp_head', 'parent_post_rel_link', 10, 0);
remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0);
remove_action('wp_head', 'wp_generator');
remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0);

3. Remove pingback_url link

Some themes hard-code the pingback URL onto the header section. To remove it, search for the following line of code and delete it away:

<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />

4. Redirect calls referring wp-includes directory to other location

wp-includes directory is common to all WordPress installation. It holds jQuery and many other JavaScript (JS) files that themes and/or plugins may call using wp_enqueue_script().

For each script that is been used by WordPress, plugins or themes, you’ll need to copy the script to a new folder location which does not give any hint that it’s related to WordPress, then deregister the default WordPress script with wp_dequeue_script(), and register the script again in its new location with wp_enqueue_script(). Check out example below for the code.

Normally, default installation of WordPress only loads up to 2 JS files from wp-includes directory, which are:

<script type='text/javascript' src='http://example.com/wp-includes/js/comment-reply.min.js?ver=3.5.1'></script>
<script type='text/javascript' src='http://example.com/wp-includes/js/jquery/jquery.js?ver=1.8.3'></script>

comment-reply.min.js is used to support threaded (nested) comments. So if you don’t use threaded comments, or don’t even enable the comments, you can go to Settings -> Discussion, and unselect the Enable threaded (nested) comments x levels deep in Other comment settings.

Disable WordPress Threaded Comments

For jQuery, it’s possible to make use of Google-hosted jQuery instead of calling from wp-includes directory. To do so, add in the following function into active theme’s functions.php:

function Google_jQuery() {
  wp_dequeue_script('jquery');

  wp_enqueue_script(
    'jquery',   // handle
    'http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js', // URL to script
    array(),    // dependencies (empty)
    '1.8.3',      //version number
    false       // load in header, 'true' for in footer
  );
}    
add_action('wp_enqueue_scripts', 'Google_jQuery');

An alternative for above function is as follow:

function Google_jQuery() {
  wp_deregister_script('jquery');

  wp_register_script('jquery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js', false, '1.8.3');
  wp_enqueue_script('jquery');
  }
}
add_action('init', 'Google_jQuery');
[note color=”#FFCC00″]You may need to change the version of jQuery depending the version that is been used by version of WordPress you’re using.[/note]

If you’ve many scripts, you can also take a look at Use Google Libraries plugin, which makes the WordPress to use the content distribution network side of Google’s AJAX Library API, rather than serving these files from your WordPress install directly.

5. Remove WordPress gallery shortcode inline styling CSS

When gallery shortcode is used, WordPress adds inline styling CSS on HTML output. Add the following PHP code to active theme’s function.php to remove the CSS. After doing this, you’ll need to add your own custom style for gallery on the frontend.

add_filter( 'use_default_gallery_style', '__return_false' );

6. Remove WordPress Recent Comments inline styling CSS

When the Recent Comments widget is used, WordPress adds inline styling CSS on HTML output, as shown below:

.recentcomments a{display:inline !important;padding: 0 !important;margin: 0 !important;}

Add the following PHP code to active theme’s function.php to remove the CSS. After doing this, you’ll need to add your own custom style for Recent Comments widget on the frontend.

function remove_recent_comments_style() {  
  global $wp_widget_factory;  
  remove_action( 'wp_head', array( $wp_widget_factory->widgets['WP_Widget_Recent_Comments'], 'recent_comments_style' ) );
}  
add_action( 'widgets_init', 'remove_recent_comments_style' );

7. Change the WordPress content and plugins directories

WordPress allows the default content directory, wp-content, to be changed. Follow the steps to change or rename the wp-content (and also themes, plugins and uploads) directories.

8. Clean up the WordPress navigation menu

By default, the output of navigation menu by WordPress includes lots of ID and CLASS selectors which are unique to WordPress. For example:

<li id="menu-item-7777" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-7777"><a href="https://www.tipandtrick.net/">Home</a></li>
<li id="menu-item-8888" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-8888"><a href="https://www.tipandtrick.net/computer-hardware/">Computers</a></li>

Roots theme uses custom functions to modify the wp_nav_menu() walker which produces a clean navigation menu such as below:

<li class="menu-home"><a href="https://www.tipandtrick.net/">Home</a></li>
<li class="menu-computers"><a href="https://www.tipandtrick.net/computer-hardware/">Computers</a></li>

To clean up the navigation menu, add the following code to active theme’s functions.php:

class Roots_Nav_Walker extends Walker_Nav_Menu {
  function check_current($classes) {
    return preg_match('/(current[-_])|active|dropdown/', $classes);
  }

  function start_lvl(&$output, $depth = 0, $args = array()) {
    $output .= "\n<ul class=\"dropdown-menu\">\n";
  }

  function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
    $item_html = '';
    parent::start_el($item_html, $item, $depth, $args);

    if ($item->is_dropdown && ($depth === 0)) {
      $item_html = str_replace('<a', '<a class="dropdown-toggle" data-toggle="dropdown" data-target="#"', $item_html);
    }

    $output .= $item_html;
  }

  function display_element($element, &$children_elements, $max_depth, $depth = 0, $args, &$output) {
    $element->is_dropdown = !empty($children_elements[$element->ID]);

    if ($element->is_dropdown) {
      if ($depth === 0) {
        $element->classes[] = 'dropdown';
      } elseif ($depth === 1) {
        $element->classes[] = 'dropdown-submenu';
      }
    }

    parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
  }
}

/**
 * Remove the id="" on nav menu items
 * Return 'menu-slug' for nav menu classes
 */
function roots_nav_menu_css_class($classes, $item) {
  $slug = sanitize_title($item->title);
  $classes = preg_replace('/(current(-menu-|[-_]page[-_])(item|parent|ancestor))/', 'active', $classes);
  $classes = preg_replace('/((menu|page)[-_\w+]+)+/', '', $classes);

  $classes[] = 'menu-' . $slug;

  $classes = array_unique($classes);

  return array_filter($classes, 'is_element_empty');
}

add_filter('nav_menu_css_class', 'roots_nav_menu_css_class', 10, 2);
add_filter('nav_menu_item_id', '__return_null');

To activate the above custom walker, modify the call to navigation menu in the active theme file, normally in ‘header.php’:

<?php wp_nav_menu(array(‘theme_location’ => ‘primary_navigation’, ‘walker’ => new Roots_Nav_Walker())); ?>

9. Rebrand and white label the WordPress

If you allow end-users to login to the administration backend, you probably notice that WordPress signature and logo are imprinted almost everywhere.

To get rid of WordPress in the administration backend, try White Label CMS.

The White Label CMS plugin is for developers who want to give their clients a more personalised and less confusing content management system. It allows complete customization of dashboard panels and logos, removal of menus, giving editors access to widgets and menus, and etc.

White Label CMS

10. Block access to URL with ‘wp-‘

A lot of important WordPress core files start with ‘wp-‘. These WordPress core files are vital for the running of the website, but it shouldn’t be visited by anybody. When a file starting with ‘wp-‘ responded, even with PHP error, it gives away that the website is powered by WordPress.

Avery Chan gives an detailed explanation on how to block access to URL which starts with ‘wp-‘, which still allows wp-admin to be accessed. The trick is by adding the following code into .htaccess of the website:

# If the resource requested is a 'wp-*' file or directory, redirect and return the 403 Forbidden status
RewriteCond %{REQUEST_FILENAME} wp-.*$ [NC] RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} -f [NC,OR] RewriteCond %{REQUEST_FILENAME} -d [NC] RewriteRule .* - [F,L]

Then, add the following code into .htaccess to allow wp-admin to be accessed via another URL of your choice. In the following example, backend is used.

# If the resource requested is 'backend' (with or without an trailing slash, rewrite URL to 'wp-login.php'
RewriteCond %{REQUEST_URI} backend/?$ [NC] RewriteRule backend/?$ /wp-login.php [NC,L]

So, to access WordPress admin page, visit http://www.domain.name/backend instead of http://www.domain.name/wp-login.php.

Note that the redirect rules above may break WordPress functionality, and causes unknown effect such as breaking themes and plugins, especially if you are not renaming the wp-content directory. If you’re encountering issue, you can make sure of alternative below.

Alternative

If you’re having problem preventing the access to the ‘wp-*’ files and directories, WordPress allows itself to be installed on a subdirectory, but have the website exist in the document root. For example:

Site URL: http://www.domain.name/

Admin URL: http://www.domain.name/subdirectory/wp-admin/

The good thing is that the subdirectory can be made up of any name, allowing webmasters or developers to use a name made of random characters and/or numbers to obscure the URL. For example, http://www.domain.name/abcdefgh789/wp-admin/, making the existence of WordPress harder to be known if the admin URL is kept secret.

  1. Create the new location for the core WordPress files to be stored (e.g. /hidewordpress).
  2. Go to the Settings -> General panel.
  3. In the box for WordPress address (URL), change the address to the new location of your main WordPress core files, e.g. http://www.domain.name/hidewordpress.
  4. In the box for Site address (URL), change the address to the root directory’s URL, e.g. http://www.domain.name.
  5. Click Save Changes.
  6. Move your WordPress core files to the new location (i.e. /hidewordpress).
  7. Copy the index.php and .htaccess (if available) files from the WordPress directory (WordPress address) into the root directory of your site (Blog address).
  8. Open your root directory’s index.php file in a text editor.
  9. Change the following and save the file. Change the line that says:

    require('./wp-blog-header.php');

    to the following, using your directory name for the WordPress core files:

    require('./hidewordpress/wp-blog-header.php');

  10. Login to the new location with new URL, e.g. http://example.com/hidewordpress/wp-admin/
  11. If you have set up Permalinks, go to the Permalinks panel and update your Permalink structure.

11. Prevent access to readme.html and license.txt

readme.html and license.txt contains information that reveals it’s a WordPress installation. You can delete the files away, but they will come back on every update. The easier way is to simply block the access to the files. To block the access, apply the following directives in .htaccess:

<files filename.extension>
  order allow,deny
  deny from all
</files>

The examples, for readme.html and license.txt, are:

<files readme.html>
  order allow,deny
  deny from all
</files>
<files license.txt>
  order allow,deny
  deny from all
</files>

12. Replace or change the name of wp-admin directory

If a website allows direct authoring and editing from end-users, chance is you don’t want them to see the wp-admin in the URL too. However, wp-admin is used extensively in the code of WordPress and hard-coded in source, so any attempt to modify wp-admin directory may bring unforeseen consequences, and in worst case scenario, rendering the WordPress failed.

If you intend to rename wp-login, try to follow the guide provided by hakre, which is based in mod_rewrite to rewrite all requests to the new name to /wp-admin, and a plugin that adds a filter to replace /wp-admin to the new name in the output.

Pin It on Pinterest

Share This

Share This

Share this post with your friends!