Technote

Development workflow Practical

Series WP-CLI automation recipes Part 4 of 8

Running scripts with eval-file, and the argument trap

It runs your own PHP file inside a fully loaded WordPress. Flags starting with -- never reach your script, though, because WP-CLI consumes them first.

Some jobs do not decompose into commands: branching on a condition, looping over hundreds of records, tying several steps into one operation. That is what wp eval-file is for.

eval and eval-file

One line goes through wp eval; a file goes through wp eval-file.

wp eval 'echo get_option( "home" );'
wp eval-file bin/report.php

Both run inside a fully loaded WordPress. Plugins are active, hooks are attached, and get_posts() and wp_insert_post() behave exactly as they do on the front end. Not having to write your own bootstrap is the whole value of the command.

Put a guard at the top of the script file.

if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
    return;
}

Now if the file ever ends up inside the document root, a web request does nothing with it. For any script that writes data, this is not optional.

The trap: arguments are positional

Everybody hits this once. Anything beginning with -- is interpreted as a flag for WP-CLI itself. It never reaches your script, and an unrecognised one gets the whole command rejected.

# does not work — --dry is consumed by eval-file
wp eval-file bin/seed.php --dry

# works — pass it positionally
wp eval-file bin/seed.php dry s25

Inside the script they arrive in $args.

$args = (array) ( $args ?? [] );
$dry  = in_array( 'dry', $args, true );

The restriction is more useful than it first appears, because it keeps a script’s interface down to a couple of short words. Once you want more than three options, the job has outgrown a script and it is time to promote it to a proper command — the subject of part six.

Move tools as the job grows — the argument convention marks the boundary

WordPress in the shell is not WordPress on the web

Same WordPress, different context. Three differences cause most of the surprises.

What differs in the CLI context — the top row even changes how content saves

User 0 reaches furthest. With nobody logged in every current_user_can() is false, and the absence of unfiltered_html in particular means kses filters your content on save. The next part shows exactly what that looks like when it happens.

Hook timing differs too. eval-file executes after WordPress has finished loading, so early hooks such as init are long gone. People add add_action( 'init', … ) inside a script and then hunt for why it never fires; it is late rather than wrong, and the answer is simply to call the code directly.

The script that dies silently on an ABSPATH guard

Most WordPress files open with this.

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

require such a file from a plain PHP script that never bootstrapped WordPress and the line executes as written, ending the run with zero bytes of output and exit code 0. No error, no warning — so you start by suspecting your own logic, and it takes a long while to find.

There are two clean responses. If you need WordPress, run through eval-file. If you do not, write a self-contained script that includes no WordPress files at all. The second is especially valuable in CI, where it finishes in seconds without a database or an install — we come back to it in part eight.

Examples of the kind of work worth scripting live in the development workflow archive, and the diagnostic plugins we built the same way are on the free tools page.

Next part

Once you write scripts, you will soon run the same script twice. Next up: idempotent seeds — making a second run create nothing new — and the several quiet traps hiding in that.

More on this topic

All technotes

Development workflow Practical

Turning taste arguments into rule checks

"It feels a bit cramped" can be neither argued with nor fixed. Spacing off the scale, colour off the palette, contrast below threshold, missing states — four rules…

Designers 9 min read

Development workflow Practical

Do not swap everything at once

A full swap makes every problem appear at the same moment — which means none of them can be attributed. So you switch one template at a time.

Designers 6 min read

Development workflow Practical

Adding an SCSS build, and whether to commit the output

WordPress themes are expected to deploy without a build step, which leads to the opposite conclusion from ordinary application code — and to its own costs.

Developers 7 min read

₩270,000 · Join the program