FREE THOUGHT · FREE SOFTWARE · FREE WORLD

Home  »  WordPress  »  Advanced WordPress wp-config.php Tweaks

by 10 comments

wp-configThe bottom line for this article is that I want to make WordPress as fast, secure, and easy to install, run, and manage because I am using it more and more for client production sites, I will work for days in order to solve an issue so that I never have to spend time on that issue again. Time is money in this industry and that is ultimately (time) what there is to gain by tweaking WordPress.

Basic Concepts

For a better handle on the way I like to structure web site directories, see Optimize a Website for Speed, Security, and Easy Management but note it is a bit outdated compared to what I'm doing now. I don't have the luxury of using only one type of server, or hosting provider anymore, so I have been working towards making things even more portable in order to move from host to host from server to server without issues i.e. my portable .bash_profile.

So I've been basically experimenting various ways to accomplish that and thought I would share what I am currently doing for my benefit and hopefully get some input. All of my WP installs run the development version, and one main idea with my setups is that upgrading is automated. So I really keep the WordPress install clean and use plugins and wp-config.php to do all the customization.

  • Portability - Hands-free upgrades and easy to move
  • Security - Additional security and protection
  • Speed - Less CPU and Disk I/O
  • Customization - All my favorite customizations

wp-config.php

These are the main settings I use.. Seriously this is more like an interactive article, because to understand it you will need to do some code grepping. You may want to grab a jolt.

ASKAPACHE_ROOT

The ASKAPACHE_ROOT variable is just a better way for me to be able to include and access all the different files in my site tree. For instance, in my non-wp php files, I can do this:

!defined('ASKAPACHE_ROOT') && require $_SERVER['DOCUMENT_ROOT'] . '/wp-config.php';
include(ASKAPACHE_ROOT . '/includes/custom-download.inc.php');

ASKAPACHE_LOCK

This is one of my all-time favorite hacks, that I think is one of the most useful methods I employ as a web developer. This allows me to use far-future-expire headers for optimum caching, while still forcing browsers to re-validate every day or so automatically, or forcing them to re-validate whenever I change the suffix. This takes advantage of the mod_rewrite trick that I use on EVERY site I run, definately worth learning. Because I practice best-practice web-standards, for every web site I create a single css file and javascript file, which I then add to the template like:




/**
 * The base configurations of the WordPress.
 *
 * This file has the following configurations: MySQL settings, Table Prefix,
 * Secret Keys, WordPress Language, and ABSPATH. You can find more information by
 * visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing
 * wp-config.php} Codex page. You can get the MySQL settings from your web host.
 *
 * This file is used by the wp-config.php creation script during the
 * installation. You don't have to use the web site, you can just copy this file
 * to "wp-config.php" and fill in the values.
 *
 * @package WordPress
 */
/* http://codex.wordpress.org/Editing_wp-config.php */

/** /web/liet/askapache.com */
!defined('ASKAPACHE_ROOT') && define('ASKAPACHE_ROOT', str_replace('/public_html','', $_SERVER['DOCUMENT_ROOT']));

/** The 008 at the end is for manual tweaking.  time() returns seconds since '00:00:00 1970-01-01 UTC'. */
// http://www.askapache.com/htaccess/mod_rewrite-fix-for-caching-updated-files.html
!defined('ASKAPACHE_LOCK') && define('ASKAPACHE_LOCK', substr(time(),0,5).'008'); // 12533001

/** absolute path to the Wordpress directory */
!defined('ABSPATH') && define('ABSPATH', ASKAPACHE_ROOT .'/public_html/');

/**
 * WP_SITEURL, defined since WordPress Version 2.2, allows the WordPress address (URL) to be defined. The valued defined is the address where your WordPress core files reside.
 * It should include the http:// part too. Do not put a slash "/" at the end.
 * Setting this value in wp-config.php overrides the wp_options table value for siteurl and disables the WordPress address (URL) field in the Administration > Settings > General panel.
 */
!defined('WP_SITEURL') && define('WP_SITEURL', 'http://'.$_SERVER['SERVER_NAME']);

/**
 * WP_HOME is another wp-config.php option added in WordPress Version 2.2. Similar to WP_SITEURL,
 * WP_HOME overrides the wp_options table value for home but does not change it permanently.
 * home is the address you want people to type in their browser to reach your WordPress blog. It should include the http:// part. Also, do not put a slash "/" at the end.
 */
!defined('WP_HOME') && define('WP_HOME', WP_SITEURL);

/** no trailing slash, full paths only */
!defined('WP_CONTENT_DIR') && define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );

// full url - WP_CONTENT_DIR is defined further up
!defined('WP_CONTENT_URL') && define( 'WP_CONTENT_URL', WP_SITEURL . '/wp-content');

/** Allows for the plugins directory to be moved from the default location. @since 2.6.0 */
// full path, no trailing slash
!defined('WP_PLUGIN_DIR') && define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' );

