Customizing the WordPress Install Process with install.php

I came across a super interesting post at WPBits about automating the wordpress installation process.  Some of the parts about where some of the functions are located in WP that allow you to change certain things on the installation are outdated since the post is from 2007, but the concept remains perfectly intact.  If you find yourself installing a lot of WordPress blogs and are tired of always having to delete the “This is your First Post” post, changing the permalinks etc. then you can take advantage of this little trick.

Trolling the Source Code Like a Boss

If you are cruising through source (because there is plenty of stuff that isn’t well documented yet in the Codex) you will see


/** Include user install customize script. */
if ( file_exists(WP_CONTENT_DIR . '/install.php') )
 require (WP_CONTENT_DIR . '/install.php');

in /wp-admin/includes/upgrade.php.  Now this is interesting because it means that when WordPress installs (or upgrades) it will look for a file called install.php in your /wp-content folder… or whatever you are using instead of the default /wp-content folder.  This file doesn’t exist by default but it gives you a chance to run some functions of your own during the installation process (since  /wp-admin/includes/upgrade.php is required by /wp-admin/install.php)

My First CuSTOM INSTALL.PHP

I followed WPBit’s example and decided to show off my new power over WordPress by putting the following into my custom /wp-content/install.php file.


No Bacon for You

<br/>Evil Superpowers

<?php exit();?>

This obviously isn’t helpful, but it is a good proof of concept and let’s you know that you have all the power.  Of course…

With great power comes great responsibility. – Uncle Ben

Functions We Can Hijack for Our Own Purposes

As WPBits explains in more detail, some of the ideal functions to tweak would be:

  • wp_install()
  • wp_install_defaults()
  • wp_new_blog_notification()
  • wp_upgrade()

All of these functions are now (currently version 3.3.1) in /wp-admin/includes/upgrade.php and they are pluggable, meaning they come with an if(function_exists()) wrapper that lets you define your own versions to override their behavior.

Since wp_install_defaults() is the culprit for creating those useless “first post” posts and pages, we’re going to target it.  I copied the entire function to my own file: /wp-content/install.php and then hacked out all the parts that inserted the first post, first page, the default links in the blogroll (sorry WordPress), and changed the default category from Uncategorized to General.  You can also adjust the widgets that are activated by default, but I thought that was going too far.

I also wanted to change some options, like permalinks, time zone, size of the post editor, banning emoticons, etc.  So I added a bunch of update_option() commands.  Just because I thought it’d be super clever, I updated the ping list, moderate and blacklist comment terms from text files by using file_get_contents().

Automagically Creating Myself as an Admin

I usually install WP for someone else, I decided that I wanted to create my client’s account on install and automatically create my own admin account.  I might reverse this process as I don’t like how the install’s welcome email doesn’t include a link to the login screen.  I know that you just tack on wp-login.php but a newbie client might not.  At the same time, the way I have it means I never have to change my credentials in the file… which I prefer for now.

Anyway, I initially overrode the default wp_install() file to do this, by repeating the process of copying the function from /wp-admin/includes/upgrade.php to my own install.php, but it turns out that I can just create a new user from the function I already have.  In that case, I decided to only override one core function.

Here’s the code I used.  Remember to use it at your own risk.  This is really targeted at people who know what they are doing with WordPress and are installing it on a regular basis.  Take note to change the username and email address for the account you are creating for yourself… currently they are left as USERNAME and YOU@YOUREMAIL.COM.  Right now it generates a random password, but that could easily be changed to always assign yourself the same password.

<?php

/**
 * Override Default Installation Content
 * do not create empty page, first test post, default links, default comment, etc
 */
