WP-CLI commands
Every wp adminkeep command: switch features on and off, change settings, replace CSS and header code, set up SMTP and Contact Form, read logs.
Since 1.5.0, everything on the Adminkeep settings screen, plus the Custom CSS, Header & Footer Code, SMTP and Contact Form screens, is also a WP-CLI command. Use it to set up a new site from a script, to apply the same settings to many sites, or to let an AI agent do the work.
The same reference ships inside the plugin, so it always matches the version you run:
wp help adminkeep
wp help adminkeep smtp set # every subcommand has its own page
Adminkeep must be active. Nothing here loads on a normal page view: the commands exist only while WP-CLI is running.
At a glance
| Command | What it does |
|---|---|
wp adminkeep feature list | Every feature: id, group, label, on/off, state |
wp adminkeep feature enable <id>... | Switch features on |
wp adminkeep feature disable <id>... | Switch features off |
wp adminkeep feature get <id> | A feature’s settings, and what each accepts |
wp adminkeep feature set <id> key=value... | Change a feature’s settings |
wp adminkeep comments count | How many comments purge would delete |
wp adminkeep comments purge | Delete them for good |
wp adminkeep css get | Print the site’s Custom CSS |
wp adminkeep css set [<file>] | Replace it from a file or standard input |
wp adminkeep code get <location> | Print one Header & Footer Code box: head, body or footer |
wp adminkeep code set <location> [<file>] | Replace that box from a file or standard input |
wp adminkeep smtp get | SMTP settings and where each value comes from |
wp adminkeep smtp set --host=... ... | Change SMTP settings |
wp adminkeep smtp test <to> | Send a test email |
wp adminkeep smtp import <source> | Copy SMTP settings from another plugin (wp-mail-smtp) |
wp adminkeep contact-form get | Contact Form settings, where each value comes from, and whether the form is live |
wp adminkeep contact-form set --provider=... ... | Change Contact Form settings |
wp adminkeep email-log list | Logged email, newest first |
wp adminkeep email-log get <id> | One logged email, content included |
wp adminkeep email-log count | How many emails are logged |
wp adminkeep email-log purge | Permanently delete logged email |
wp adminkeep email-log import <source> | Copy another plugin’s log in |
wp adminkeep emails list | WordPress core’s own emails, the ones Nice Default Emails covers |
wp adminkeep emails send <id>... --to=<email> | Send them to one address, to see how they look |
wp adminkeep setting get [<key>] | Plugin-level settings: key, value, type, accepted values; with a key, just its value |
wp adminkeep setting set key=value... | Change plugin-level settings: hide_unused, delete_data |
Features
wp adminkeep feature list
wp adminkeep feature list --enabled --fields=id --format=csv
wp adminkeep feature list --group=site_lock
feature list is where the ids come from. The groups are site_lock, content,
appearance, admin and email.
| id | Feature |
|---|---|
disable_comments | Disable Comments |
registration_lock | Registration Lockdown (disable user registration) |
disable_xmlrpc | Disable XML-RPC |
disable_file_edit | Disable File Editing |
install_lock | Installation Lockdown (block plugin and theme installs) |
username_privacy | Username Privacy (hide usernames from visitors) |
two_factor | Two-Factor Login (an emailed code after the password) |
duplicate | Duplicate |
live_draft | Live Draft |
keep_url | Keep URL |
order | Order |
replace_media | Replace Media |
custom_css | Custom CSS |
header_footer_code | Header & Footer Code |
user_columns | User Registration Date |
smtp | SMTP |
email_log | Email Log |
nice_emails | Nice Default Emails |
contact_form | Contact Form |
Switch a feature on or off
wp adminkeep feature enable disable_comments
wp adminkeep feature enable disable_xmlrpc disable_file_edit
wp adminkeep feature disable install_lock
Only the switch changes. A feature’s settings are kept while it is off, the same as on the settings screen, and the change takes effect from the next request.
Read and change a feature’s settings
wp adminkeep feature get order
feature get prints one row per setting: its key, the current value, its type, and what
feature set accepts for it. That table is the reference for a feature’s keys, so there is
no list to look up anywhere else.
# Manual ordering for posts and pages, new posts at the top.
wp adminkeep feature set order post_types=post,page new_post_position=top
# Keep replaced media files for two weeks.
wp adminkeep feature set replace_media retain_days=14
Values are true or false for a switch, a whole number, plain text, or a comma-separated
list. A list replaces what is stored, and an empty value empties it. Everything you don’t name
is kept. feature set does not switch the feature on; that is feature enable.
What each setting means is covered in Configuration.
Two-Factor Login
Since 2.6.0.
wp adminkeep feature enable two_factor
wp adminkeep feature set two_factor roles=administrator,editor trust_days=14
wp adminkeep feature disable two_factor
feature enable two_factor emails a recovery link and prints the address it went to, or warns
that it could not be sent. From a shell there is usually no user, so the link goes to the site’s
administration email address. Keep that email: the link turns Two-Factor Login off without
logging in.
The settings are roles (role slugs, comma-separated; an empty value means nobody is asked),
trust_device (true or false, whether the code screen offers “Remember this device”) and
trust_days (how long a remembered device skips the code, 30 by default).
Locked out by Two-Factor Login? wp adminkeep feature disable two_factor is the way back in
from a shell. It changes only the switch, so the chosen roles are kept. The
Two-Factor Login docs list the other two
ways.
Comments
wp adminkeep comments count
wp adminkeep comments purge
This is the same cleanup as the button under Disable Comments, with the same guards. Read Comment cleanup first: it is the one thing in the plugin that deletes data, and it cannot be undone.
- By default only spam and trash are counted and deleted.
--approvedadds approved and pending comments.--wooadds WooCommerce order notes, webhook logs and product reviews. Leave it out on a store unless you mean it.countprints a bare number, so a script can read it. Give it the same flags you plan to givepurge.purgeshows the number and asks before deleting.--yesskips the question.
It runs in batches, so a very large site will not time out, and it works whether or not the Disable Comments feature is on.
Custom CSS
wp adminkeep css get > site.css
wp adminkeep css set site.css
cat site.css | wp adminkeep css set
css get prints the stored CSS and nothing else, so it is safe to redirect into a file.
css set replaces the stored CSS with a file’s contents, or with standard input when you
leave the file out or pass -. The CSS is checked the way the Custom CSS screen checks it:
anything that looks like an HTML tag is refused.
Empty input clears the CSS. If CSS is already stored, clearing it asks for confirmation
first; --yes skips the question.
The CSS is only printed on your site while the feature is on:
wp adminkeep feature enable custom_css.
The live editor’s admin bar item is a feature setting, on by default:
wp adminkeep feature set custom_css admin_bar=false hides it. Without a shell, the CSS can be
read and saved over the REST API with an application password.
Since 2.0.0, css get prints the CSS exactly as stored, with no newline added, so its output
can be piped back into css set without changing anything.
Header & Footer Code
wp adminkeep code get head > head.html
wp adminkeep code set head analytics.html
cat gtm-noscript.html | wp adminkeep code set body
printf '' | wp adminkeep code set footer --yes
Since 2.0.0. The same three boxes as Appearance → Header & Footer Code, one at a time. The
location is head, body or footer: head prints inside <head>, body just after
<body> opens, footer at the end of the page after WordPress’s own footer scripts. See
Header & Footer Code for what each box is for.
code get <location>prints one box’s stored code and nothing else. The output is byte for byte what is stored, with no newline added, so it can be piped back intosetunchanged.code set <location> [<file>]replaces one box with a file’s contents, or with standard input when you leave the file out or pass-. The code is stored and printed exactly as given. The other two boxes are left as they are.- Each box holds up to 65,536 bytes (64 KB); anything longer is refused and nothing is written.
- Empty input clears the box. If the box holds code, clearing it asks for confirmation first,
unless you pass
--yes. - The change is recorded as made by the user given with
--user, or as “WP-CLI” when there is none. A user given with--usermust hold bothmanage_optionsandunfiltered_html, as on the screen; otherwise nothing is written.
The code is only printed on your site while the feature is on:
wp adminkeep feature enable header_footer_code. set still saves it while the feature is off,
and says so. Without a shell, the boxes can be read and saved over the
REST API with an application password.
SMTP
wp adminkeep smtp set --host=smtp.example.com --port=587 --encryption=tls
wp adminkeep smtp set --auth --username=apikey
printf %s "$SMTP_PASSWORD" | wp adminkeep smtp set --password-stdin
wp adminkeep smtp set [email protected] --from-name="Example"
wp adminkeep feature enable smtp
wp adminkeep smtp test [email protected]
wp adminkeep smtp import wp-mail-smtp --dry-run
wp adminkeep smtp import wp-mail-smtp
smtp set changes only what you name; everything else is kept.
| Flag | Meaning |
|---|---|
--host=<host> | SMTP server |
--port=<port> | 1 to 65535. Usually 587 (tls) or 465 (ssl) |
--encryption=<encryption> | none, ssl or tls |
--auth / --no-auth | Whether the server needs a username and password |
--username=<username> | SMTP username |
--password-stdin | Read the password from standard input |
--password=<password> | The password, in plain sight. Prefer --password-stdin |
--clear-password | Remove the saved password |
--from-email=<email> | Address email is sent from. An empty value clears it |
--from-name=<name> | Name email is sent from |
--force-from / --no-force-from | Use the From address even when a plugin sets its own |
--force-name / --no-force-name | Use the From name even when a plugin sets its own |
The password. It is never printed, by any command. --password-stdin keeps it out of
your shell history and out of the process list; --password= puts it in both.
Settings in wp-config.php. A setting fixed by an ADMINKEEP_SMTP_* constant cannot be
changed from the command line, the same as on the screen. smtp get shows where each value
comes from, so you can see which ones are fixed.
The test email. smtp test needs the SMTP feature on and a server configured; otherwise
it stops with an error instead of reporting a success that went out some other way. When
sending fails, it prints the server’s side of the conversation with the username and
password removed, and exits with an error. --log prints that conversation even when the
email is sent.
Copying from WP Mail SMTP. Since 1.10.0, smtp import wp-mail-smtp copies WP Mail SMTP’s
SMTP connection: server, port, encryption, authentication, username, password, From address and
name, and whether each is forced. It replaces your current Adminkeep SMTP settings, except
values held by ADMINKEEP_SMTP_* constants in wp-config.php, which are kept. WP Mail SMTP’s
settings are only read, and it does not need to be active.
| Flag | Meaning |
|---|---|
<source> | Where to copy from. Today there is one: wp-mail-smtp |
--dry-run | Show what would be copied without changing anything |
The output names the fields copied and the ones kept from wp-config.php, not their values,
and says what became of the password: copied and stored encrypted, kept from wp-config.php,
left as it was because WP Mail SMTP has none saved, or left as it was because WP Mail SMTP’s
saved password could not be read. In that last case set it with smtp set --password-stdin.
Only an SMTP connection can be copied: if WP Mail SMTP is set to an API mailer such as
SendLayer or the Gmail API, or has no SMTP host, the command exits 1 and names the reason. After
copying, send a test email with smtp test, then deactivate WP Mail SMTP if it is still active,
so the two plugins do not both configure the mailer.
Choosing a provider, ports and the constants are covered in the WordPress SMTP settings guide.
Contact Form
Since 2.3.0. The nonce provider arrived in 2.4.0, which also removed none.
wp adminkeep feature enable contact_form
wp adminkeep contact-form get
wp adminkeep contact-form set --provider=turnstile --turnstile-site-key=XXXX
printf %s "$TURNSTILE_SECRET" | wp adminkeep contact-form set --turnstile-secret-stdin
wp adminkeep contact-form set --provider=nonce
wp adminkeep contact-form set [email protected] --subject-prefix="[Example]"
contact-form get prints one row per setting with its value and source (constant, stored or
default), and a last row with the status: live (nonce), live (turnstile), or
hidden: turnstile keys not set. Secrets show only (set), (not set) or (unreadable).
It takes --format=<table|json|csv|yaml>.
contact-form set changes only what you name: --provider=<nonce|turnstile|recaptcha> (nonce
is the default; it needs no keys but does not work on a site that caches its pages),
--to=<email>, --subject-prefix=<text>, --success-text=<text>, --error-text=<text>,
--turnstile-site-key=<key>, --recaptcha-site-key=<key>, --recaptcha-threshold=<0.1 to 0.9>,
and for turnstile and recaptcha each --<provider>-secret-stdin, --<provider>-secret=<key>
(in plain sight; prefer stdin) and --clear-<provider>-secret. It refuses, and changes nothing, on
a field held by a wp-config.php constant, two secret flags for one provider, a bad email address,
a threshold out of range or an unknown provider, none included. It never prints a secret. When
the feature is off, it reminds you to run wp adminkeep feature enable contact_form.
The flags, the constants and what each setting does are in the Contact Form docs.
Email Log
wp adminkeep email-log list --status=failed --format=json
wp adminkeep email-log get 482
wp adminkeep email-log count --status=failed
wp adminkeep email-log purge --older-than=90 --yes
wp adminkeep email-log import email-log --dry-run
This is the same log as the Email Log screen in the admin, and it works whether or not the Email Log feature is on: what was logged stays readable after logging is switched off. Read Email Log first for what each status means and what is kept.
listtakes--status=<sent|failed|unconfirmed>,--search=<text>(matches the recipient, sender or subject, never the body),--since=<date>(read as UTC, e.g.2026-09-01),--limit=<number>(default 50, at most 500), and--format=<table|json|csv|yaml|ids|count>. It never prints a body — usegetfor one email’s content.get <id>prints one email in full, including its content.counttakes--statusonly, and prints a bare number.purgetakes--allor--older-than=<days>, never both. It asks for confirmation first, unless you pass--yes. This cannot be undone.import <source>copies another plugin’s log in.email-logis currently the only source, for the Email Log plugin — see moving from the Email Log plugin. It needs Email Log switched on first, and reads the other plugin’s table without changing it.--dry-runreports the counts without writing anything.
Core emails
wp adminkeep feature enable nice_emails
wp adminkeep emails list
wp adminkeep emails list --format=ids
wp adminkeep emails send password_reset [email protected]
wp adminkeep emails send new_user comment_notification [email protected]
wp adminkeep emails send --all [email protected]
These are the emails WordPress core writes itself, the ones Nice Default
Emails dresses up. Most of them are hard to trigger on purpose (a
new account, a comment held for moderation, an automatic update, a personal data request), so
send makes WordPress send them for you.
listprints each email this site can send: its id, what it is, and the core function that sends it. The six multisite emails are listed only on a multisite network. Takes--format=<table|json|csv|yaml|ids|count>.sendtakes one or more ids fromlist, or--all, but not both, and needs--to=<email>. It prints one row per email (id, subject, whether it was wrapped, status) and takes--format=<table|json|csv|yaml>.
Each email is sent by the core function that sends it for real, so it arrives exactly as your site
would send it: through your mailer (the SMTP feature, when on), in the Nice Default Emails layout,
and recorded by Email Log when that is on. Only the recipient is changed: every email goes to
--to, and to nobody else.
What the emails need is made for the run and deleted after it: a throwaway subscriber for the account emails (no real account’s password or reset link changes), a private post with two comments, personal data requests. Settings core writes while sending, such as a pending admin email change or a recovery mode key, are put back, so the links in those emails do nothing. If something could not be cleaned up, the command says what, so you can remove it by hand.
send needs Nice Default Emails switched on; otherwise it stops rather than sending plain text.
It exits 1 if any email fails, and names the one that did.
Plugin-level settings
wp adminkeep setting get
wp adminkeep setting get hide_unused
wp adminkeep setting set hide_unused=true
wp adminkeep setting set delete_data=true
Since 1.8.1. Settings that belong to the plugin itself rather than to one feature, in the
same key=value shape as feature set. There are two:
hide_unused: the same as the Hide unused features switch on the settings screen, which hides switched-off features from its nav.delete_data(since 2.2.0, off by default): the same as Delete all Adminkeep data when the plugin is deleted in the Plugin settings tab. Off, deleting the plugin keeps its settings and data; on, deleting it removes them. See Uninstalling.
Both are site settings, so no --user is needed (WP-CLI’s global --user is accepted
and ignored). get <key> prints the value and nothing else; get alone lists every setting
and takes --format=json. A wrong key or value exits 1 and writes nothing.
This replaces 1.8.0’s wp adminkeep view get|hide-unused|show-all --user=<user>, which set the
view for one administrator at a time.
For scripts and AI agents
feature list,feature get,smtp get,contact-form get,email-log list,emails listandemails sendtake--format=json(alsocsv,yamlandtable;email-log listandemails listalso takeidsandcount).- Exit code 0 means the change was made. Any mistake (an unknown id, an unknown key, the wrong type of value) exits 1, names the valid choices, and writes nothing.
comments purgeandemail-log purgealways ask first, andcss setandcode setask before clearing stored code. Pass--yesto skip the question.- A change takes effect from the next request.
- On multisite, pick the site with WP-CLI’s own
--url=<site>. wp help adminkeepis written as a complete reference. An agent that reads it needs nothing else.
A new site, set up in one go:
wp plugin install adminkeep --activate
wp adminkeep feature enable disable_comments disable_xmlrpc disable_file_edit
wp adminkeep feature enable order
wp adminkeep feature set order post_types=post,page
wp adminkeep feature list --enabled --format=json