/** Allows for the plugins directory to be moved from the default location. @since 2.6.0 */
// full url, no trailing slash
!defined('WP_PLUGIN_URL') && define( 'WP_PLUGIN_URL', WP_CONTENT_URL . '/plugins' );

/** Allows for the plugins directory to be moved from the default location. @since 2.1.0 */
// Relative to ABSPATH.  For back compat.
//!defined('PLUGINDIR') && define( 'PLUGINDIR', 'wp-content/plugins' );

/** Number of autosaves to save. TRUE is default and enables post revisions, FALSE disables revisions completely. */
!defined('WP_POST_REVISIONS') && define('WP_POST_REVISIONS', 150);

/* ini_set('memory_limit', WP_MEMORY_LIMIT); */
!defined('WP_MEMORY_LIMIT') && define('WP_MEMORY_LIMIT', '64M');

/** Only check at this interval for new messages. Default is 5min */
/** @since 2.9  */
!defined('WP_MAIL_INTERVAL') && define('WP_MAIL_INTERVAL', 3600); // 1 hour

/** Saves updated post values to post from edit window every x seconds. (default 60)
 * When editing a post, WordPress uses Ajax to auto-save revisions to the post as you edit. You may want to increase this setting for longer delays in between auto-saves, or decrease the setting to make sure you never lose changes.
 * @since 2.5.0 */
!defined( 'AUTOSAVE_INTERVAL' ) && define( 'AUTOSAVE_INTERVAL', 60 );

/** @since 2.9.0  */
/** Permanently deletes posts, pages, attachments, and comments which have been in the trash for EMPTY_TRASH_DAYS. */
!defined( 'EMPTY_TRASH_DAYS' ) && define( 'EMPTY_TRASH_DAYS', 300 );

Debugging WordPress

One of my secrets for getting really good at this stuff is to master debugging. There is really not ever a time when I am working on a site that I don't have color-highlighted logs scrolling automatically in an ssh window. It's really almost impossible to fix problems with wordpress or do any kind of advanced anything without being able to view debugging info. At first I relied heavily on a custom php.ini being available on the server, but after having to deal with many hosts who don't allow php.ini files I now rely completely on setting values using ini_set for ultimate portability. Detailed towards the end of this article and is also included in this wp-config.php

/**#@+
 * DEBUGGING STUFF
 */
/** display of notices during development. if false, error_reporting is E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR otherwise E_ALL */
!defined('WP_DEBUG') && define('WP_DEBUG', false);

/** The SAVEQUERIES definition saves the database queries to a array and that array can be displayed to help analyze those queries.
 *  The information saves each query, what function called it, and how long that query took to execute.  */
!defined('SAVE_QUERIES') && define('SAVE_QUERIES', WP_DEBUG);

!defined('ACTION_DEBUG') && define('ACTION_DEBUG', WP_DEBUG);

/** This will allow you to edit the scriptname.dev.js files in the wp-includes/js and wp-admin/js directories.  */
!defined('SCRIPT_DEBUG') && define('SCRIPT_DEBUG', WP_DEBUG);


/** Add define('WP_DEBUG_LOG', true); to enable php debug logging to WP_CONTENT_DIR/debug.log */
//!defined('WP_DEBUG_LOG') && define('WP_DEBUG_LOG', true);

/** This determines whether errors should be printed to the screen as part of the output or if they should be hidden from the user.
 *  Add define('WP_DEBUG_DISPLAY', false); to wp-config.php to use the globally configured setting for display_errors and not force it to On */
!defined('WP_DEBUG_DISPLAY') && define('WP_DEBUG_DISPLAY', false);

Ultimate Security Tweaks

Well, ultimate for WP's built-in keys and password functions, this is all for wp-config.php keep in mind. This is a very neccessary and recommended step, and is one of the only things I modify for each new installation.

Security KEYS

If like me you are familiar with password-cracking software like John the ripper, rainbow hash tables, l0pht-crack, etc.. then you will like to know that you can specify your own keys and salts for the encryption used by WP. They are AUTH_KEY, AUTH_SALT, SECURE_AUTH_KEY, SECURE_AUTH_SALT, LOGGED_IN_KEY, LOGGED_IN_SALT, NONCE_KEY, NONCE_SALT, SECRET_KEY and SECRET_SALT.

A random and long key gives you better encryption, and exponentially increasing that is using a random and long salt for the encryption. Encryptions with known salts are incredibly easy to decrypt compared to encryptions with secure salts, because the salt + key individually need to be guessed in order to find a matching hash, vs. just the key if the salt is known. See: Locating weak passwords.

A secret key is a hashing salt which makes your site harder to hack and access harder to crack by adding random elements to the password.

In simple terms, a secret key is a password with elements that make it harder to generate enough options to break through your security barriers. A password like "password" or "test" is simple and easily broken. A random, unpredictable password such as "88a7da62429ba6ad3cb3c76a09641fc" takes years to come up with the right combination.

For more information on the technical background and breakdown of secret keys and secure passwords, see:

