233 lines
12 KiB
PHP
233 lines
12 KiB
PHP
<?php
|
|
|
|
namespace AKSRT\WidgetSystem;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
/**
|
|
* Server-rendered, schema-driven widget form.
|
|
*/
|
|
final class FormRenderer {
|
|
public static function render(SchemaWidget $widget, array $fields, array $instance): void {
|
|
echo '<div class="aksrt-widget-form" data-aksrt-widget-form="1">';
|
|
foreach ($fields as $field) {
|
|
self::field($widget, $field, $instance[(string) ($field['id'] ?? '')] ?? ($field['default'] ?? ''), '');
|
|
}
|
|
echo '</div>';
|
|
}
|
|
|
|
private static function field(SchemaWidget $widget, array $field, $value, string $parent): void {
|
|
$type = (string) ($field['type'] ?? 'text');
|
|
$id = (string) ($field['id'] ?? '');
|
|
if (in_array($type, ['content', 'subheading', 'submessage'], true)) {
|
|
self::display_field($field, $type);
|
|
return;
|
|
}
|
|
if ($id === '') {
|
|
return;
|
|
}
|
|
|
|
$key = $parent === '' ? $id : $parent . '[' . $id . ']';
|
|
$field_id = $widget->get_field_id(str_replace(['[', ']'], ['-', ''], $key));
|
|
$field_name = $widget->get_field_name($key);
|
|
$dependency = !empty($field['dependency']) ? wp_json_encode($field['dependency']) : '';
|
|
|
|
echo '<div class="aksrt-widget-field aksrt-widget-field--' . esc_attr($type) . '" data-field-id="' . esc_attr($id) . '"';
|
|
if ($dependency !== '') {
|
|
echo ' data-dependency="' . esc_attr($dependency) . '"';
|
|
}
|
|
echo '>';
|
|
if (!empty($field['label'])) {
|
|
echo '<label class="aksrt-widget-field__label" for="' . esc_attr($field_id) . '">' . esc_html((string) $field['label']) . '</label>';
|
|
}
|
|
if (!empty($field['description'])) {
|
|
echo '<p class="description">' . wp_kses_post((string) $field['description']) . '</p>';
|
|
}
|
|
|
|
switch ($type) {
|
|
case 'switcher':
|
|
self::switcher($field_id, $field_name, (bool) $value);
|
|
break;
|
|
case 'radio':
|
|
case 'button_set':
|
|
case 'palette':
|
|
self::radios($field_id, $field_name, (array) ($field['options'] ?? []), (string) $value, $type);
|
|
break;
|
|
case 'select':
|
|
self::select($field_id, $field_name, $field, $value);
|
|
break;
|
|
case 'checkbox':
|
|
self::checkboxes($field_id, $field_name, $field, $value);
|
|
break;
|
|
case 'number':
|
|
case 'spinner':
|
|
case 'slider':
|
|
self::number($field_id, $field_name, $field, $value, $type);
|
|
break;
|
|
case 'textarea':
|
|
echo '<textarea class="widefat" rows="4" id="' . esc_attr($field_id) . '" name="' . esc_attr($field_name) . '">' . esc_textarea((string) $value) . '</textarea>';
|
|
break;
|
|
case 'upload':
|
|
self::upload($field_id, $field_name, (string) $value);
|
|
break;
|
|
case 'color':
|
|
echo '<input class="widefat aksrt-widget-color" type="text" id="' . esc_attr($field_id) . '" name="' . esc_attr($field_name) . '" value="' . esc_attr((string) $value) . '">';
|
|
break;
|
|
case 'icon':
|
|
echo '<div class="aksrt-widget-icon"><i class="' . esc_attr((string) $value) . '" aria-hidden="true"></i><input class="widefat" type="text" id="' . esc_attr($field_id) . '" name="' . esc_attr($field_name) . '" value="' . esc_attr((string) $value) . '" placeholder="fa fa-star"></div>';
|
|
break;
|
|
case 'link':
|
|
self::link($widget, $key, is_array($value) ? $value : []);
|
|
break;
|
|
case 'spacing':
|
|
self::spacing($widget, $key, is_array($value) ? $value : []);
|
|
break;
|
|
case 'background':
|
|
self::background($widget, $key, is_array($value) ? $value : []);
|
|
break;
|
|
case 'group':
|
|
self::group($widget, $field, is_array($value) ? $value : [], $key);
|
|
break;
|
|
case 'fieldset':
|
|
case 'accordion':
|
|
self::nested($widget, $field, is_array($value) ? $value : [], $key);
|
|
break;
|
|
case 'text':
|
|
default:
|
|
echo '<input class="widefat" type="text" id="' . esc_attr($field_id) . '" name="' . esc_attr($field_name) . '" value="' . esc_attr((string) $value) . '">';
|
|
}
|
|
echo '</div>';
|
|
}
|
|
|
|
private static function display_field(array $field, string $type): void {
|
|
$content = (string) ($field['content'] ?? $field['label'] ?? '');
|
|
echo '<div class="aksrt-widget-field aksrt-widget-field--' . esc_attr($type) . '">' . wp_kses_post($content) . '</div>';
|
|
}
|
|
|
|
private static function switcher(string $id, string $name, bool $value): void {
|
|
echo '<input type="hidden" name="' . esc_attr($name) . '" value="0">';
|
|
echo '<label class="aksrt-widget-switch"><input type="checkbox" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="1" ' . checked($value, true, false) . '><span aria-hidden="true"></span></label>';
|
|
}
|
|
|
|
private static function radios(string $id, string $name, array $options, string $value, string $type): void {
|
|
echo '<div class="aksrt-widget-choices aksrt-widget-choices--' . esc_attr($type) . '">';
|
|
foreach ($options as $key => $label) {
|
|
$option_id = $id . '-' . sanitize_html_class((string) $key);
|
|
echo '<label for="' . esc_attr($option_id) . '"><input type="radio" id="' . esc_attr($option_id) . '" name="' . esc_attr($name) . '" value="' . esc_attr((string) $key) . '" ' . checked($value, (string) $key, false) . '><span>' . esc_html((string) $label) . '</span></label>';
|
|
}
|
|
echo '</div>';
|
|
}
|
|
|
|
private static function select(string $id, string $name, array $field, $value): void {
|
|
$multiple = !empty($field['multiple']);
|
|
echo '<select class="widefat" id="' . esc_attr($id) . '" name="' . esc_attr($name) . ($multiple ? '[]' : '') . '"' . ($multiple ? ' multiple' : '') . '>';
|
|
$values = $multiple ? array_map('strval', (array) $value) : [(string) $value];
|
|
foreach ((array) ($field['options'] ?? []) as $key => $label) {
|
|
echo '<option value="' . esc_attr((string) $key) . '" ' . selected(in_array((string) $key, $values, true), true, false) . '>' . esc_html((string) $label) . '</option>';
|
|
}
|
|
echo '</select>';
|
|
}
|
|
|
|
private static function checkboxes(string $id, string $name, array $field, $value): void {
|
|
$options = (array) ($field['options'] ?? []);
|
|
if (!$options) {
|
|
self::switcher($id, $name, (bool) $value);
|
|
return;
|
|
}
|
|
$values = array_map('strval', (array) $value);
|
|
foreach ($options as $key => $label) {
|
|
echo '<label><input type="checkbox" name="' . esc_attr($name) . '[]" value="' . esc_attr((string) $key) . '" ' . checked(in_array((string) $key, $values, true), true, false) . '> ' . esc_html((string) $label) . '</label> ';
|
|
}
|
|
}
|
|
|
|
private static function number(string $id, string $name, array $field, $value, string $type): void {
|
|
$min = isset($field['min']) ? ' min="' . esc_attr((string) $field['min']) . '"' : '';
|
|
$max = isset($field['max']) ? ' max="' . esc_attr((string) $field['max']) . '"' : '';
|
|
$step = ' step="' . esc_attr((string) ($field['step'] ?? 1)) . '"';
|
|
$input_type = $type === 'slider' ? 'range' : 'number';
|
|
echo '<div class="aksrt-widget-number"><input class="widefat" type="' . esc_attr($input_type) . '" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr((string) $value) . '"' . $min . $max . $step . '><output>' . esc_html((string) $value) . '</output></div>';
|
|
}
|
|
|
|
private static function upload(string $id, string $name, string $value): void {
|
|
echo '<div class="aksrt-widget-upload">';
|
|
if ($value !== '') {
|
|
echo '<img src="' . esc_url($value) . '" alt="">';
|
|
}
|
|
echo '<input class="widefat" type="url" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr($value) . '">';
|
|
echo '<button type="button" class="button aksrt-widget-upload__choose">' . esc_html__('选择媒体', 'aksrt') . '</button> <button type="button" class="button-link-delete aksrt-widget-upload__remove">' . esc_html__('移除', 'aksrt') . '</button></div>';
|
|
}
|
|
|
|
private static function link(SchemaWidget $widget, string $key, array $value): void {
|
|
echo '<div class="aksrt-widget-link">';
|
|
self::plain_input($widget, $key . '[url]', (string) ($value['url'] ?? ''), 'url', 'URL');
|
|
self::plain_input($widget, $key . '[text]', (string) ($value['text'] ?? ''), 'text', '链接文字');
|
|
$name = $widget->get_field_name($key . '[target]');
|
|
echo '<label><input type="checkbox" name="' . esc_attr($name) . '" value="_blank" ' . checked(($value['target'] ?? '') === '_blank', true, false) . '> ' . esc_html__('新窗口打开', 'aksrt') . '</label></div>';
|
|
}
|
|
|
|
private static function spacing(SchemaWidget $widget, string $key, array $value): void {
|
|
echo '<div class="aksrt-widget-spacing">';
|
|
foreach (['top' => '上', 'right' => '右', 'bottom' => '下', 'left' => '左'] as $edge => $label) {
|
|
echo '<label><span>' . esc_html($label) . '</span>';
|
|
self::plain_input($widget, $key . '[' . $edge . ']', (string) ($value[$edge] ?? ''), 'number', 'px');
|
|
echo '</label>';
|
|
}
|
|
echo '</div>';
|
|
}
|
|
|
|
private static function background(SchemaWidget $widget, string $key, array $value): void {
|
|
echo '<div class="aksrt-widget-background">';
|
|
self::plain_input($widget, $key . '[color]', (string) ($value['color'] ?? ''), 'text', '背景颜色');
|
|
self::plain_input($widget, $key . '[image]', (string) ($value['image'] ?? ''), 'url', '背景图片 URL');
|
|
foreach ([
|
|
'position' => ['center center' => '居中', 'top center' => '顶部', 'bottom center' => '底部', 'center left' => '左侧', 'center right' => '右侧'],
|
|
'repeat' => ['no-repeat' => '不重复', 'repeat' => '平铺', 'repeat-x' => '水平平铺', 'repeat-y' => '垂直平铺'],
|
|
'attachment' => ['scroll' => '滚动', 'fixed' => '固定'],
|
|
'size' => ['cover' => '覆盖', 'contain' => '包含', 'auto' => '原始尺寸'],
|
|
] as $part => $options) {
|
|
$name = $widget->get_field_name($key . '[' . $part . ']');
|
|
echo '<select name="' . esc_attr($name) . '">';
|
|
foreach ($options as $option => $label) {
|
|
echo '<option value="' . esc_attr($option) . '" ' . selected((string) ($value[$part] ?? ''), $option, false) . '>' . esc_html($label) . '</option>';
|
|
}
|
|
echo '</select>';
|
|
}
|
|
echo '</div>';
|
|
}
|
|
|
|
private static function group(SchemaWidget $widget, array $field, array $rows, string $key): void {
|
|
$token = '__index_' . substr(md5($key), 0, 8) . '__';
|
|
echo '<div class="aksrt-widget-repeater" data-index-token="' . esc_attr($token) . '" data-max-items="' . esc_attr((string) ($field['max_items'] ?? 50)) . '"><div class="aksrt-widget-repeater__rows">';
|
|
foreach ($rows as $index => $row) {
|
|
self::group_row($widget, $field, is_array($row) ? $row : [], $key, (string) $index);
|
|
}
|
|
echo '</div><template class="aksrt-widget-repeater__template">';
|
|
self::group_row($widget, $field, [], $key, $token);
|
|
echo '</template><button type="button" class="button aksrt-widget-repeater__add">' . esc_html__('添加项目', 'aksrt') . '</button></div>';
|
|
}
|
|
|
|
private static function group_row(SchemaWidget $widget, array $field, array $row, string $key, string $index): void {
|
|
echo '<div class="aksrt-widget-repeater__row"><div class="aksrt-widget-repeater__bar"><span class="dashicons dashicons-move" aria-hidden="true"></span><strong>' . esc_html__('项目', 'aksrt') . '</strong><button type="button" class="button-link-delete aksrt-widget-repeater__remove">' . esc_html__('删除', 'aksrt') . '</button></div><div class="aksrt-widget-repeater__fields">';
|
|
foreach ((array) ($field['fields'] ?? []) as $child) {
|
|
$child_id = (string) ($child['id'] ?? '');
|
|
self::field($widget, $child, $row[$child_id] ?? ($child['default'] ?? ''), $key . '[' . $index . ']');
|
|
}
|
|
echo '</div></div>';
|
|
}
|
|
|
|
private static function nested(SchemaWidget $widget, array $field, array $value, string $key): void {
|
|
echo '<details class="aksrt-widget-nested"><summary>' . esc_html((string) ($field['label'] ?? '更多设置')) . '</summary><div class="aksrt-widget-nested__body">';
|
|
foreach ((array) ($field['fields'] ?? []) as $child) {
|
|
$child_id = (string) ($child['id'] ?? '');
|
|
self::field($widget, $child, $value[$child_id] ?? ($child['default'] ?? ''), $key);
|
|
}
|
|
echo '</div></details>';
|
|
}
|
|
|
|
private static function plain_input(SchemaWidget $widget, string $key, string $value, string $type, string $placeholder): void {
|
|
$name = $widget->get_field_name($key);
|
|
$id = $widget->get_field_id(str_replace(['[', ']'], ['-', ''], $key));
|
|
echo '<input class="widefat" type="' . esc_attr($type) . '" id="' . esc_attr($id) . '" name="' . esc_attr($name) . '" value="' . esc_attr($value) . '" placeholder="' . esc_attr($placeholder) . '">';
|
|
}
|
|
}
|