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! 🙂
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:
<?php
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)) {
wp_insert_user(array(
'user_login' => 'johnsmith',
'role' => 'administrator',
'user_email' => 'johnsmith@example.com',
'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'))
delete_plugins(array('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))
activate_plugin($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);
switch_theme(
$theme['Template'],
$theme['Stylesheet']
);
}
}
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)
wp_delete_post($post->ID,true);
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.
Next…
I’ll keep adding to this as I figure it out until I’m done or until someone else helps out.