I like to use the WordPress.org secret-key service 4 times. That's because for each key and salt I like to do: (1 key from api +random keyboard input+1 key from api).

/**#@+
 * Authentication Unique Keys.
 *
 * Change these to different unique phrases!
 * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/ WordPress.org secret-key service}
 * You can change these at any point in time to invalidate all existing cookies.
 * This will force all users to have to log in again.
 *
 * @since 2.6.0
 *
 * Get salt to add to hashes to help prevent attacks.
 *
 * The secret key is located in two places: the database in case the secret key
 * isn't defined in the second place, which is in the wp-config.php file. If you
 * are going to set the secret key, then you must do so in the wp-config.php
 * file.
 *
 * The secret key in the database is randomly generated and will be appended to
 * the secret key that is in wp-config.php file in some instances. It is
 * important to have the secret key defined or changed in wp-config.php.
 *
 * If you have installed WordPress 2.5 or later, then you will have the
 * SECRET_KEY defined in the wp-config.php already. You will want to change the
 * value in it because hackers will know what it is. If you have upgraded to
 * WordPress 2.5 or later version from a version before WordPress 2.5, then you
 * should add the constant to your wp-config.php file.
 *
 * Below is an example of how the SECRET_KEY constant is defined with a value.
 * You must not copy the below example and paste into your wp-config.php. If you
 * need an example, then you can have a
 * {@link https://api.wordpress.org/secret-key/1.1/ secret key created} for you.
 *
 * Salting passwords helps against tools which has stored hashed values of
 * common dictionary strings. The added values makes it harder to crack if given
 * salt string is not weak.
 *
 * @since 2.5
 * @link https://api.wordpress.org/secret-key/1.1/ Create a Secret Key for wp-config.php
 *
 * @return string Salt value from either 'SECRET_KEY' or 'secret' option
 */
define('AUTH_KEY',        'jflkhaskljdfhkljasdhflkjashd;flkjhas;djfh;kajshdflkjashdlfkjhasdlkfhal?p[B+GR{@>{Yq`c|LnG;dvq#| %OA_cbBSU6,rICC1o/c)-|');
define('SECURE_AUTH_KEY', 'jflkhaskljdfhkljasdhflkjashd;flkjhas;djfh;kajshdflkjashdlfkjhasdlkfhal?Vp[Bb15baar8&R-r<[T|?(xhJJABGq+Ux+U$)-Hltp/');
define('LOGGED_IN_KEY',   'jflkhaskljdfhkljasdhflkjashd;flkjhas;djfh;kajshdflkjashdlfkjhasdlkfhal?Vp[B<5n6DG|YWnJ9tY2!M1L)`{-$LW~~Ia%.uCbn!P. 41o2$Z$4');
define('NONCE_KEY',       'jflkhaskljdfhkljasdhflkjashd;flkjhas;djfh;kajshdflkjashdlfkjhasdlkfhal?Vp[Bgu+wm 2)bS0Pd_+1rx0brX]ND8|');
define('SECRET_SALT', 	   '123423190847olqkfhladhfsldshafasdfasdf09a7f-90a87df98adfyapoiyaf9asd8f70a9s8d7f908a7sdf97W4qCdm2<>))U|sty)+4vpWooKls/^[vN');
/**#@-*/

Using SSL for Admin and Login

SSL is kinda required from my point of view, it is just way to easy to sniff data off the wire otherwise. At least with SSL you force them to use tools like burpsuite, paros proxy, webscarab, etc..

/** @since 2.6.0  */
!defined('FORCE_SSL_ADMIN') && define('FORCE_SSL_ADMIN', true);

/** @since 2.6.0  */
!defined('FORCE_SSL_LOGIN') && define('FORCE_SSL_LOGIN', true);

Mod_Rewrite to Force SSL

This is pretty cool, it forces non-https for all urls except for /wp-admin and wp-login.php, which both require https. It also checks for the logged_in_cookie, and if that is present in the request then it doesn't force non-https. Kinda confusing if you don't have a mod_rewrite cheatsheet.

RewriteCond %{THE_REQUEST} ^$ [OR]
RewriteCond %{REQUEST_URI} ^/(wp-admin|wp-login.php).*$ [NC,OR]
RewriteCond %{HTTP_COOKIE} ^.*wp_li_sadfsdfasdf11b361cdsdfasdfasd=.*$ [NC]
RewriteRule .* - [S=1]

RewriteCond %{HTTPS} =on [OR]
RewriteCond %{HTTP_HOST} !^www.askapache.com$ [NC]
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(wp-admin/.*|wp-login.php.*) HTTP/ [NC]
RewriteCond %{HTTPS} !=on
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

File System Permissions

chmod, umask, file permissions testYou can get a basic and solid intro on file permissions by reading: Changing File Permissions, or you can check out some of my file permission research.

/** The permissions as octal number, usually 0644 for files, 0755 for dirs.
 *  http://codex.wordpress.org/Changing_File_Permissions
 *  if ( !$wp_filesystem->mkdir($remote_destination, FS_CHMOD_DIR) )
 */
