I sometimes run scripts from the command line and still need WordPress functionality and the regular WordPress environment. Here’s a very basic script that I usually use as a structure for this kind of actions.
<?php
/**
* Dummy CLI script that loads the WordPress environment
* Author: Thorsten Ott
* Author URI: http://hitchhackerguide.com
*/
set_time_limit( 0 );
ini_set( "memory_limit", "64M" );
$_SERVER['HTTP_HOST'] = 'wp_trunk'; // set this to the apache vhost name of your WordPress install
ob_start();
require_once( dirname( __FILE__ ) . '/wp-load.php' ); // you need to adjust this to your path
require_once( ABSPATH . 'wp-admin/includes/admin.php' );
ob_end_clean();
$cli_script = new WordPress_CLI;
$cli_script->set_required_arg( 'blog_id', 'blog_id of blog to use' );
$cli_script->set_required_arg( 'action', 'what shall I do' );
$cli_script->set_argument_validation( '#^blog_id$#', 'cli_init_blog', 'blog_id invalid' );
$cli_script->init();
abstract class WordPress_CLI_Factory {
public $args;
private $validate_args = array();
private $required_args = array();
public function __construct() {
$this->args = $this->get_cli_arguments();
}
public function init() {
if ( !$this->validate_args() )
exit;
$this->dispatch();
}
abstract function dispatch();
public function set_required_arg( $name, $description='' ) {
$this->required_args[$name] = $description;
}
public function set_argument_validation( $name_match, $value_match, $description='argument validation error' ) {
$this->validate_args[] = array( 'name_match' => $name_match, 'value_match' => $value_match, 'description' => $description );
}
private function validate_args() {
$result = true;
if ( empty( $this->args ) && !empty( $this->required_args ) ) {
$this->show_help();
$result = false;
} else {
foreach( $this->required_args as $name => $description ) {
if ( !isset( $this->args->$name) ) {
$this->raise_required_argument_error( $name, $description );
$result = false;
}
}
}
foreach( $this->validate_args as $validator ) {
foreach( $this->args as $name => $value ) {
$name_match_result = preg_match( $validator['name_match'], $name );
if ( ! $name_match_result ) {
continue;
} else {
$value_match_result = $this->dispatch_argument_validator( $validator['value_match'], $value );
if ( ! $value_match_result ) {
$this->raise_argument_error( $name, $value, $validator );
$result = false;
continue;
}
}
}
}
return $result;
}
private function dispatch_argument_validator( $match, $value ) {
$match_result = false;
if ( is_callable( array( &$this, $match ) ) ) {
$_match_result = call_user_func( array( &$this, $match ), $value );
} else if ( is_callable( $match ) ) {
$_match_result = call_user_func( $match, $value );
} else {
$_match_result = preg_match( $match, $value );
}
return $_match_result;
}
private function raise_argument_error( $name, $value, $validator ) {
printf( "Validation of %s with value %s failed: %s\n", $name, $value, $validator['description'] );
}
private function raise_required_argument_error( $name, $description ) {
printf( "Argument %s is required: %s\n", $name, $description );
}
private function show_help() {
printf( "Please provide the following arguments: %s\n", print_r( $this->required_args, true ) );
}
private function cli_init_blog( $value ) {
$blog_address = get_blogaddress_by_id( (int) $value );
if ( $blog_address == 'http://' )
return false;
switch_to_blog( (int) $value );
return true;
}
private function get_cli_arguments() {
$_ARG = new StdClass;
$argv = $_SERVER['argv'];
array_shift( $argv );
foreach ( $argv as $arg ) {
if ( preg_match( '#--([^=]+)=(.*)#', $arg, $reg ) )
$_ARG->$reg[1] = $reg[2];
elseif( preg_match( '#-([a-zA-Z0-9])#', $arg, $reg ) )
$_ARG->$reg[1] = 'true';
}
return $_ARG;
}
}
class WordPress_CLI extends WordPress_CLI_Factory {
public function dispatch() {
print_r( get_bloginfo() );
}
}

July 22, 2011 


Nice one!
I want to run a script by real cron (WordPress cron is too unreliable). In this script I’ll be using $wpdb to insert data into WordPress tables.
I believe I can use your script!
That’s exactly what this can be used for π Feel fry to try it out and send me some feedback after this.
This is great and all, but there’s no documentation. It’s a fairly sophisticated script to try to parse manually. I think this could find a lot of use for WPcom / VIP, but its operation is very opaque.
1) This only works in a multi-site environment. It fails silently outside of one, or if HTTP_HOST is not set correctly.
2) What is the action parameter for? It’s required, but how do I tell what valid options are?
Hi Ben, this was more meant as a snippet to build upon not as a ready solution. The action parameter is just an example for further implementations and could be used to determine what the script should do. I did not test this in a non-multi-site environment but if there is interest I’m happy to revise this further.
Thanks! I agree with Ben. Sample usage would be cool. Specifically, how can I setup a wpdb object and start making calls?
I’m having a hard time getting wpdb to load on the command line. This looks like a possible solution but not showing sample usage doesn’t make it easy to get my head around it quickly.
How do I actually use the “action” argument on line 18? Sample?
Thanks again
As $this->args would hold an array of the validated arguments you could simply use a action parameter which would then call different functions from your dispatch() method. This could look like this:
class WordPress_CLI extends WordPress_CLI_Factory { public function dispatch() { switch( $this->args->action ) { case 'hello_world': echo 'hello world'; break; case 'count100': for( $i=0; $i<100; $i++ ) echo $i; break; default: echo 'all done'; break; } } }In this case a call such as
php scriptname.php --blog_id=1 --action=hello_worldwould cause dispatch() to run the “hello world” echo
Thanks for this. Was dealing with a script that worked fine if run through the browser, but that did nothing from the command line. Adding $_SERVER[‘HTTP_HOST’] = ‘blah’ made all the difference.