Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FAU-411] Add campo-key field / Add form fields validation rules #130

Merged
merged 9 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Support WordPress "Quote" block in content fields.
- Campo-Key term meta field.
- Term meta fields validation rules.

### Changed

- Make "Duration of studies in semester" a single line input.
- Make "Duration of studies in semester" a single line input.

## [1.2.7] - 2023-11-23

Expand Down
6 changes: 4 additions & 2 deletions resources/ts/components/ContentField/styles.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Unfortunately, there is no way to filter or adjust the core blocks toolbar.
// Hiding the block toolbar items is fragile, so it is merely a UX improvement,
// Unfortunately, there is no way to filter
// or adjust the core blocks toolbar.
// Hiding the block toolbar items is fragile,
// so it is merely a UX improvement,
// with the actual sanitization happening server-side.

// Hide H1, H2 and H6 Heading level toolbar buttons
Expand Down
34 changes: 34 additions & 0 deletions resources/ts/term-meta-fields-validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import domReady from '@wordpress/dom-ready';

const TERM_EDIT_FORM_SELECTOR = '#addtag, #edittag';

domReady( () => {
const form = document.querySelector< HTMLFormElement >(
TERM_EDIT_FORM_SELECTOR
);
const submitButton = form?.querySelector< HTMLButtonElement >(
"input[type='submit']"
);

if ( ! form || ! submitButton ) {
return;
}

form.querySelectorAll< HTMLInputElement >( '.form-field input' ).forEach(
( input ) => {
input.addEventListener( 'input', () => {
if ( form.checkValidity() ) {
submitButton.disabled = false;
return;
}

if ( input.checkValidity() ) {
return;
}

submitButton.disabled = true;
form.reportValidity();
} );
}
);
} );
55 changes: 55 additions & 0 deletions src/Infrastructure/Dashboard/TermMeta/AssetsLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Fau\DegreeProgram\Infrastructure\Dashboard\TermMeta;

use Inpsyde\Assets\Asset;
use Inpsyde\Assets\AssetManager;
use Inpsyde\Assets\Loader\ArrayLoader;
use Inpsyde\Assets\Script;
use Inpsyde\Modularity\Properties\PluginProperties;
use WP_Screen;

final class AssetsLoader
{
public const HANDLE = 'ts/term-validation';

public function __construct(
private PluginProperties $pluginProperties,
) {
}

public function load(AssetManager $assetManager): void
{
/**
* @var \Inpsyde\Assets\Asset[] $assets
*/
$assets = (new ArrayLoader())->load([
[
'handle' => self::HANDLE,
'url' => (string) $this->pluginProperties->baseUrl()
. 'assets/ts/term-meta-fields-validation.js',
'location' => Asset::BACKEND,
'type' => Script::class,
'enqueue' => fn () => $this->isTermTaxonomyEditContext(),
],
]);

$assetManager->register(...$assets);
}

private function isTermTaxonomyEditContext(): bool
{
if (! function_exists('get_current_screen')) {
return false;
}

$screen = get_current_screen();
if (!$screen instanceof WP_Screen) {
return false;
}

return ! empty($screen->taxonomy);
}
}
23 changes: 23 additions & 0 deletions src/Infrastructure/Dashboard/TermMeta/CampoKeyTermMetaField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Fau\DegreeProgram\Infrastructure\Dashboard\TermMeta;

class CampoKeyTermMetaField extends InputTermMetaField
{
public const KEY = 'uniquename';

public function __construct(
string $description,
TermMetaFieldValidationPattern $validationPattern = null,
) {

parent::__construct(
self::KEY,
__('Campo Key', 'fau-degree-program'),
$description,
validationPattern: $validationPattern,
);
}
}
25 changes: 24 additions & 1 deletion src/Infrastructure/Dashboard/TermMeta/InputTermMetaField.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public function __construct(
private string $title,
private string $description = '',
private string $type = 'text',
private ?TermMetaFieldValidationPattern $validationPattern = null,
) {
}

Expand All @@ -19,6 +20,11 @@ public function key(): string
return $this->key;
}

public function title(): string
{
return $this->title;
}

public function sanitize(mixed $value): string
{
return sanitize_text_field((string) $value);
Expand All @@ -31,13 +37,25 @@ public function templateName(): string

public function templateData(mixed $value): array
{
$showInRest = true;

if (! is_null($this->validationPattern)) {
$showInRest = [
'schema' => [
'type' => 'string',
'pattern' => $this->validationPattern->pattern(),
],
];
}

return [
'key' => $this->key,
'value' => (string) $value,
'title' => $this->title,
'description' => $this->description,
'type' => $this->type,

'validationPattern' => $this->validationPattern(),
'show_in_rest' => $showInRest,
];
}

Expand All @@ -52,4 +70,9 @@ public function metaArgs(): array
'show_in_rest' => true,
];
}

public function validationPattern(): ?TermMetaFieldValidationPattern
{
return $this->validationPattern;
}
}
2 changes: 2 additions & 0 deletions src/Infrastructure/Dashboard/TermMeta/TermMetaField.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
interface TermMetaField
{
public function key(): string;
public function title(): string;
public function sanitize(mixed $value): mixed;

public function templateName(): string;
public function templateData(mixed $value): array;
public function validationPattern(): ?TermMetaFieldValidationPattern;

/**
* @see register_meta
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Fau\DegreeProgram\Infrastructure\Dashboard\TermMeta;

class TermMetaFieldValidationPattern
{
/**
* @param non-empty-string $pattern regex pattern without delimiters
* @param string $expectedPatternMessage message to display as the expected pattern
*/
public function __construct(
private string $pattern,
private string $expectedPatternMessage = '',
) {
}

public function matches(string $value): bool
{
return (bool) preg_match(
'/' . $this->pattern() . '/',
$value
);
}

/**
* @return non-empty-string
*/
public function pattern(): string
{
return $this->pattern;
}

public function expectedPatternMessage(): string
{
return $this->expectedPatternMessage;
}
}
60 changes: 60 additions & 0 deletions src/Infrastructure/Dashboard/TermMeta/TermMetaFieldsValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Fau\DegreeProgram\Infrastructure\Dashboard\TermMeta;

use WP_Error;

final class TermMetaFieldsValidator
{
public function validate(TermMetaField ...$termMetaFields): ?WP_Error
{
if (! $this->isTermEditingContext()) {
return null;
}

foreach ($termMetaFields as $termMetaField) {
$validationPattern = $termMetaField->validationPattern();
if (is_null($validationPattern)) {
continue;
}

$postedValue = filter_input(
INPUT_POST,
$termMetaField->key(),
FILTER_SANITIZE_SPECIAL_CHARS
);

$sanitizedValue = (string) $termMetaField->sanitize($postedValue);

// Skip validation if field is empty.
if ($sanitizedValue === '') {
continue;
}

if (! $validationPattern->matches($sanitizedValue)) {
return new WP_Error(
'invalid_term_meta',
sprintf(
// translators: %1$s: field title. %2$s: expected pattern description.
__(
'The value of the field %1$s is invalid. expected value: %2$s',
'fau-degree-program'
),
$termMetaField->title(),
$validationPattern->expectedPatternMessage(),
)
);
}
}

return null;
}

private function isTermEditingContext(): bool
{
$action = filter_input(INPUT_POST, 'action', FILTER_SANITIZE_SPECIAL_CHARS);
return $action === 'editedtag' || $action === 'add-tag';
}
}
Loading
Loading