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() ); } }
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:
In this case a call such as
php scriptname.php --blog_id=1 --action=hello_world
would 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.