# `MishkaCmsMigration.Targets.PostRedirect`
[🔗](https://github.com/mishka-group/mishka_cms_migration/blob/v0.0.1/lib/mishka_cms_migration/targets/post_redirect.ex#L6)

The `"post_redirect"` items of a source, each post's old address, written as the CMS's own
redirect rules (`MishkaCmsCore.Runtime.Redirect`), through the `:create` and `:update` an
admin's own redirect form runs, on the run's site and as the admin who pressed Import: the admin
needs the core's `admin:dashboard:runtime:redirect`, and the core's own rules decide the rest,
such as how an address is stored and that one site redirects an address once.

An item's `"from"` is the address the post had at the source, such as `/2025/12/hello/`, and the
rule sends it, with a 301, to where the Blog serves the post the same run or an earlier one
wrote for that source id (`MishkaCmsMigration.Targets.BlogPost.address/3`): `/blog/hello` for a
post in the language the site leads with, `/fa/blog/salam` for one in Persian.

## Which items

By the run's `post_address` choice (`MishkaCmsMigration.MigrationRun`'s options), read with
`existing/2` before anything is written, in the dry run too:

  * `"blog_without_redirects"` — every item is skipped as `"not_chosen"`, and no rule is
    written;
  * `"blog"` (the default) — a rule is written for each item, except:
    * one the source gives no old address (`"from"` is `nil`, such as a draft's) — skipped as
      `"no_old_address"`;
    * in an import, one whose post has no Blog post — it failed, was never written or an admin
      left it out — skipped as `"post_missing"`;
    * in an import, one whose old address is the post's Blog address already — skipped as
      `"same_address"`.

A dry run writes no post, so it does not look for one: an item it plans may still be skipped
for its post when the import runs.

An old address the site already redirects, by a rule of an admin's own or of another source's
run, is refused by the core's one-rule-per-address identity, and the item fails with the core's
reason; the site's rule is kept as it is.

A re-run is held to the rules every target is: a rule WordPress did not change is
`"unchanged"`, and one an admin edited or deleted in the CMS is kept as the admin left it
(`MishkaCmsMigration.Workers.Helpers.Decision`). Switching the choice off later leaves the
rules an earlier run wrote.

Defined only where Mishka Blog is loaded, and supervised by `MishkaCmsMigration.Application`
only then; on a node without the Blog its items wait for it (`"blog_missing"`).

# `error_return`

```elixir
@type error_return() ::
  {:error, [%{action: atom(), field: atom(), message: String.t()}]}
```

# `okey_return`

```elixir
@type okey_return() :: {:ok, struct() | map() | module() | [any()]}
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `config`

```elixir
@spec config() :: keyword()
```

# `config`

```elixir
@spec config(atom()) :: any()
```

# `enable`

```elixir
@spec enable() :: okey_return() | error_return()
```

# `get`

```elixir
@spec get() :: keyword()
```

# `health_check`

```elixir
@spec health_check() :: :ok | {:degraded, term()} | {:error, term()}
```

Optional. See `c:MishkaInstaller.Event.Hook.health_check/0`. Override to report health.

# `on_dependency_error`

```elixir
@spec on_dependency_error(term()) :: term()
```

Optional. See `c:MishkaInstaller.Event.Hook.on_dependency_error/1`. Override to react.

# `register`

```elixir
@spec register() :: okey_return() | error_return()
```

# `restart`

```elixir
@spec restart() :: okey_return() | error_return()
```

# `start`

```elixir
@spec start() :: okey_return() | error_return()
```

# `start_link`

# `stop`

```elixir
@spec stop() :: okey_return() | error_return()
```

# `unregister`

```elixir
@spec unregister() :: okey_return() | error_return()
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