function wp_install_defaults($user_id) {
 global $wpdb, $wp_rewrite, $current_site, $table_prefix;

 /*
 * BEGIN KIA TWEAKS
 * Customize Some Options
 */

 // Set Timezone

 //$timezone = "America/New_York";
 $timezone = "America/Chicago";
 //$timezone = "America/Denver";
 //$timezone = "America/Los_Angeles";

 update_option('timezone_string',$timezone);

 // Start of the Week
 update_option('start_of_week',0); //0 is Sunday, 1 is Monday and so on

 // Disable Smilies
 update_option('use_smilies', 0);

 // Increase the Size of the Post Editor
 update_option('default_post_edit_rows',40);

 // Update Ping Services
 // http://mrjimhudson.com/wordpress-update-services-use-a-larger-ping-list/
 if ( file_exists(WP_CONTENT_DIR . '/KIA-ping-list.txt') ) {
 $services = file_get_contents('KIA-ping-list.txt', true);
 update_option('ping_sites',$services);
 }

 // Update Comment Moderation List
 // http://perishablepress.com/wordpress-blacklist-characters/
 if ( file_exists(WP_CONTENT_DIR . '/KIA-comment-moderation-list.txt') ) {
 $modlist = file_get_contents('KIA-comment-moderation-list.txt', true);
 update_option('moderation_keys',$modlist);
 }

 // Update Comment Blacklist
 // http://www.pureblogging.com/2008/04/29/create-a-comment-blacklist-in-wordpress-download-my-list-of-spam-words/
 if ( file_exists(WP_CONTENT_DIR . '/KIA-comment-blacklist.txt') ) {
 $blacklist = file_get_contents('KIA-comment-blacklist.txt', true);
 update_option('blacklist_keys',$blacklist);
 }

 // Don't Organize Uploads by Date
 update_option('uploads_use_yearmonth_folders',0);

 // Update Permalinks
 update_option('selection','custom');
 update_option('permalink_structure','/%post_id%/%postname%/');
 $wp_rewrite->flush_rules();

 // Default category
 $cat_name = __('General');
 /* translators: Default category slug */
 $cat_slug = sanitize_title(_x('General', 'Default category slug'));

 /*
 * Create Self as Admin User. If the user already exists, the user tables are
 * being shared among blogs. Just set the role in that case.
 */
 $self_id = username_exists('USERNAME');
 if ( !$self_id ) {
 $self_password = wp_generate_password( 12, false );
 $self_id = wp_create_user('USERNAME', $user_password, 'YOU@YOUREMAIL.COM');
 update_user_option($self_id, 'default_password_nag', true, true);
 wp_new_user_notification( $self_id, $self_password );
 }

$self = new WP_User($self_id);
 $self->set_role('administrator');

 /*
 * END KIA TWEAKS
 */

 /*
 * END KIA TWEAKS
 */

if ( global_terms_enabled() ) {
 $cat_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM {$wpdb->sitecategories} WHERE category_nicename = %s", $cat_slug ) );
 if ( $cat_id == null ) {
 $wpdb->insert( $wpdb->sitecategories, array('cat_ID' => 0, 'cat_name' => $cat_name, 'category_nicename' => $cat_slug, 'last_updated' => current_time('mysql', true)) );
 $cat_id = $wpdb->insert_id;
 }
 update_option('default_category', $cat_id);
 } else {
 $cat_id = 1;
 }

$wpdb->insert( $wpdb->terms, array('term_id' => $cat_id, 'name' => $cat_name, 'slug' => $cat_slug, 'term_group' => 0) );
 $wpdb->insert( $wpdb->term_taxonomy, array('term_id' => $cat_id, 'taxonomy' => 'category', 'description' => '', 'parent' => 0, 'count' => 1));
 $cat_tt_id = $wpdb->insert_id;

// Default link category
 $cat_name = __('Blogroll');
 /* translators: Default link category slug */
 $cat_slug = sanitize_title(_x('Blogroll', 'Default link category slug'));

if ( global_terms_enabled() ) {
 $blogroll_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM {$wpdb->sitecategories} WHERE category_nicename = %s", $cat_slug ) );
 if ( $blogroll_id == null ) {
 $wpdb->insert( $wpdb->sitecategories, array('cat_ID' => 0, 'cat_name' => $cat_name, 'category_nicename' => $cat_slug, 'last_updated' => current_time('mysql', true)) );
 $blogroll_id = $wpdb->insert_id;
 }
 update_option('default_link_category', $blogroll_id);
 } else {
 $blogroll_id = 2;
 }

$wpdb->insert( $wpdb->terms, array('term_id' => $blogroll_id, 'name' => $cat_name, 'slug' => $cat_slug, 'term_group' => 0) );
 $wpdb->insert( $wpdb->term_taxonomy, array('term_id' => $blogroll_id, 'taxonomy' => 'link_category', 'description' => '', 'parent' => 0, 'count' => 7));
 $blogroll_tt_id = $wpdb->insert_id;

// Set up default widgets for default theme.
 update_option( 'widget_search', array ( 2 => array ( 'title' => '' ), '_multiwidget' => 1 ) );
 update_option( 'widget_recent-posts', array ( 2 => array ( 'title' => '', 'number' => 5 ), '_multiwidget' => 1 ) );
 update_option( 'widget_recent-comments', array ( 2 => array ( 'title' => '', 'number' => 5 ), '_multiwidget' => 1 ) );
 update_option( 'widget_archives', array ( 2 => array ( 'title' => '', 'count' => 0, 'dropdown' => 0 ), '_multiwidget' => 1 ) );
 update_option( 'widget_categories', array ( 2 => array ( 'title' => '', 'count' => 0, 'hierarchical' => 0, 'dropdown' => 0 ), '_multiwidget' => 1 ) );
 update_option( 'widget_meta', array ( 2 => array ( 'title' => '' ), '_multiwidget' => 1 ) );

 update_option( 'sidebars_widgets', array ( 'wp_inactive_widgets' => array ( ), 'sidebar-1' => array ( 0 => 'search-2', 1 => 'recent-posts-2', 2 => 'recent-comments-2', 3 => 'archives-2', 4 => 'categories-2', 5 => 'meta-2',), 'sidebar-2' => array ( ), 'sidebar-3' => array ( ), 'sidebar-4' => array ( ), 'sidebar-5' => array ( ), 'array_version' => 3 ) );

if ( ! is_multisite() )
 update_user_meta( $user_id, 'show_welcome_panel', 1 );
 elseif ( ! is_super_admin( $user_id ) && ! metadata_exists( 'user', $user_id, 'show_welcome_panel' ) )
 update_user_meta( $user_id, 'show_welcome_panel', 2 );

if ( is_multisite() ) {
 // Flush rules to pick up the new page.
 $wp_rewrite->init();
 $wp_rewrite->flush_rules();

$user = new WP_User($user_id);
 $wpdb->update( $wpdb->options, array('option_value' => $user->user_email), array('option_name' => 'admin_email') );

// Remove all perms except for the login user.
 $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id != %d AND meta_key = %s", $user_id, $table_prefix.'user_level') );
 $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id != %d AND meta_key = %s", $user_id, $table_prefix.'capabilities') );

// Delete any caps that snuck into the previously active blog. (Hardcoded to blog 1 for now.) TODO: Get previous_blog_id.
 if ( !is_super_admin( $user_id ) && $user_id != 1 )
 $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $wpdb->base_prefix.'1_capabilities') );
 }
}

