Wordpress - Hide the fact a site is using WordPress?

The biggest WordPress giveaways are between the <head> </head> tags.

Example WordPress head content output by The Twentyten Theme and how to remove:

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

Remove directly from header.php

 <link rel="stylesheet" type="text/css" media="all" href="http://example.com/wp-content/themes/twentyten/style.css" /> 

Hide WordPress by calling your stylesheet from another location and change the wp-content directory. WordPress requires your theme to include some basic information at the top of style.css (style.css must be in the themes root directory). You will need to create an alternate CSS and call it from your head. WordPress does not require you to use the themes style.css it only requires it to be in the themes directory.

Remove directly from header.php

<link rel="alternate" type="application/rss+xml" title="Example Blog &raquo; Feed" href="http://example.com/feed/" /> 
<link rel="alternate" type="application/rss+xml" title="Example Blog &raquo; Comments Feed" href="http://example.com/comments/feed/" />    
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://example.com/xmlrpc.php?rsd" /> 
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://example.com/wp-includes/wlwmanifest.xml" /> 
<link rel='index' title='Example Blog' href='http://example.com/' /> 
<meta name="generator" content="WordPress 3.1-alpha" /> 

To remove these extra links you can add a filter to functions.php

// remove junk from head
remove_action('wp_head', 'rsd_link');
remove_action('wp_head', 'wp_generator');
remove_action('wp_head', 'feed_links', 2);
remove_action('wp_head', 'index_rel_link');
remove_action('wp_head', 'wlwmanifest_link');
remove_action('wp_head', 'feed_links_extra', 3);
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', 10, 0);

You can change your plugin directory and your wp-content directory in your wp-config.php file but you could have some problems if your theme or any plugins do not use the proper method to call files.

define( 'WP_CONTENT_DIR', $_SERVER['DOCUMENT_ROOT'] . '/new-wp-content' );

Set WP_CONTENT_URL to the full URI of this directory (no trailing slash), e.g.

define( 'WP_CONTENT_URL', 'http://example/new-wp-content');

Optional Set WP_PLUGIN_DIR to the full local path of this directory (no trailing slash), e.g.

define( 'WP_PLUGIN_DIR', $_SERVER['DOCUMENT_ROOT'] . '/new-wp-content/new-plugins' );

Set WP_PLUGIN_URL to the full URI of this directory (no trailing slash), e.g.

define( 'WP_PLUGIN_URL', 'http://example/new-wp-content/new-plugins');

PLUGINS

Be aware that some plugins like Akismat, All in One SEO, W3-Total-Cache, Super Cache, and many others add comments to the HTML output. Most are easy to modify to remove the comments but your changes will be overwritten anytime the plugins get updated.

wp-includes

The wp-includes directory holds jquery and various other js files that themes or plugins will call using wp_enqueue_script(). To change this you will need to deregister the default WordPress scripts and register the new location. Add to functions.php:

function my_init() {
    if (!is_admin()) {
        // comment out the next two lines to load the local copy of jQuery
        wp_deregister_script('jquery');
        wp_register_script('jquery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js', false, '1.3.2');
        wp_enqueue_script('jquery');
    }
}
add_action('init', 'my_init');

This will need to be done with each script used by your theme or plugins.


One bit that is often missed - delete readme.html in WordPress root. It not only identifies installation as WP but also has precise version. And don't forget to repeat on updates.

Related Question: Prevent access or auto-delete readme.html, license.txt, wp-config-sample.php


I've always used the Roots Theme method.
But applying it to those ThemeJungle's out there is usually a big headache.

So, started to play with the WP_CONTENT_* constants. Which I believe is a much less error prone method and this is what I have working right now:

safari activity window
/m is the uploads folder, /t is the themes folder and /t/t is the active theme folder. The site is not complex, so few assets loaded...


WP_CONTENTLESS

wp-config.php

Setting wp-content to the root (/public_html/) of the site.