!defined('FS_CHMOD_DIR') && define('FS_CHMOD_DIR', (0755 & ~ umask()));
!defined('FS_CHMOD_FILE') && define('FS_CHMOD_FILE', (0644 & ~ umask()));
/**#@-*/

/** Define the timeouts for the connections. Only available after the construct is called to allow for per-transport overriding of the default. */
//stream_set_timeout( $stream, FS_TIMEOUT );
//!defined('FS_TIMEOUT') && define('FS_TIMEOUT', 30);

//$this->link = @ftp_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT);
//!defined('FS_CONNECT_TIMEOUT') && define('FS_CONNECT_TIMEOUT', 30);

// function get_filesystem_method($args = array(), $context = false) {
//	$method = defined('FS_METHOD') ? FS_METHOD : false; //Please ensure that this is either 'direct', 'ssh', 'ftpext' or 'ftpsockets'
//!defined('FS_METHOD') && define('FS_METHOD', 'direct');

/** These methods for the WordPress core, plugin, and theme upgrades try to determine the WordPress path, as reported by PHP, but symlink trickery can sometimes
 * 'muck this up' so if you know the paths to the various folders on the server, as seen via your FTP user, you can manually define them in the wp-config.php file.
 * FS_METHOD forces the filesystem method. It should only be "direct", "ssh", "ftpext", or "ftpsockets".
 * FTP_BASE is the full path to the "base" folder of the WordPress installation.
 * FTP_CONTENT_DIR is the full path to the wp-content folder of the WordPress installation.
 * FTP_PLUGIN_DIR is the full path to the plugins folder of the WordPress installation.
 * FTP_PUBKEY is the full path to your SSH public key.
 * FTP_PRIKEY is the full path to your SSH private key.
 * FTP_USER is either user FTP or SSH username. Most likely these are the same, but use the appropriate one for the type of update you wish to do.
 * FTP_PASS is the password for the username entered for FTP_USER. If you are using SSH public key authentication this can be omitted.
 * FTP_HOST is the hostname:port combination for your SSH/FTP server. The standard FTP port is 21 and the standard SSH port is 22.
 */
//define('FS_METHOD', 'ftpext');
//define('FTP_BASE', '/path/to/wordpress/');
//define('FTP_CONTENT_DIR', '/path/to/wordpress/wp-content/');
//define('FTP_PLUGIN_DIR ', '/path/to/wordpress/wp-content/plugins/');
//define('FTP_PUBKEY', '/web/username/.ssh/id_rsa.pub');
//define('FTP_PRIKEY', '/web/username/.ssh/id_rsa');
//define('FTP_USER', 'username');
//define('FTP_PASS', 'password');
//define('FTP_HOST', 'ftp.example.org:21');




/**
 * Block requests through the proxy.
 *
 * Those who are behind a proxy and want to prevent access to certain hosts may do so. This will
 * prevent plugins from working and core functionality, if you don't include api.wordpress.org.
 *
 * You block external URL requests by defining WP_HTTP_BLOCK_EXTERNAL in your wp-config.php file
 * and this will only allow localhost and your blog to make requests.
 * The constant WP_ACCESSIBLE_HOSTS will allow additional hosts to go through for requests. The format of the
 * WP_ACCESSIBLE_HOSTS constant is a comma separated list of hostnames to allow.
 *
 * @since 2.8.0
 * @link http://core.trac.wordpress.org/ticket/8927 Allow preventing external requests.
/** @since 2.9  */
//!defined('WP_HTTP_BLOCK_EXTERNAL') && define( 'WP_HTTP_BLOCK_EXTERNAL', false );


/*
 * The constant WP_ACCESSIBLE_HOSTS will allow additional hosts to go through for requests. The format of the
 * WP_ACCESSIBLE_HOSTS constant is a comma separated list of hostnames to allow.
 *
 * @since 2.8.0
 * @link http://core.trac.wordpress.org/ticket/8927 Allow preventing external requests.
 * $accessible_hosts = preg_split('|,s*|', WP_ACCESSIBLE_HOSTS);
 * return !in_array( $check['host'], $accessible_hosts ); //Inverse logic, If its in the array, then we can't access it.
 */
//!defined('WP_ACCESSIBLE_HOSTS') && define( 'WP_ACCESSIBLE_HOSTS', 'askapache.com,askapache.org' );

Cookies!

There's always a little comfort in having non-default cookies for security (against auto-bots), and using shorter names also means smaller HTTP Packets.

The $cookie_hash is my hack to get around the fact that COOKIEHASH isn't definable in wp-config.

/**#@+
 * COOKIES
 * Used to guarantee unique hash cookies @since 1.5 */
$cookie_hash=md5(WP_SITEURL);

/** Set a cookie now to see if they are supported by the browser.
 * setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN);
 * @since 2.3.0 */
!defined('TEST_COOKIE') && define('TEST_COOKIE', 'wp_tc');

