feat: scaffold plugin foundation

This commit is contained in:
Keith Solomon
2026-04-26 12:44:16 -05:00
commit 557657344d
24 changed files with 5238 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
<?php
namespace WPContentSync\Settings;
final class Settings {
private const LOGGING_LEVELS = array( 'error', 'warning', 'info', 'debug' );
private const CONFLICT_STRATEGIES = array( 'last_write_wins', 'manual_review' );
/**
* @var array<int, array{name: string, source_url: string, destination_url: string}>
*/
private array $sync_pairs;
private string $logging_level;
private bool $automatic_url_replacement;
private string $conflict_strategy;
/**
* @param array<int, array{name: string, source_url: string, destination_url: string}> $sync_pairs Sync pairs.
*/
private function __construct(
array $sync_pairs,
string $logging_level,
bool $automatic_url_replacement,
string $conflict_strategy
) {
$this->sync_pairs = $sync_pairs;
$this->logging_level = $logging_level;
$this->automatic_url_replacement = $automatic_url_replacement;
$this->conflict_strategy = $conflict_strategy;
}
/**
* @param array<string, mixed> $data Raw settings data.
*/
public static function fromArray( array $data ): self {
$logging_level = self::sanitizeChoice(
$data['logging_level'] ?? 'warning',
self::LOGGING_LEVELS,
'warning'
);
$conflict_strategy = self::sanitizeChoice(
$data['conflict_strategy'] ?? 'last_write_wins',
self::CONFLICT_STRATEGIES,
'last_write_wins'
);
$automatic_url_replacement = array_key_exists( 'automatic_url_replacement', $data )
? self::sanitizeBoolean( $data['automatic_url_replacement'] )
: true;
return new self(
self::sanitizeSyncPairs( $data['sync_pairs'] ?? array() ),
$logging_level,
$automatic_url_replacement,
$conflict_strategy
);
}
/**
* @return array<int, array{name: string, source_url: string, destination_url: string}>
*/
public function syncPairs(): array {
return $this->sync_pairs;
}
public function loggingLevel(): string {
return $this->logging_level;
}
public function automaticUrlReplacementEnabled(): bool {
return $this->automatic_url_replacement;
}
public function conflictStrategy(): string {
return $this->conflict_strategy;
}
/**
* @return array<string, mixed>
*/
public function toArray(): array {
return array(
'sync_pairs' => $this->sync_pairs,
'logging_level' => $this->logging_level,
'automatic_url_replacement' => $this->automatic_url_replacement,
'conflict_strategy' => $this->conflict_strategy,
);
}
/**
* @param mixed $value Value to sanitize.
* @param array<int, string> $allowed Allowed values.
*/
private static function sanitizeChoice( $value, array $allowed, string $fallback ): string {
$sanitized = sanitize_text_field( (string) $value );
return in_array( $sanitized, $allowed, true ) ? $sanitized : $fallback;
}
/**
* @param mixed $value Value to normalize.
*/
private static function sanitizeBoolean( $value ): bool {
if ( is_bool( $value ) ) {
return $value;
}
$normalized = strtolower( sanitize_text_field( (string) $value ) );
return in_array( $normalized, array( '1', 'true', 'yes', 'on' ), true );
}
/**
* @param mixed $pairs Raw sync pairs.
* @return array<int, array{name: string, source_url: string, destination_url: string}>
*/
private static function sanitizeSyncPairs( $pairs ): array {
if ( ! is_array( $pairs ) ) {
return array();
}
$sanitized = array();
foreach ( $pairs as $pair ) {
if ( ! is_array( $pair ) ) {
continue;
}
$name = sanitize_text_field( (string) ( $pair['name'] ?? '' ) );
$source_url = esc_url_raw( (string) ( $pair['source_url'] ?? '' ) );
$destination_url = esc_url_raw( (string) ( $pair['destination_url'] ?? '' ) );
if ( '' === $name || '' === $source_url || '' === $destination_url ) {
continue;
}
$sanitized[] = array(
'name' => $name,
'source_url' => $source_url,
'destination_url' => $destination_url,
);
}
return $sanitized;
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace WPContentSync\Settings;
final class SettingsRepository {
public const OPTION_NAME = 'wpcs_settings';
public function get(): Settings {
$value = get_option( self::OPTION_NAME, array() );
return Settings::fromArray( is_array( $value ) ? $value : array() );
}
public function save( Settings $settings ): void {
update_option( self::OPTION_NAME, $settings->toArray(), false );
}
/**
* @param mixed $value Value to sanitize.
* @return array<string, mixed>
*/
public function sanitizeOption( $value ): array {
return Settings::fromArray( is_array( $value ) ? $value : array() )->toArray();
}
}