# WP-CLI for developers

Look up every Link Manager Pro WP-CLI command with its options and defaults, and run them safely from scripts and cron jobs.
Page: https://docs.linkmanagerpro.com/developers/cli
Use when someone asks: link manager pro wp-cli scripting; wp link-manager-pro commands; automate link manager pro with wp-cli; wp-cli migrate:fresh
Intent: Reference

Link Manager Pro registers 12 WP-CLI commands under `wp link-manager-pro`. This page is the reference for scripts and cron jobs: options, defaults, which commands ask first and what they print.

The task-based guide is [WP-CLI commands](https://docs.linkmanagerpro.com/guides/wp-cli). It covers the commands step by step. This page adds the scripting details.

## Run commands in scripts

Add `--yes` to every command that asks a question, or a script waits for input. Use `--dry-run` first on the commands that have it.

- `--yes` skips the confirmation of `import`, `backup restore`, `replace-shortcodes`, `replace-prefix-links`, `link`, `unlink`, `uninstall` and `migrate-link-markers`. `uninstall` also needs `--delete-data`.
- `--dry-run` exists on `replace-shortcodes`, `replace-prefix-links`, `link`, `unlink` and `migrate-link-markers`. It changes nothing and never asks.
- A dry run of `link` only counts the posts it would scan. It doesn't say which links would change.
- `--user=<admin>` is a global WP-CLI option. `backup restore` needs it when `--items` includes `posts`, because the posts are saved as that user. The other commands work without it ([WP-CLI commands](https://docs.linkmanagerpro.com/guides/wp-cli#before-you-start)).
- On a multisite network, add `--url=<site address>` to choose the site.
- WP-CLI checks options against each command's list before it runs. A mistyped option stops the command with `Error: Parameter errors: unknown --<name> parameter`, and nothing changes. `migrate` and `migrate:status` declare no options, so they ignore extra ones.

Errors come from `WP_CLI::error()`. WP-CLI prints `Error: <message>` and stops the command. Test the exit status of your script step, not the output text.

```bash
wp link-manager-pro purge-clicks --days=90 || echo "purge failed"
```

`migrate` is the one command where `Success` can follow an error. It collects the errors of each migration file as output lines, then always prints `Success: Migrations completed.` Search its output for `Error:` instead of relying on the status.

## Every command at a glance

A dash means the command has no such option.

| Command | Options (defaults) | Reads or writes | Asks first | Dry run |
|---|---|---|---|---|
| `import` | `--source=<betterlinks\|prettylinks\|thirstyaff>` (none: lists what it found and stops with an error), `--items=<csv>` (every item with data, never `settings`), `--conflict=skip\|overwrite` (`skip`), `--affiliates=suggested\|none\|<domains>` (`suggested`), `--yes` | Writes | Yes | None |
| `backup export` | `--items=<csv>` (all 12 items), `--file=<path>` (`./link-manager-pro-backup-<Ymd-His>.json`) | Reads the database, writes one file | No | None |
| `backup restore <file>` | `--items=<csv>` (all but `posts` and `webhooks`), `--yes` | Writes | Yes | None |
| `replace-shortcodes` | `--dry-run`, `--yes` | Writes posts | Yes | `--dry-run` |
| `replace-prefix-links` | `--from=<prefix>` (every remembered previous prefix), `--affiliate`, `--dry-run`, `--yes` | Writes posts | Yes | `--dry-run` |
| `link` | `--per-batch=<n>` (100), `--dry-run`, `--yes` | Writes posts | Yes | `--dry-run` (counts posts only) |
| `unlink` | `--scope=scanned\|all` (`scanned`), `--post-types=<csv>` (`post,page`), `--ids=<csv>`, `--per-batch=<n>` (200), `--restore-shortlinks`, `--strip-rel`, `--disable-autolink`, `--dry-run`, `--yes` | Writes posts | Yes | `--dry-run` |
| `purge-clicks` | `--days=<n>` (the `tracking.click_retention_days` setting) | Deletes click rows | No | None |
| `uninstall` | `--delete-data` (required), `--yes` | Deletes all plugin data, then deactivates the plugin | Yes | None |
| `migrate-link-markers` | `--per-batch=<n>` (200), `--dry-run`, `--yes` | Writes posts | Yes | `--dry-run` |
| `migrate` | None | Creates or updates tables | No | None |
| `migrate:status` | None | Reads the migration files and checks which tables exist and have every column | No | Not needed |

`wp help link-manager-pro <command>` prints the same options. The `import` options are explained in [WP-CLI commands](https://docs.linkmanagerpro.com/guides/wp-cli#import-from-another-plugin-with-import). After a finished ThirstyAffiliates import, while `general.affiliate_prefix` is empty and ThirstyAffiliates' prefix passes the prefix rules, `import` prints two hint lines before `Success: Migration completed successfully.` They name that prefix and the command `wp link-manager-pro replace-prefix-links --affiliate --dry-run`. The command saves nothing and asks nothing.

## Back up and restore from the command line

`backup export` writes the same JSON file as the backup screen, and `backup restore` reads it back. Neither has an upload size limit, because they run in your shell and not in a web request.

### `backup export`

`wp link-manager-pro backup export` writes a backup file to disk and prints the record count and file size.

| Option | Default | What it does |
|---|---|---|
| `--items` | All 12 items | Comma-separated list from `categories`, `tags`, `links`, `link_rules`, `clicks`, `affiliates`, `campaigns`, `link_health`, `redirects`, `settings`, `webhooks`, `posts`. |
| `--file` | `link-manager-pro-backup-<Ymd-His>.json` in the current folder | Where to write the file. The time in the name is UTC. |

An unknown item name stops the command with `Unknown item(s): ...` and the list of valid items. The command refuses to overwrite: if the file exists it stops with `<file> already exists. Choose another --file.` It also stops when the folder doesn't exist or isn't writable. Both checks run before the export starts when you pass `--file`.

It stops with an error while an unfinished restore exists, because a backup would capture half-restored data. Resume or roll back that restore on the backup screen first ([Back up and restore](https://docs.linkmanagerpro.com/guides/backup-restore#resume-or-roll-back-an-unfinished-restore)).

```bash
wp link-manager-pro backup export --items=links,clicks --file=/tmp/links.json
```

It ends with `Success: Backup written to /tmp/links.json (N records, SIZE).`

### `backup restore`

`wp link-manager-pro backup restore <file>` replaces the chosen items with the contents of the file and keeps everything else.

| Option | Default | What it does |
|---|---|---|
| `<file>` | Required | Path to the backup `.json` file. `Backup file not found.` if it isn't a file. |
| `--items` | All items except `posts` and `webhooks` | Same item names as the export. |
| `--yes` | Off | Skips the question `Restore <items> from <file>? ...` |

Posts and webhooks are the exception to the default. To restore webhooks, list `webhooks` in `--items`. To restore posts, list `posts` in `--items` and add the global `--user=<administrator>`. Without a user who can edit others' posts, the command stops with `Restoring posts saves them as a user: add --user=<administrator>.`

::: warning
A restore replaces the current data in the chosen items, and once it finishes you can't undo it. Export a backup first. If the restore can't put back every record, it rolls back and your data stays as it was. The command's own help says a restore stopped part-way can be resumed or rolled back on the backup screen.
:::

```bash
wp link-manager-pro backup restore /tmp/links.json --items=links,clicks --yes
```

It ends with `Success: Restore finished: N records.` When the restore has notes, a `Warning` follows. It can name a short link prefix that wasn't restored because it breaks a prefix rule. If another restore is in progress, the command stops with `A restore is already in progress. Resume or roll it back first.` The file is copied, never moved.

## Move links to a new prefix with replace-prefix-links

`wp link-manager-pro replace-prefix-links` rewrites your own short link addresses in post content from a previous short link prefix to the current one.

It works on the prefixes the plugin remembers after you change **Short link prefix**, **Internal link prefix** or **Affiliate link prefix**. The plugin keeps the last 5 of them. It changes only links on your site whose slug is an existing short link, in published, scheduled and private posts and pages. It saves a revision of each post first. While `general.affiliate_prefix` is set, a link to an affiliate's domain moves to that prefix instead of the link or internal prefix.

| Option | Default | What it does |
|---|---|---|
| `--from` | Every remembered previous prefix | Moves only this prefix, for example `link`. It must not be a prefix in use now, or the command stops with `--from must be a prefix that isn't in use now.` |
| `--affiliate` | Off | Moves only links to an affiliate's domain, from any of your prefixes or a remembered affiliate prefix to `general.affiliate_prefix`. With that prefix empty, it moves links under a remembered affiliate prefix back to the link prefix. With `--from`, the command stops with `--affiliate and --from can't be used together.` |
| `--dry-run` | Off | Counts the links and posts that would change. It never asks. |
| `--yes` | Off | Skips the question `Update N link(s) in N post(s)? A revision of each post is saved first.` |

Before it changes anything, the command prints the previous prefixes and warns about posts it can't save (permission, markup or schedule) and posts with old short links in page-builder data, such as Elementor. It lists the builder posts but doesn't change them. Update those in the builder.

::: warning
The real run edits your posts. Run `--dry-run` first and back up before you answer `y` ([Back up and restore](https://docs.linkmanagerpro.com/guides/backup-restore)).
:::

```bash
wp link-manager-pro replace-prefix-links --dry-run
wp link-manager-pro replace-prefix-links --from=link --yes
wp link-manager-pro replace-prefix-links --affiliate --dry-run
```

The dry run ends with `Success: Dry run: N link(s) would be updated in N post(s).` The real run ends with `Success: Updated N link(s) in N post(s).` Posts it couldn't change print as `[skipped] #ID Title: reason`. With no previous prefix it says `No previous short-link prefix: nothing to update.` When no post holds an old link it says `No post links use a previous prefix.`, or `No affiliate links in posts need a new prefix.` with `--affiliate`. With `--affiliate`, it prints `Affiliate links under: /link/, /go/` first, and says `No affiliate prefix is set and none was used before: nothing to update.` when there is nothing to scan. A second run finds nothing, because rewritten links no longer match. To change the prefix itself, see [Change your short link prefix](https://docs.linkmanagerpro.com/tutorials/change-link-prefix).

## Database commands

Two commands manage the plugin's tables: `migrate` and `migrate:status`. Both are safe to run. The plugin also runs its migrations when you activate or update it, so you rarely need them by hand.

### `migrate`

`wp link-manager-pro migrate` creates the plugin's missing tables and brings existing ones up to the current layout, using WordPress's `dbDelta`. It has no options.

```bash
wp link-manager-pro migrate
```

It prints `Running migrations...`, a `Migrating:` and a `Migrated:` line for each of the 8 migration files, any errors, and `Success: Migrations completed.` The success line prints even after an error line.

### `migrate:status`

`wp link-manager-pro migrate:status` prints a table with the name, file and status of each migration and changes nothing. It has no options.

```bash
wp link-manager-pro migrate:status
```

The `Status` column reads `Ran` when the table that migration creates exists with every column. It reads `Incomplete` when columns are missing, `Missing` when the table doesn't exist, and `Unknown` when the migration creates no table. For each incomplete table the command prints `<migration> is missing columns: a, b` and `Run "wp link-manager-pro migrate" to add them.` The check only reads the database.

## Examples

### Nightly backup with system cron

This crontab line writes a dated backup file every night at 3:00. The command refuses to overwrite a file, so a second run on the same day fails instead of replacing the first backup.

```text
0 3 * * * cd /var/www/html && wp link-manager-pro backup export --file=/var/backups/lmp/link-manager-pro-$(date +\%Y\%m\%d).json
```

The `\%` is crontab syntax for a literal percent sign. Create the folder first and let the cron user write to it. Delete old files on your own schedule, because the plugin doesn't prune them.

### Purge old clicks after a deploy

`purge-clicks` deletes for good and doesn't ask. Pass `--days` to override the **Keep click data for** setting for one run ([Keep click data for](https://docs.linkmanagerpro.com/guides/settings/tracking#keep-click-data-for)).

```bash
wp link-manager-pro purge-clicks --days=90
```

It ends with `Success: Purged N click records older than 90 days.` If another purge is running, it stops with `Another click purge is running. Try again in a few minutes.`

### Dry run before masking on staging

Count the posts `link` would scan, then run it for real with `--yes` only when the count matches what you expect.

```bash
wp link-manager-pro link --dry-run
wp link-manager-pro link --yes
```

The dry run answers like `Success: Dry run: 120 post(s) (110 published, 4 scheduled, 6 private) would be scanned for masking.` Undo masking with [`unlink`](https://docs.linkmanagerpro.com/guides/wp-cli#restore-original-links-with-unlink).

## Related

- [WP-CLI commands](https://docs.linkmanagerpro.com/guides/wp-cli)
- [Back up and restore](https://docs.linkmanagerpro.com/guides/backup-restore)
- [Database tables](https://docs.linkmanagerpro.com/developers/data/tables)
- [Backup file format](https://docs.linkmanagerpro.com/developers/data/backup-format)
- [Developer docs](https://docs.linkmanagerpro.com/developers/)