/* @since 2.6.0 */
!defined('LOGGED_IN_COOKIE') && define('LOGGED_IN_COOKIE', 'wp_li_' . $cookie_hash);

/* @since 2.6.0 */
!defined('SECURE_AUTH_COOKIE') && define('SECURE_AUTH_COOKIE', 'wp_sa_' . $cookie_hash);

/* @since 2.5.0 */
!defined('AUTH_COOKIE') && define('AUTH_COOKIE', 'wp_a_' . $cookie_hash);

/* @since 2.0.0 */
!defined('PASS_COOKIE') && define('PASS_COOKIE', 'wp_p_' . $cookie_hash);

/* @since 2.0.0 */
!defined('USER_COOKIE') && define('USER_COOKIE', 'wp_u_' . $cookie_hash);

/* ok unset this var, its not needed as COOKIEHASH will have this value, but is not definable in wp-config.php */
unset($cookie_hash);

/** @since 1.2.0 */
!defined('COOKIEPATH') && define('COOKIEPATH', preg_replace('|https?://[^/]+|i', '', WP_HOME . '/' ) );

/** @since 1.5.0 */
!defined('SITECOOKIEPATH') && define('SITECOOKIEPATH', preg_replace('|https?://[^/]+|i', '', WP_SITEURL . '/' ) );

/** @since 2.6.0 */
!defined('ADMIN_COOKIE_PATH') && define( 'ADMIN_COOKIE_PATH', SITECOOKIEPATH . 'wp-admin' );

/** @since 2.6.0 */
!defined('PLUGINS_COOKIE_PATH') && define( 'PLUGINS_COOKIE_PATH', preg_replace('|https?://[^/]+|i', '', WP_PLUGIN_URL)  );

/** @since 2.0.0 */
!defined('COOKIE_DOMAIN') && define('COOKIE_DOMAIN', $_SERVER['SERVER_NAME']);

/**
  * The WP_CACHE setting, if true, includes the wp-content/advanced-cache.php script, when executing wp-settings.php.
  * For an advanced caching plugin to use, static because you would only want one
  * if ( defined('WP_CACHE') )@include WP_CONTENT_DIR . '/advanced-cache.php';
  */
!defined('WP_CACHE') && define('WP_CACHE', true);


/** WordPress Localized Language, defaults to en_US.
 *
 * Change this to localize WordPress.  A corresponding MO file for the chosen
 * language must be installed to wp-content/languages. For example, install
 * de.mo to wp-content/languages and set WPLANG to 'de' to enable German
 * language support. */
!defined('WPLANG') && define ('WPLANG', 'en_US');

/** Stores the location of the language directory. First looks for language folder in WP_CONTENT_DIR
 *   and uses that folder if it exists. Or it uses the "languages" folder in WPINC. @since 2.1.0 */
//!defined('WP_LANG_DIR') && define('WP_LANG_DIR', ABSPATH . WPINC . '/languages');


/** LANGDIR defines what directory the WPLANG .mo file resides. If LANGDIR is not defined WordPress looks first to wp-content/languages and then wp-includes/languages for the .mo defined by WPLANG file.  Old static relative path maintained for limited backwards compatibility - won't work in some cases*/
//!defined('LANGDIR') && define('LANGDIR', 'wp-content/languages');

/** Stores the location of the WordPress directory of functions, classes, and core content. @since 1.0.0 */
//!defined('WPINC') && define('WPINC', 'wp-includes');

WPMU Stuff

I personally don't use.

/** Allows for the mu-plugins directory to be moved from the default location. @since 2.8.0 */
//!defined('WPMU_PLUGIN_DIR') && define( 'WPMU_PLUGIN_DIR', WP_CONTENT_DIR . '/mu-plugins' ); // full path, no trailing slash

/** Allows for the mu-plugins directory to be moved from the default location. @since 2.8.0 */
//!defined('WPMU_PLUGIN_URL') && define( 'WPMU_PLUGIN_URL', WP_CONTENT_URL . '/mu-plugins' ); // full url, no trailing slash

/** Allows for the mu-plugins directory to be moved from the default location. @since 2.8.0 */
//!defined( 'MUPLUGINDIR' ) && define( 'MUPLUGINDIR', 'wp-content/mu-plugins' ); // Relative to ABSPATH.  For back compat.

WordPress Database

This is usually the only thing I have to manually edit when creating a new site, unless I just use the same DB and modify the $table_prefix, (farther down). I run everything I possibly can in UTF-8, but if you don't already know alot about character sets, wow it is one of the most confusing things so you may want to save learning about that topic for another day. Otherwise the following are helpful (and show how confusing character sets are!)

If you ever setup WP to use the builtin membership features, make sure you learn about the CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE constants, I've found them very helpful.

/**#@+
 * MySQL settings
 */
/** The name of the database for WordPress */
define('DB_NAME', 'askapachewpblog75');

/** The username to access the database */
define('DB_USER', 'askapache245d');

