beyond the wordpress 5 minute install
DESCRIPTION
The slides for the talk I gave at WordCamp Portsmouth UK 2011, 16/7/11. It basically covers some security and best practices hints and tips that aren't part of the standard WordPress installation.TRANSCRIPT
Beyond the 5-minute InstallSteve Taylor
http://[email protected]@sltayloresque
WordCamp Portsmouth UK 2011
Security & best practices
● .htaccess
● wp-config.php
● robots.txt
● functions.php / “functionality plugin”
● Plugins
● Other issues?
A bit about me● Custom theme developer
● No themes released
● A few plugins
This talk● Advice for beginners
● Tips for developers
.htaccess
● “hypertext access”
● Controls requests to server before any PHP / WordPress processing
● Apache only (IIS?)
● Root of website (sub-directories?)
● Sometimes simple, sometimes complex!
http://httpd.apache.org/docs/
http://perishablepress.com/press/2006/01/10/stupid-htaccess-tricks/
www or not www?
● Personal choice / aesthetics
● Both should be accessible; one should redirect (301) to the other
● Tell Google Webmaster Tools!
www or not www?
# Force no “www”RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
● Personal choice / aesthetics
● Both should be accessible; one should redirect (301) to the other
● Tell Google Webmaster Tools!
www or not www?
# Force no “www”RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
● Personal choice / aesthetics
● Both should be accessible; one should redirect (301) to the other
● Tell Google Webmaster Tools!
# Force “www”RewriteCond %{HTTP_HOST} ^example\.com$ [NC]RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
Protect important files
●# Protect .htaccess files<Files .htaccess>
order allow,denydeny from all
</Files>
●# Protect wp-config.php<Files wp-config.php>
order allow,denydeny from all
</FilesMatch>
WordPress pretty permalinks
WordPress pretty permalinks
●# BEGIN WordPress<IfModule mod_rewrite.c>RewriteEngine OnRewriteBase /RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule . /index.php [L]</IfModule># END WordPress
Include at end of .htaccess:
WordPress pretty permalinks
Really bad idea for big sites:
WordPress pretty permalinks
Really bad idea for big sites:
http://ottopress.com/2010/category-in-permalinks-considered-harmful/
http://codex.wordpress.org/Using_Permalinks
Better:
wp-config.php
● Create your own wp-config-sample.php
● Check the file for new stuff in new versions of WordPress
● Edit and initialize BEFORE installing WordPress!
http://codex.wordpress.org/Editing_wp-config.php
http://digwp.com/2010/08/pimp-your-wp-config-php/
Server-dependent settings
●// ** MySQL settings - You can get this info from your web host ** ///** The name of the database for WordPress */define('DB_NAME', 'database_name_here');
●/** MySQL database username */define('DB_USER', 'username_here');
●/** MySQL database password */define('DB_PASSWORD', 'password_here');
●/** MySQL hostname */define('DB_HOST', 'localhost');
Server-dependent settings
●switch ( $_SERVER['HTTP_HOST'] ) {case 'dev.example.com': {
// Dev serverdefine( 'DB_NAME', 'aef4RgX_mysitedev' );define( 'DB_USER', 'aef4RgX_mysitedev' );define( 'DB_PASSWORD', 'Jyt6v48jS9frkGgZyS5iIjif6LnosuYr' );define( 'DB_HOST', 'localhost' );break;
}default: {
// Live serverdefine( 'DB_NAME', 'sd6FE2xc_mysitelive' );define( 'DB_USER', 'sd6FE2xc_mysitelive' );define( 'DB_PASSWORD', 'as3d56JvDlPisYwU7c1nfZ3Yct0NEiZR' );define( 'DB_HOST', 'localhost' );break;
}}
https://www.grc.com/passwords.htm
Authentication Keys and Salts
define('AUTH_KEY', 'put your unique phrase here');define('SECURE_AUTH_KEY', 'put your unique phrase here');define('LOGGED_IN_KEY', 'put your unique phrase here');define('NONCE_KEY', 'put your unique phrase here');define('AUTH_SALT', 'put your unique phrase here');define('SECURE_AUTH_SALT', 'put your unique phrase here');define('LOGGED_IN_SALT', 'put your unique phrase here');define('NONCE_SALT', 'put your unique phrase here');
https://api.wordpress.org/secret-key/1.1/salt/
Change them for every installation!
Database table prefix
$table_prefix = 'wp_';
The default:
Database table prefix
$table_prefix = 'wp_';
$table_prefix = 'a3rfGtQ1_';
The default:
Much better:
Database table prefix
When coding database queries, don’t use hard-coded table names!
Database table prefix
global $wpdb;$custom_query = $wpdb->get_results( “SELECT ID, post_title FROM
$wpdb->posts” );
When coding database queries, don’t use hard-coded table names!
A standard WP table:
Database table prefix
global $wpdb;$custom_query = $wpdb->get_results( “SELECT ID, post_title FROM
$wpdb->posts” );
When coding database queries, don’t use hard-coded table names!
A standard WP table:
http://codex.wordpress.org/Class_Reference/wpdb
global $wpdb;$custom_query = $wpdb->get_results( “SELECT field FROM ” .
$wpdb->prefix . “table” );
A custom table:
Server needs FTP for upgrades?
define( "FTP_HOST", "ftp.example.com" );define( "FTP_USER", "myftpuser" );define( "FTP_PASS", "hQfsSITtKteo1Ln2FEhHlPkXZ" );
Debugging
define( 'WP_DEBUG', true );
Debugging
define( 'WP_DEBUG', true );
●switch ( $_SERVER['HTTP_HOST'] ) {case 'dev.example.com': {
// Dev serverdefine( 'WP_DEBUG', isset( $_GET['debug'] ) );break;
}default: {
// Live serverdefine( 'WP_DEBUG', false );break;
}}
http://dev.example.com/?debug=1
Control revisions and autosave
// Only keep 3 revisions of each postdefine( 'WP_POST_REVISIONS', 3 );
Control revisions and autosave
// Only keep 3 revisions of each postdefine( 'WP_POST_REVISIONS', 3 );
// Don’t keep revisions of postsdefine( 'WP_POST_REVISIONS', false );
Control revisions and autosave
// Autosave posts interval in secondsdefine( 'AUTOSAVE_INTERVAL', 60 );
// Only keep 3 revisions of each postdefine( 'WP_POST_REVISIONS', 3 );
// Don’t keep revisions of postsdefine( 'WP_POST_REVISIONS', false );
Disable plugin and theme editing
define( 'DISALLOW_FILE_EDIT', true );
robots.txt
http://codex.wordpress.org/Search_Engine_Optimization_for_WordPress#Robots.txt_Optimization
User-agent: *Disallow: /wp-adminDisallow: /wp-includesDisallow: /wp-content/pluginsDisallow: /wp-content/cacheDisallow: /wp-content/themesDisallow: /trackbackDisallow: /feedDisallow: /commentsDisallow: /category/*/*Disallow: */trackbackDisallow: */feedDisallow: */commentsDisallow: /*?*Disallow: /*?Allow: /wp-content/uploads
Sitemap: http://example.com/sitemap.xml
Custom theme functions.php / “functionality” plugin
● Snippets not worth making into a plugin
● Plugin is more portable
● Check out /mu-plugins/
http://justintadlock.com/archives/2011/02/02/creating-a-custom-functions-plugin-for-end-users
http://wpcandy.com/teaches/how-to-create-a-functionality-plugin
http://codex.wordpress.org/Must_Use_Plugins
Disable upgrade notifications for people who can't do upgrades
if ( ! current_user_can( 'update_core' ) ) {add_action( 'init', create_function( '$a', "remove_action( 'init',
'wp_version_check' );" ), 2 );add_filter( 'pre_option_update_core', create_function( '$a', "return
null;" ) );}
Remove nofollow from comments
remove_filter( 'pre_comment_content', 'wp_rel_nofollow' );add_filter( 'get_comment_author_link', 'slt_dofollow' );add_filter( 'post_comments_link', 'slt_dofollow' );add_filter( 'comment_reply_link', 'slt_dofollow' );add_filter( 'comment_text', 'slt_dofollow' );function slt_dofollow( $str ) {
$str = preg_replace('~<a ([^>]*)\s*(["|\']{1}\w*)\s*nofollow([^>]*)>~U','<a ${1}${2}${3}>', $str );
return str_replace( array( ' rel=""', " rel=''" ), '', $str );}
}
http://digwp.com/2010/04/wordpress-custom-functions-php-template-part-2/
Better default display names
add_action( 'user_register', 'slt_default_user_display_name' );function slt_default_user_display_name( $user_id ) {
$first = get_usermeta( $user_id, 'first_name' );$last = get_usermeta( $user_id, 'last_name' );$display = $first . " " . $last;wp_update_user( array( "ID" => $user_id, "display_name" => $display )
);}
Plugins
Force Strong Passwords. Copies WordPress's JavaScript password strength meter into PHP and forces “executive” users to have a strong password when updating their profile.http://wordpress.org/extend/plugins/force-strong-passwords/
Google XML Sitemaps (or equivalent).http://wordpress.org/extend/plugins/google-sitemap-generator/
Use Google Libraries.http://wordpress.org/extend/plugins/use-google-libraries/
WordPress Database Backup.http://wordpress.org/extend/plugins/wp-db-backup/
Other issues
● File permissionshttp://codex.wordpress.org/Hardening_WordPress#File_permissions
● .htpasswd for /wp-admin/
● Settings > Discussion