I am about to have to write a script to take a fresh install of WordPress 3.0.1 and add-in all the initial features for a website. This is for a company that installs lots of similar websites and they need a standard starting point in configuration and data.

  • I'm wondering if anyone else has already done this and if so if they can share their code?

I envision we will tweak this script each time they create a new site so hard-coding is fine although eventually (after enough experience) I'd like to convert into a plugin.

Here's the basic list of tasks I think we'll need (these assume I've started with WordPress 3.0.1 already installed and my custom plugins and custom theme copied into the appropriate directories):

// Create users for the current site
// Delete Hello Dolly Plugin
// Download, Install and Activate repository plugins
// Activate Custom Plugins (assume the plugins are already there)
// Activate Custom Theme
// Delete Hello Post
// Delete Comment on Hello Post
// Create Pages with Starter Content
// Create Initial Custom Post Types with Starter Content
// Create Multiple Menus 
// Create Menu Items for those Menus linking to Pages and wp-login.php
// Create Initial Taxonomy Terms
// Set Desired Permalinks Setting
// Set Static Front Page Setting

That's about it (though I may identify more as I get into it.)

Again, I'm looking for code that I can just copy and modify so I don't have don't have to figure out all these details myself (which is not hard, just tedious and time consuming).

Oh one more thing, I have to start on this now so the sooner the better! :-)

  • Could you clarify this one Create Menus for Custom Pages ? Do you mean individual menu areas on some pages or what?
    – Rarst
    Sep 13, 2010 at 7:27
  • Hi @Rarst: I need to create three menuseach with menu items that link to the Custom Pages I'll be adding (my use of "Custom" is probably confusing, I'll drop that word and just say "Pages.") So I need to add three menus and menu items for each where one of the menu items needs to link to the login page. Sep 13, 2010 at 7:39
  • Why delete the "Hello Dolly" plugin? I mean, I understand why you don't want it there, but its presence doesn't affect the operation of the site, and if you use the automatic upgrade function, it will be restored every time a new version is released.
    – Doug
    Sep 13, 2010 at 14:05
  • 2
    Hi @Doug: Why delete Hello Dolly? Simple answer: The client doesn't want it there. :) Sep 14, 2010 at 0:37

5 Answers 5


As I mentioned I was going to be start working on this need immediately so I'm making headway. Given that I'm knocking these down I figured it's best to start posting them. Still, if someone else can/will post (some of) the parts I haven't done I'll be happy to let you copy whatever I'd done you haven't and select your answer as the best answer. Until then I'm going to start posting the code.

First Thing: Include wp-load.php:

Since we're creating a standalone file in the root of the website to run initialization that will only be used to "bootstrap" a site (I called mine /my-init.php) we start by including /wp-load.php to load the WordPress API functions:

include "wp-load.php";

Creating Users for the Site

We'll use the wp_insert_user() function located in /wp-includes/registration.php to create our users. This file is not loaded by default so we'll have to load it ourselves with a call to require_once().

We'll also use the get_user_by() function to first see if the user has already been created; no need to run the code twice if they haven't. NOTE: This is a pattern will follow; e.g. our script should not duplicate or overwrite anything if called multiple times, especially after users have added or changed data for any of the items we plan to initialize.