/** 
 Inside WP_CONTENT, the following folders should exist: 
 /languages , /mu-plugins , /plugins , /themes , /upgrade , /uploads  

 The WP_CONTENT_* definitions bellow REMOVE the existence of the /wp-content folder 
 and makes its contents reside in the ROOT of your site

 UTTERMOST attention is necessary when doing file maintenance activities in the server (i.e.: WP upgrades, new Webmaster...), 
 as the Themes and Plugins folders are meant to be renamed to /t and /p (serious candidates for unthoughful removal)

 PLEASE note:
 - we change the Plugins folder in WP_PLUGIN_* definitions
 - the Themes folder is changed by a MustUse Plugin 
   (/mu-plugins/set-extra-themes-folder.php)
 - the Uploads folder is changed in WordPress settings page 
   (http://example.com/wp-admin/options-media.php)
 - the hardcode path to be used in WP_CONTENT_DIR and WP_PLUGIN_DIR can be checked using an action inside the set-extra-themes-folder Plugin (check the comments in this file)
*/
define( 'WP_CONTENT_DIR', '/www/htdocs/username/public_html' );
define( 'WP_CONTENT_URL', 'http://www.example.com' );

define( 'WP_PLUGIN_DIR', '/www/htdocs/username/public_html/p' );
define( 'WP_PLUGIN_URL', 'http://www.example.com/p' );

I've asked about it in [wp-hackers] - Any drawbacks in setting WP_CONTENT_DIR (and URL) to DOCUMENT_ROOT?, where John Blackbourn1, Mike Little2 and Otto3 were kindly enough as to advise:

1
I've had this structure active on a site for the last 18 months and haven't seen any problems. As with any change to the location of the content directory, you'll need to double check any plugins you add to the site don't assume that the content directory is at wp-content.

2
There are discussions around the net the $_SERVER['DOCUMENT_ROOT'] may be susceptible to hacking. In which case this is extremely dangerous because there are lots of places that require() or include() WP_CONTENT_DIR . 'something';

3
There are cases where the content in $_SERVER can be perfectly safe, but for security purposes, it is better to always treat it as untrusted data. For this specific case, hardcode the directory.


A New Themes Folder

/mu-plugins/set-extra-themes-folder.php

As there's no WP_THEMES_* constants, we need the function register_theme_directory() to "Register a directory that contains themes."
Tried to set the extra directory to the root but the results are funny (i.e.: it doesn't work).

<?php
/*
    Plugin Name: Set Extra Themes Folder
    Version: 1.0
    Description: Allows the directory - http://example.com/t - to be used as an extra theme's directory
    Plugin URI: http://wordpress.stackexchange.com/questions/1507
    Author: brasofilo
    Author URI: http://rodbuaiz.com
*/


/**
 * Remove the comment from the following line to know the correct path to put in register_theme_diretory()
*/
//add_action( 'admin_head', 'brsfl_alert_directory_path' );

function brsfl_alert_directory_path()
{
    echo '<script type="text/javascript">
        alert("Directory: '.$_SERVER['DOCUMENT_ROOT'].'");
    </script>';
}


/**
 * The following will enable the directory "t" to be used as an EXTRA Themes directory
*/
register_theme_directory( '/www/htdocs/username/public_html/t' );


/**
 * De-registering default scripts in wp-includes for CDN ones
*/
add_action('init', 'brsfl_init_scripts');

function brsfl_init_scripts() 
{
    if ( !is_admin() ) 
    {
        wp_deregister_script( 'jquery' );
        wp_deregister_script( 'swfobject' );
        wp_register_script( 'jquery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js', false, '1.7.1' );
        wp_register_script( 'swfobject', 'https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js', false, null, true );
        wp_enqueue_script( 'jquery' );
        wp_enqueue_script( 'swfobject' );
    }
}

Uploads Folder

/wp-admin/options-media.php

Instead of http://example.com/uploads, it'll be http://example.com/m.
Unchecking Organize my uploads into... will give a WPless appearance to the assets URLs.
If the site is live, a search/replace must be done in the database and files must be moved around.
uploads folder settings


Plugins and Head Content

Refer to Cris_O Answer in this Q&A.


Readme.html

Refer to Rarst Answer in this Q&A.


Other Steps

As usual, ThemeJungle themes may prompt specific hacks in the theme.
Like... TimThumb not working (!!!lol!!!).