I don’t keep this file live on the server, but I suppose you could if you dropped an .htaccess file into the /wp-content folder and banned access to your custom install.php file


<Files install.php>
 Order Allow,Deny
 Deny from all
</Files>

That about sums it all up.  Let me know what cool jedi tricks you are doing with your custom install.php file!

Downloads

Download696 downloads
//rename from install.php2 to install.php
Download1299 downloads
 (source: mrjimhudson.com )
Download533 downloads
 (source: perishablepress.com )
Download615 downloads
 (source: pureblogging.com )

 

This entry was posted in Tutorial and tagged , , . Bookmark the permalink. Trackbacks are closed, but you can post a comment.

11 Comments

  1. Posted January 28, 2012 at 4:19 am | Permalink

    Awesome indeed. We just ordered Thrice Cooked Bacon from Mission Chinese here in San Francisco. Rice cakes, bitter melon, tofu skin, scallion, black bean and chili oil. Lots of chili oil. Its super good. If you ever come here we will treat you, for all your good work. :)

  2. Posted February 1, 2012 at 5:47 pm | Permalink

    This is something I discovered not too long ago. It really comes in handy for those of us that install a lot of WordPress sites with the same settings.

    I created a tool at http://wpkgr.com/ that will download and enable a theme and plugins as well during the install. The install.php file could be edited more to add the customizations described in this blog post.

    Thanks for sharing your code!

  3. Julien
    Posted February 13, 2012 at 8:51 am | Permalink

    You might want to have a look at the new WordPress Command line interface : https://github.com/andreascreten/wp-cli

    It’s pretty powerful. Not sure if it will expose every setting you want (I’ve only just started using it), but it might end up being more maintainable. Let me know if it’s helpful!

  4. kathy
    Posted February 13, 2012 at 12:58 pm | Permalink

    @Leslie thrice-cooked bacon? swoon? i don’t really eat a lot of bacon, but it is very delicious, makes vegetables taste better and is the perfect dummy content for WordPress testing. It’s a triple threat.

    @Raymond nice work! i don’t actually do this ‘that’ often, but still… it is annoying to do the same things to every site.

    @Julien that’s pretty cool. i’ll have to check it out even though i usually think command line is too geeky even for me. ;)

  5. lin0r
    Posted December 5, 2012 at 12:23 pm | Permalink

    hi kathy!
    thanx for this summary! do you know wpkgr.com? they are providing an automatically generated index.php to include extensions (include means download actual version, install, activate)! but they don’t offer a possibility to add your own settings, as you did here.
    do you see any chance to include that function (include standard-extensions you’re using for every WP-install) into your index.php? i’m not really good in php… :(
    that would be very helpful!!
    thanx a lot for an anwser and lots of greetings from munich, bavaria, germany!

    • Posted December 5, 2012 at 1:45 pm | Permalink

      @lin0r wpkgr.com is offering something a little different. They are bundling the plugin files into the WordPress .zip file (if I understand correctly). I’m only customizing options with a custom install.php. Though if you add a custom install.php to their custom .zip file you can probably achieve what you are looking for…. I think you could activate a plugin from the install.php, I’ve never tried. Let me know if you figure it out. thanks for stopping by.

      • lin0r
        Posted December 5, 2012 at 2:06 pm | Permalink

        hi again :)
        thanks a lot for your answer, and sorry for bothering you again… but what they do is just generating an “install.php” file which is doing the rest. the instruction there are:

        - Choose plugins and theme
        - Create pkg file (pkg-file is really just the install.php – i tried that)
        - Place file in ‘wp-content/’
        - Run WordPress install as usual (wp-admin/install.php)
        Selected theme & plugins are automatically downloaded, unzipped, and activated during WordPress installation.

        i guess thats exactly what you’re doing for the custom settings. that’s why i thought you could help me with that, if you look at the output-install.php-file – if thats not too much trouble for you. would be a gr8 help for me and a perfect addition for your post. i would love to do it myself, but my knowledge of php is really poor :-)

        • Posted December 5, 2012 at 2:13 pm | Permalink

          @Linor – I’m not bothered in the least. It would be a cool addition, but I just can’t provide free support in the comments. Sorry. If you’re interested in hiring me, please send an email via my contact page.

  6. Posted February 10, 2013 at 1:54 am | Permalink

    Thanks Katy for sharing this !!!

    • Posted February 10, 2013 at 2:35 am | Permalink

      Je t’en pris! tu est vraiment français… d’écrire mon nom sans “h”. :) j’éspère que mon article t’a aidé dans qq façon.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

This site's anti-spam requires Javascript; enable it and refresh this page to continue.

NoScript Users: Whitelist the domain services.wpspamhammer.com and refresh.