require_once( ABSPATH . WPINC . '/registration.php');     
$user = get_user_by('slug','johnsmith');
if (!is_object($user)) {
    'user_login'        => 'johnsmith',
    'role'              => 'administrator',
    'user_email'        => '[email protected]',
    'user_url'          => 'http://example.com',
    'first_name'        => 'John',
    'last_name'         => 'Smith',
    'comment_shortcuts' => '',
    'use_ssl'           => '0',
    'user_pass'         => '12345',

Deleting the "Hello Dolly" Plugin

To delete the "Hello Dolly" plugin (sorry Matt) we'll use the delete_plugins() function. delete_plugins() expects an array of file paths that are relative to the /wp-content/includes/ directory. For the Hello Dolly plugin the file path is simply hello.php since the Hello Dolly plugin isn't stored in it's own directory but for most plugins it will be in the form of {$subdir}\{$filename}.php; i.e. the file path for Akismet is akismet/akismet.php.

However, delete_plugins() is not available until we've included /wp-admin/includes/plugin.php and there's also a dependency with wp-admin/includes/file.php so we require_once() both of those before we call delete_plugins(). Finally we use WP_PLUGIN_DIR constant combined with file_exists() to see if the main plugin file exists before we attempt to delete it (not that is would matter if we tried to delete a missing file, but it's more elegant to actually check first and you might need to know how for some other reason):

require_once(ABSPATH . 'wp-admin/includes/plugin.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
if (file_exists(WP_PLUGIN_DIR . '/hello.php'))

Note that sometimes delete_plugins() will fail because of file permissions or maybe the fact a plugin is currently activated or some other reason that you'll first need to resolve but for our use-case Hello Dolly goes away without a fight.

Downloading, Installing and Activating Repository Plugins

I don't actually need to download plugins from the repository right now (I was thinking it would just be a nice to have) we're going to let this requirement slide and revisit it later.

Activating Your Plugins

Next up is activating our own custom plugins. We are assuming we have already uploaded them to the plugin directory and all we need to do it activate them for WordPress. (Note: This technique will work for activating repository plugins too, it just won't download and install them first.)

We'll use the activate_plugin() function which like delete_plugins() requires /wp-admin/includes/plugin.php to be included but does not need /wp-admin/includes/file.php in case you are only needing to automate activation and not deletion.

We'll again test for existence (not need to activate if not there, eh?) and we'll also verify using the is_plugin_active() function that the plugin has not already been activated. Note I used a few variables this time ($plugin_filepath and $plugin_dir) to keep from duplicating the plugin identifier numerous times.

Our example that follows activates the plugin my-custom-plugin.php which is located in the my-custom-plugin subdirectory:

require_once(ABSPATH . 'wp-admin/includes/plugin.php');
$plugin_filepath = 'my-custom-plugin/my-custom-plugin.php';
$plugin_dir = WP_PLUGIN_DIR . "/{$plugin_filepath}";
if (file_exists($plugin_dir) && !is_plugin_active($plugin_filepath))

Activating Your Preferred Theme

Activating a theme is a bit easier than deleting or activating a plugin, comparatively speaking; one function call is all that is required: switch_theme(). The switch_theme() function accepts two (2) parameters: the template and the stylesheet. Well, at least that's what the parameters are named. You might be more familiar with the terms Parent Theme and Child Theme.

Assuming you've created a Child Theme with the default TwentyTen theme that comes with WordPress being the Parent Theme and you called it "My Custom Theme" and placed it into the /wp-content/themes/my-custom-theme directory, you'd activate your theme using this call:

switch_theme('twentyten', 'my-custom-theme');

But what if it is not a child theme? That's easy, just pass the directory slug/theme identifier (i.e. the name of subdirectory off of /wp-content/themes that contains your theme) as both parameters. Assuming you want to activate the Thematic theme by Ian D Stewart you've call switch_theme() like so:

switch_theme('thematic', 'thematic');

Personally I think it's a bit whacky to have to keep track of both details here so I wrote a function called activate_my_theme() that first checks to make sure the the get_current_theme() function and if not activates it. You just need to tell it the child theme (aka the "stylesheet") and it figures out the parent theme for you (aka the "template") by grabbing the details from the get_theme() function.

activate_my_theme('My Current Theme');
function activate_my_theme($theme_name) {
  if ($theme_name!=get_current_theme()) {
    $theme = get_theme($theme_name);

One key point to be aware of; the get_theme() function expects to be passed the name of the Child Theme, NOT it's directory slug/theme identifier. (The name comes from the "Theme Name:" section in the header of the theme's style.css file. Fortunately the get_current_theme() function returns the name too.)

Inspecting the header in the style.css file of the WordPress default theme Twenty Ten we see it's name is in fact 'Twenty Ten':

Theme Name: Twenty Ten
Theme URI: http://wordpress.org/
Description: The 2010 theme for WordPress is stylish, customizable, simple, and readable -- make it yours with a custom menu, header image, and background. Twenty Ten supports six widgetized areas (two in the sidebar, four in the footer) and featured images (thumbnails for gallery posts and custom header images for posts and pages). It includes stylesheets for print and the admin Visual Editor, special styles for posts in the "Asides" and "Gallery" categories, and has an optional one-column page template that removes the sidebar.
Author: the WordPress team
Version: 1.1
Tags: black, blue, white, two-columns, fixed-width, custom-header, custom-background, threaded-comments, sticky-post, translation-ready, microformats, rtl-language-support, editor-style

Deleting the "Hello World" Post

Next we want to delete the "Hello World" post. You may have seen that @Rarst has shown us how to use the wp_delete_post() function which is exactly what we need. As he explained the second parameter will fully delete the post as opposed to moving it to the trash and the first parameter is the $post->ID.

Of course it would be nice to be able to specify the slug instead of the $post->ID and so I decide to find a way to do that. After some spelunking I found that WordPress has an unfortunately named function called get_page_by_path() which actually allows us to look up any post type by its slug (it is unfortunately named because you might overlook it when trying to find something that works with post types other than 'page'.)

Since we passing get_page_by_path() the WordPress-defined constant OBJECT it will return to us a post in the form of an post object. For the third parameter we passed 'post' to indicate we wanted it to lookup post types of 'post'. Since get_page_by_path() will return the post object we need or return null if no post matches the slug we can check for existence and do a lookup at the same time:

$post = get_page_by_path('hello-world',OBJECT,'post');
if ($post)

Note: We could have run code to delete every post in the database but if we had we would not be able to run this code again once we've added the posts we want to keep and that was one of our design constraints.


I'll keep adding to this as I figure it out until I'm done or until someone else helps out.

  • This is really helpful, any chance of including the rest of the functionality on here?
    – jjeaton
    Oct 9, 2010 at 2:31
  • @jjeaton - Short answer: Yes, but.... Longer answer: It's going to be a few days if not weeks. I've done significant work on this problem since I last wrote here but my client is pushing to get a project finished and Im behind, so... if you can wait a little while I'll be posting it as soon as I can get the free time to write it up. BTW, what aspects are you most interest in? Oct 9, 2010 at 4:05
  • of course, no rush at all. I was thinking this question would be really valuable and so wanted to see the whole solution. I run several WordPress sites, and I'm always looking for ways to automate the repetitive maintenance I have to do on them (plugin updates, upgrades, etc.) so some of this is really valuable.
    – jjeaton
    Oct 15, 2010 at 16:20

Set Desired Permalinks

A new (awesome) theme project I came across this week that is heavily focused on HTML5/CSS3 functionality has it's own 'bootstrap' script to create some boilerplate content, incorporate permalink settings, set a relative root for the site install, etc. These features are called on theme activation. The project is called Roots and the code can be downloaded here ; I take no credit for this code. That said, here's the code to auto-set /year/postname as the permalink structure (and the activation hooks below for global $pagenow are explained here: http://foolswisdom.com/wp-activate-theme-actio/ . ).


    global $pagenow;
    if (is_admin() && 'themes.php' === $pagenow && isset( $_GET['activated'])) {

        // set the permalink structure
        if (get_option('permalink_structure') != '/%year%/%postname%/') { 
            update_option('permalink_structure', '/%year%/%postname%/');




  • Oh, there are plans to continue work on this question... But as many other plans they are on hold. :) I want to note that it is better to link to non-educational extensive third party code snippets, rather than post theme here. This site puts user contributions under cc-wiki license so it situation gets murky and confused when applied to code.
    – Rarst
    Apr 7, 2011 at 18:40
  • For sure, for sure. There is awesome progress here nonetheless. That's a great call on your suggestion, I've been around the Stack Exchange block a time or two but never thought about the licensing implications. I edited my code down and the rest of the code is easily obtained at the links I provided. Thanks for the the tip :)
    – user4443
    Apr 7, 2011 at 19:05

Delete Hello Post (with comment)

wp_delete_post( 1, true );

Straight from wp_delete_post() docs. Second parameter nukes it completely, instead of moving to trash.

Create menus

This creates new menu and adds all existing pages as items to it. I am not sure it is entirely correct, I was unable to get menu items to show Page label among other things. Anyway my brain is melting so I am taking a break. Maybe someone will be able to upgrade this to something more reliable.

$menu = wp_create_nav_menu( 'Pages' );
$menu = wp_get_nav_menu_object( 'Pages' );
$pages = get_pages();

foreach( $pages as $page ) {

$item = array(
'menu-item-db-id' => 0,
'menu-item-object-id' => $page->ID,
'menu-item-type' => 'post_type',
'menu-item-status' => 'publish'

wp_update_nav_menu_item( $menu->term_id, 0, $item );
  • Hi @Rarst: Thanks for commenting. Ah, you took the easy one... ;-) I was just coming back to write that one up. Sep 13, 2010 at 7:36
  • @MikeSchinkel Anything you are not writing right now? It would be a waste to dive into the menus code (it's scary) to come with result and find it is done already. :)
    – Rarst
    Sep 13, 2010 at 7:44
  • Hi @Rarst! Start at the end of the list? (thanks in advance.) Sep 13, 2010 at 7:54
  • Ok, I will try to handle Menus, but no promises. That code is complex inside (price of eye candy and usability) so I am not confident my skills are up to it.
    – Rarst
    Sep 13, 2010 at 8:00
  • Hey @Rarst - I pretty much got it all working but it'll probably be another 24 hours or so before I can finish my answer. Just wanted to let you know so you didn't kill yourself trying to get it to work. Thanks for the effort. Sep 13, 2010 at 11:00

If i understand it well, you want it for inital instalation - then i am affraid your approach is totally wrong.

Far better, easier and standardised way is to create install.php and put it in wp-content folder - it is automaticaly loaded during installation.

There you can put your own wp_install function (as the wordpress own function uses if (!function_exist) ) so there you can easily setup your options, activate plugins, fill initial posts, categories, tags, users ...

The second option may be for situation, where you want to clear the allready existing wp (e.g. for demo version set up every e.g. 30 minutes using cron) - you can a) trunctate database and use procedure above, or create the plugin who do the same.

  • 2
    @Thomas Kapler - Thanks for your answer but I beg to differ; my approach is not "totally wrong." First, what I discuss is the same code that you would use in install.php, and second there are other use cases where install.php is not applicable. Yes, install.php has it's use but it doesn't take care of the details nor is to the panacea you imply it to be. Feb 18, 2011 at 4:25

Have a look at this install script. https://github.com/Pravdomil/WP-Quick-Install

I take your ideas and some code and create something what you probably searching for.

Features are setup database, different languages, create users, set basic site settings, delete default plugins and templates, download install and activate plugins and themes, default avatar, permalinks, static front page.

Fell free to contribute.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.