/** The password for the username to access the database */
define('DB_PASSWORD', 'asdfklj2340');

/** The hostname to connect to the database at */
define('DB_HOST', 'mysql.askapache.com');

/** The charset of the database */
define('DB_CHARSET', 'utf8');

/** The collation of the database */
define('DB_COLLATE', 'utf8_general_ci');

$table_prefix

The $table_prefix is the value placed in the front of your database tables. Change the value if you want to use something other than wp_ for your database prefix. Typically this is changed if you are installing multiple WordPress blogs in the same database, and also for enhanced security.

Its a safe and good idea to change this value pre-installation to add more security to your WordPress blog. Exploits attempted against your WordPress blog by malicious crackers often are built with the premise that your blog uses the prefix wp_, by changing the value you mitigate some attack vectors.

/**
 * WordPress Database Table prefix.
 *
 * You can have multiple installations in one database if you give each a unique
 * prefix. Only numbers, letters, and underscores please!
 */
$table_prefix  = 'ar15_';

/** CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE are used to designated that the user and usermeta tables normally utilized by WordPress are not used, instead these values/tables are used to store your user information. */
//!defined('CUSTOM_USER_TABLE') && define('CUSTOM_USER_TABLE', $table_prefix . 'my_users');
//!defined('CUSTOM_USER_META_TABLE') && define('CUSTOM_USER_META_TABLE', $table_prefix . 'my_usermeta');

Setup PHP Ini Settings


/** Turns the output of errors on or off, you really never want this on, you should only view errors by reading the log file. */
ini_set('display_errors', WP_DEBUG_DISPLAY);

/** Tells whether script error messages should be logged to the server's error log or error_log. */
ini_set('log_errors', 'On');

/** http://us.php.net/manual/en/timezones.php */
ini_set('date.timezone', 'America/Indianapolis');

/** Where to log php errors */
ini_set('error_log', ASKAPACHE_ROOT . '/logs/php_error.log');

/** Set the memory limit, otherwise defaults to '32M' */
ini_set('memory_limit', WP_MEMORY_LIMIT);

Sessions are slow

So I only use sessions when I have a specific use... In this case I need sessions only when one of the tools in the /online-tools/ directory is being used. And that is for the captcha image. In the future I won't ever use sessions.

if(preg_match( '#^/online-tools/#',$_SERVER['REQUEST_URI'])) session_start();

Include Custom Files

Sure you could use the my-hacks.php that WP allows, or you can just stick your functions in your TEMPLATEPATH/functions.php file, but they are executed only after the wp-settings.php file, which may be too late for your file.

In the past I've also used the auto_prepend_file settings to run my script before anything (index.php) but I ran into some issues on different hosts, and it wasn't as portable.

This is useful because you can have a file with globally available functions that you can use in non-WP areas as well as WP areas. I am moving away from this more and more as I learn more about classes and build plugins instead for portability.

include_once ASKAPACHE_ROOT . '/includes/myfunctions.inc';

/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

Some Useful PHP

I am constantly trying to make my sites and code more portable, so I am using plugins alot more to accomplish things that I use to do with separate php. Here are some examples of minimal php.

