setupRedirect(). Returns the framed
* success/error message to the dispatcher.
*
* The form-validation logic previously lived on
* PluginLogicAdminActions::addAdminRedirect() (M201, design-audit-2026-06-02).
* That parent method is now a thin shim that calls addAdminRedirect() here
* so existing tests/callers do not break.
*/
class ABJ_404_Solution_AddRedirectHandler implements ABJ_404_Solution_AdminActionHandlerInterface {
/** @var ABJ_404_Solution_PluginLogicAdminActions */
private $parent;
/** @var ABJ_404_Solution_RedirectFormResolver */
private $resolver;
public function __construct(
ABJ_404_Solution_PluginLogicAdminActions $parent,
?ABJ_404_Solution_RedirectFormResolver $resolver = null
) {
$this->parent = $parent;
$this->resolver = $resolver !== null ? $resolver : $parent->redirectFormResolver();
}
public function nonceAction(): string {
return 'abj404addRedirect';
}
public function nonceArg(): string {
return '_wpnonce';
}
public function useCheckAdminReferer(): bool {
return true;
}
public function handle(string $action, string &$sub): string {
$message = $this->addAdminRedirect();
if ($message == '') {
return __('New Redirect Added Successfully!', '404-solution');
}
return $message . __('Error: unable to add new redirect.', '404-solution');
}
/**
* Run the add-redirect work. Public so the legacy
* PluginLogicAdminActions::addAdminRedirect() shim and existing tests can
* call it directly.
*
* @return string error message, '' on success
*/
public function addAdminRedirect(): string {
$message = "";
$f = $this->parent->getFunctions();
$urlNormalization = $this->parent->getUrlNormalization();
$redirectsRepo = $this->parent->getRedirectsRepo();
$logger = $this->parent->getLogger();
if (!isset($_POST['manual_redirect_url']) || $_POST['manual_redirect_url'] == "") {
$message .= __('Error: URL is a required field.', '404-solution') . "
";
return $message;
}
$manualURL = isset($_POST['manual_redirect_url']) ? wp_unslash($_POST['manual_redirect_url']) : '';
$manualURL = $urlNormalization->normalizeUserProvidedPath($manualURL);
if ($f->substr($manualURL, 0, 1) != "/") {
$message .= __('Error: URL must start with /', '404-solution') . "
";
return $message;
}
$typeAndDest = $this->resolver->getRedirectTypeAndDest();
$tdMsg = is_string($typeAndDest['message']) ? $typeAndDest['message'] : '';
if ($tdMsg != "") {
return $tdMsg;
}
$tdType2 = is_scalar($typeAndDest['type']) ? (string)$typeAndDest['type'] : '';
$tdDest2 = is_scalar($typeAndDest['dest']) ? (string)$typeAndDest['dest'] : '';
$postedCodeForCheck2 = isset($_POST['code']) && is_scalar($_POST['code']) ? (string)$_POST['code'] : '';
$code410 = $postedCodeForCheck2 === '410' || $postedCodeForCheck2 === '451';
if ($tdType2 != "" && ($tdDest2 !== "" || $code410)) {
$statusType = ABJ404_STATUS_MANUAL;
if (isset($_POST['is_regex_url']) &&
$_POST['is_regex_url'] != '0') {
$statusType = ABJ404_STATUS_REGEX;
}
$code = isset($_POST['code']) && is_scalar($_POST['code']) && (string)$_POST['code'] !== '' ? (string)$_POST['code'] : '301';
$originalManualURL = $manualURL;
$autoPromoteAdd = $this->resolver->maybeAutoPromoteRegex($statusType, $manualURL);
$statusType = $autoPromoteAdd['statusType'];
$manualURL = $autoPromoteAdd['url'];
$newRedirectId = $redirectsRepo->setupRedirect(ABJ_404_Solution_RedirectSpec::fromArray(array(
'fromURL' => $manualURL,
'status' => (string)$statusType,
'type' => $tdType2,
'finalDest' => $tdDest2,
'code' => sanitize_text_field($code),
'disabled' => 0,
)));
if ($autoPromoteAdd['autoPromoted']) {
$this->resolver->saveRegexAutoPromoteNotice((int)$newRedirectId, $originalManualURL, $manualURL, $autoPromoteAdd['urlRewritten']);
}
} else {
$message .= __('Error: Data not formatted properly.', '404-solution') . "
";
$logger->errorMessage("Add redirect data issue. Type: " . esc_html($tdType2) . ", dest: " .
esc_html($tdDest2));
}
return $message;
}
}