feat: add basic support for the plugin "Redirection" (#17)

This PR adds very basic support for manipulating the database tables associated with the plugin "[Redirection](https://wordpress.org/plugins/redirection/)". Only the `Items` table is implemented with this PR, and a single method `Item::match()` that tests a URL for matches in Redirection

Reviewed-on: https://codeberg.org/vlw/wp/pulls/17
Co-authored-by: vlw <victor@vlw.se>
Co-committed-by: vlw <victor@vlw.se>
This commit is contained in:
Victor Westerlund 2026-02-24 11:51:37 +01:00 committed by Victor Westerlund
parent 2bfc93ceda
commit dba0fe4ebb
3 changed files with 188 additions and 0 deletions

View file

@ -21,3 +21,9 @@ $post->post_content;
// Update the datetime modified for this post
$post->post_modified = new DateTimeImmutable();
```
# Plugins
This library also has support for the following plugins:
Plugin|Versions|Reference
--|--|--
[Redirection](https://wordpress.org/plugins/redirection/)|5.3.10 (limited support)|[Plugins/redirection](/vlw/wp/src/branch/feat/plugin-redirection/src/Plugins/redirection)

View file

@ -0,0 +1,148 @@
<?php
namespace vlw\WP\Plugins\redirection;
use Exception;
use DateTimeImmutable;
use vlw\Scaffold\Database\Model;
use vlw\WP\Database;
use vlw\WP\Plugins\redirection\Tables\{Items, StatusEnum};
require_once "Tables/Items.php";
class Item extends Model {
public static function match(string $subject): array {
$matches = [];
$subject = self::get_pathname($subject);
$query = Database::current()
->from(Database::get_table(Items::TABLE_NAME))
->where([Items::STATUS->value => StatusEnum::ENABLED->value])
->select([
Items::ID->value,
Items::URL->value,
Items::MATCH_URL->value,
Items::REGEX->value
]);
foreach ($query->fetch_all(MYSQLI_ASSOC) as $row) {
// Check if subject is a direct match against the value of URL if its not a RegEx
if (!$row[Items::REGEX->value]) {
if ($subject === $row[Items::URL->value]) {
$matches[] = new static($row[Items::ID->value]);
}
continue;
}
$preg_match = [];
$pattern = str_replace("/", "\\/", $row[Items::URL->value]);
preg_match("/{$pattern}/", $subject, $preg_match);
// This subject matched this RegEx, instance this redirection Item
if (!$preg_match) {
continue;
}
$matches[] = new static($row[Items::ID->value]);
}
return $matches;
}
/**
* Return the pathname of a given URL
*
* @param string $subject
* @return string
*/
private static function get_pathname(string $subject): string {
// Coerce relative URL into absolute so parse_url() does not freak out
if (substr($subject, 0, 4) !== "http") {
$subject = trim($subject);
$subject = "http://example.com/{$subject}/";
}
return parse_url($subject, PHP_URL_PATH);
}
public function __construct(public readonly int $id) {
parent::__construct(
Database::get_table(Items::TABLE_NAME),
Items::values(),
[Items::ID->value => $id]
);
}
public string $url {
get => $this->get(Items::URL->value);
set (string $url) => $this->set(Items::URL->value, $url);
}
public string $match_url {
get => $this->get(Items::URL->value);
set (string $match_url) => $this->set(Items::URL->value, substr($match_url, 0, 2000));
}
public string $match_data {
get => $this->get(Items::MATCH_DATA->value);
set (string $match_data) => $this->set(Items::MATCH_DATA->value, $match_data);
}
public bool $regex {
get => $this->get(Items::REGEX->value);
set (bool $regex) => $this->set(Items::REGEX->value, $regex);
}
public int $position {
get => $this->get(Items::POSITION->value);
set (int $position) => $this->set(Items::POSITION->value, $position);
}
public int $last_count {
get => $this->get(Items::LAST_COUNT->value);
set (int $last_count) => $this->set(Items::LAST_COUNT->value, $last_count);
}
public DateTimeImmutable $last_access {
get => new DateTimeImmutable($this->get(Items::LAST_ACCESS->value));
set (DateTimeImmutable $last_access) => $this->set(Items::LAST_ACCESS->value, $last_access->format(static::DATETIME_FORMAT), $last_access);
}
public int $group_id {
get => $this->get(Items::GROUP_ID->value);
set (int $group_id) => $this->set(Items::GROUP_ID->value, $group_id);
}
public StatusEnum $status {
get => StatusEnum::from($this->get(Items::STATUS->value));
set (StatusEnum $status) => $this->set(Items::STATUS->value, $status->value, $status);
}
public string $action_type {
get => $this->get(Items::MATCH_TYPE->value);
set (string $action_type) => $this->set(Items::ACTION_TYPE->value, substr($action_type, 0, 20));
}
public int $action_code {
get => $this->get(Items::ACTION_CODE->value);
set (int $action_code) => $this->set(Items::ACTION_CODE->value, $action_code);
}
public string $action_data {
get => $this->get(Items::ACTION_DATA->value);
set (string $action_data) => $this->set(Items::ACTION_DATA->value, $action_data);
}
public string $match_type {
get => $this->get(Items::MATCH_TYPE->value);
set (string $match_type) => $this->set(Items::MATCH_TYPE->value, substr($match_type, 0, 20));
}
public string $title {
get => $this->get(Items::TITLE->value);
set (string $title) => $this->set(Items::TITLE->value, $title);
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace vlw\WP\Plugins\redirection\Tables;
use vlw\xEnum;
enum StatusEnum: string {
use xEnum;
case ENABLED = "enabled";
case DISABLED = "disabled";
}
enum Items: string {
use xEnum;
public const TABLE_NAME = "redirection_items";
case ID = "id";
case URL = "url";
case MATCH_URL = "match_url";
case MATCH_DATA = "match_data";
case REGEX = "regex";
case POSITION = "position";
case LAST_COUNT = "last_count";
case LAST_ACCESS = "last_access";
case GROUP_ID = "group_id";
case STATUS = "status";
case ACTION_TYPE = "action_type";
case ACTION_CODE = "action_code";
case ACTION_DATA = "action_data";
case MATCH_TYPE = "match_type";
case TITLE = "title";
}