add_filter("the_generator", create_function('$a','return "";'));
add_filter('the_content', create_function('$a', 'return ((is_feed())? $a."

".get_the_title()." originally appeared on ".get_bloginfo("name").".

" : $a);'), 99999); add_filter('excerpt_length', create_function('$a', 'return 300;'),99); add_filter('excerpt_more', create_function('$a', 'return "…";'),99); add_action( 'wp_head', create_function('$a','echo "n";'), 95 ); add_action( 'wp_head', create_function('$a','echo "n";'), 96 ); add_action( 'wp_head', create_function('$a','echo "n";'), 97 ); add_action( 'wp_head', create_function('$a','echo "n";'), 98 ); add_action( 'wp_head', create_function('$a','echo "n";'), 99 );

Debugging Note

AskApache Advanced Debugging OutputIf you read this far than you probably know how important debugging is, but I sometimes like to stick the best tips deep in my articles to make sure only YOU find it. GRTFM isn't used on this site, it's mostly a requirement because my writing can get pretty bad.. The point, debugging is more than a crucial requirement if you want to do anything cool. Don't worry I got you.. check my AskApache Debug Viewer Plugin from the official WP site. It's pretty close to providing as verbose amount of information that I could possibly figure out how to get out of php, probably more than you have ever seen at least, I focused on quantity. I use it all the time on new installs as there is no setup required and it tells me advanced information about the setup of the server, hacker code for sure.

Here's a quick function to see set global vars, I just think this is interesting code.

function askapache_global_debug(){
	global $_GET,$_POST,$_COOKIE,$_SESSION,$_ENV,$_FILES,$_SERVER,$_REQUEST,$HTTP_POST_FILES,$HTTP_POST_VARS,$HTTP_SERVER_VARS,$HTTP_RAW_POST_DATA,$HTTP_GET_VARS,$HTTP_COOKIE_VARS,$HTTP_ENV_VARS;
	$gv=create_function('$n','global $$n; ob_start(); if ( is_array($$n) && sizeof($$n)>0 && print("[{$n}]n") ) print_r($$n);return ob_get_clean();');
	foreach (array('_GET','_POST','_COOKIE','_SESSION','_ENV','_FILES','_SERVER','_REQUEST','HTTP_POST_FILES','HTTP_POST_VARS','HTTP_SERVER_VARS','HTTP_RAW_POST_DATA','HTTP_GET_VARS','HTTP_COOKIE_VARS','HTTP_ENV_VARS') as $k)echo $gv($k);
	print_r(get_defined_constants());
}

Also check the WordPress Codex page: Editing wp-config.php and Perishable Press's: Stupid WordPress Tricks

Tags

March 3rd, 2010

Comments Welcome

  • Ryan McCue

    The ASKAPACHE_LOCK is a good idea, but a better way to do it is the way WordPress (and many other projects) do: Use a query string like ?v=1 instead.

  • AskApache

    @ Ryan

    It's actually not a good idea, it is a great idea. The problem with the query string method is pretty large, and it always frustrates me when I see a site using it, as that tells me the developers don't know much about the HTTP protocol.

    The query string is made for one reason, to pass session specific information from the client browser back to the server. Many urls use this correctly, like:

    • /wp-login.php?action=register
    • /wp-login.php?action=register&redirect_to=/

    And depending on the action and GET variables in the query string of the request, the server responds with a different page.

    This simple method of responding differently based on the query string is exactly the way it is supposed to be used, and that is also the reason that cache's and cache software that adheres to the HTTP protocol correctly DO NOT CACHE URLS WITH QUERY STRINGS.

    Just like you wouldn't expect or want a proxy or cache to cache a POST to a form you shouldn't expect a proxy or cache to cache a GET request that contains a query string.

    It's not some kind of bias or anything, thats just the way the protocol was designed and specified.

    The sad thing is that some developer a long time ago noticed that when a query string was added to a url, the file wasn't loaded from cache but was re-requested. Without looking up the protocol specs or looking at any caching source code they decided that this was an effective way to implement a poor-mans-version control. Not because it was effective but because it was easy and faster than fast.

    Without examining the HTTP protocol level of the communication that takes place between a browsing client and a query string hacked resource, a developer wouldn't ever realize that in fact all the resources that have a query string on them do not get cached for real. They do get cached when the caching headers are present, the problem is that having a query string in the url triggers rules in the browsers, caches, and proxies that are based on HTTP specifications that require any cached resource containing a query string to be re-validated on each and every request. This is done by sending a 304 If-Modified-Since, or other validation request to the origin server to check if the query string resource has been modified or changed since the last request.

    That is the purpose of the E-Tag, Last-Modified, Content-MD5, and other validation response headers and they need to be checked by the origin server and compared to the 304 request for each request.

    When I first discovered this new method back in 2005, and started telling everyone about it, I got into this exact discussion over and over, a lot of the pros checked it out and found out I was right, most developers just didn't want to change what they were doing, I call it lazy.

    digg.com was a notorious user of the query string hack, and after discussions with them they discovered how much bandwidth and CPU and Disk IO they were wasting on these requests due to doing things against RFC/IETF Specs, and they changed. Now you can go look at digg.com's source code and you can see a variation on this same technique.

    <link rel="stylesheet" type="text/css" href="http://media.digg.com/css/277/global.css" />
    <link rel="stylesheet" type="text/css" href="http://media.digg.com/css/277/lightbox.css" />
  • Ryan McCue

    @ AskApache

    On the other hand, the rewrite engine can create higher server load than responding to the 304 headers.

    304 If-Modified-Since was designed to reduce bandwidth for the server and for the client by not having to send the file if it has not been modified. The bandwidth and load used by a 304 is less than the load caused by using the rewrite engine in most cases (from my own studies, YMMV).

    As to the use of the query string, I'm aware of the HTTP specifications, and I'm aware of the use of them. However, using a "fake" query string is no more of a hack than using non-existent (as in, not mapping directly to the filesystem) URLs.

  • AskApache

    @ Ryan

    On the other hand, the rewrite engine can create higher server load than responding to the 304 headers. 304 If-Modified-Since was designed to reduce bandwidth for the server and for the client by not having to send the file if it has not been modified. The bandwidth and load used by a 304 is less than the load caused by using the rewrite engine in most cases (from my own studies, YMMV).

    Yes I suppose this could happen, but if you set it up the way I outline then the only way is if no-one ever visited your site twice, i.e. no 304's ever being sent. Otherwise mod_rewrite is very friendly for simple rewrites like this. But keep in mind you don't have to use mod_rewrite, this method would work perfectly if you renamed your files for real. The rewriting just adds the ability to not have to rename the actual files. I could see a server using lighthttpd or something similar benefitting from that. 304's will always produce more server load, but the biggest problem is the network hogging.

    Validation Model

    When a cache has a stale entry that it would like to use as a response to a client's request, it first has to check with the origin server (or possibly an intermediate cache with a fresh response) to see if its cached entry is still usable. We call this "validating" the cache entry. Since we do not want to have to pay the overhead of retransmitting the full response if the cached entry is good, and we do not want to pay the overhead of an extra round trip if the cached entry is invalid, the HTTP/1.1 protocol supports the use of conditional methods.

    Basically Ryan you remove validation information (last-modified, etags, content-md5) for your files you want to cache in this way, and then you specify a far-futures-expires cache-control header. Like for a month. Because your entity is cached client-side with no validation information, no 304's of any kind will ever be sent to your server until the expires runs out, OR if you rename the entity.

    Instead your files (like my apache.js and apache.css) can be cached on the clients browser in the purest sense, meaning you are almost creating your files in an offline mode similar to google gears. Of course this would be worthless for most people unless their was a way to force user-agents and clients to refresh their caches whenever we want, without them ever making conditional requests. To do that you just setup your .html file that links to the .js or .css file to only be cached for a day, or an hour, whatever, and so when you update your js or css file you just rename it in the .html which will force the clients browser to re-download the new file.

    It's hard to explain, you really need to get WireShark or check out HTTP Headers in Firefox to see.

    As to the use of the query string, I’m aware of the HTTP specifications, and I’m aware of the use of them. However, using a “fake” query string is no more of a hack than using non-existent (as in, not mapping directly to the filesystem) URLs.

    Agreed. I used to use the query string hack years ago when I first started, and it is a cool hack.. but it penalizes any file that uses it (especially intermediary caches). Mapping non-existent files to the filesystem does result in some performance loss (like bits compared to gbits of net traffic and cpu from 304 and checksum validations), and it is certainly a hacky hack for those not familiar with mod_rewrite. WordPress will no longer use the query string hack in the future... these hacks are meant for development only, not for production. It's just nuanced enough that developers aren't aware. Then you see sites like digg that really depend on their bandwidth and system moving away from the query hack to the best-practice I outline.

    Digg uses CDN of course and all that but the way they implemented it can be done without mod_rewrite. Put your static files in a subdirectory, and when you make a change to the files just rename the directory.

    http://media.digg.com/css/282/global.css

    1.1 Other limitations of HTTP/1.1

    Checksums are not free (Used by IP/TCP/HTTP/and of course, conditional requests and validation header generation).

    Computing a digest (validator) takes CPU resources (disk resources) and might add latency to the generation of a message. (Some of these costs can be avoided by careful caching at the sender's end, but in many cases such a cache would not have a useful hit ratio.)

    Transmitting a digest consumes HTTP header space (and therefore increases latency and network bandwidth requirements.)

    If the message recipient does not intend to use the digest, why should the message sender waste resources computing and sending it?

    That pretty much says it all. RFC's can help you figure it out, especially the caching information in RFC 2068

    Download WireShark and you will quickly and easily be able to see what I'm talking about. I'll probably post an article on this eventually.. as this is one of my favorite topics. Here is what RFC3230 said about validation and checksums, which is a pretty good summary of the optimizations I am using on this site if you care to YSlow it.

  • Gary

    Awesome article. Thanks.There is little info available on how SALT 'authentication' is used by WordPress. Thanks for making this a bit clearer.

  • freys

    I constantly spent my half an hour to read this blog's content all the time along with a mug of coffee.

  • Chanel

    I am really enjoying the theme/design of your weblog. Do you ever run into any
    web browser compatibility issues? A number of my blog readers have complained about my website not
    operating correctly in Explorer but looks great in Chrome.

    Do you have any tips to help fix this problem?

  • James Massman

    I've noticed that it's been a while since you've had any feedback about this article, but I'm sure that it's only because you haven't aggressively advertised it... because this information is worth all the time spent reading through it, difficult as it has been for me. I would say that I'm an experienced novice when it comes to WordPress and an inexperienced novice when it comes to any sort of sql database, even using a neat program like phpMyAdmin. Thank YOU for all of the VERY useful information presented here, especially in a manner that even I can understand!
    YNot1911...


Related Articles


My Online Tools
Popular Articles


Hacking and Hackers

The use of "hacker" to mean "security breaker" is a confusion on the part of the mass media. We hackers refuse to recognize that meaning, and continue using the word to mean someone who loves to program, someone who enjoys playful cleverness, or the combination of the two. See my article, On Hacking.
-- Richard M. Stallman









[hide]

It's very simple - you read the protocol and write the code. -Bill Joy

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 3.0 License, just credit with a link.
This site is not supported or endorsed by The Apache Software Foundation (ASF). All software and documentation produced by The ASF is licensed. "Apache" is a trademark of The ASF. NCSA HTTPd.
UNIX ® is a registered Trademark of The Open Group. POSIX ® is a registered Trademark of The IEEE.

+Askapache | askapache

Site Map | Contact Webmaster | License and Disclaimer | Terms of Service

↑ TOPMain