| 1 |
<?php |
| 2 |
trait WPJAM_Call_Trait{ |
| 3 |
public function call($name, ...$args){ |
| 4 |
if(is_string($name) && static::mod($name, '_by_model')){ |
| 5 |
$cb = [$this->model, $name]; |
| 6 |
}else{ |
| 7 |
$cb = is_closure($name) ? $name : $this->$name; |
| 8 |
$cb = is_closure($cb) ? $cb->bindTo($this, $this) : $cb; |
| 9 |
} |
| 10 |
|
| 11 |
return wpjam_call($cb, ...$args); |
| 12 |
} |
| 13 |
|
| 14 |
public function try($name, ...$args){ |
| 15 |
return wpjam_try([$this, $name], ...$args); |
| 16 |
} |
| 17 |
|
| 18 |
public function catch($name, ...$args){ |
| 19 |
return wpjam_catch([$this, $name], ...$args); |
| 20 |
} |
| 21 |
|
| 22 |
protected function call_dynamic_method($name, ...$args){ |
| 23 |
return $this->call(wpjam_dynamic_method(static::class, $name), ...$args); |
| 24 |
} |
| 25 |
|
| 26 |
public static function add_dynamic_method($name, $closure){ |
| 27 |
wpjam_dynamic_method(static::class, $name, $closure); |
| 28 |
} |
| 29 |
|
| 30 |
public static function mod(&$method, $mod){ |
| 31 |
if(str_ends_with($mod, '_')){ |
| 32 |
return try_prefix($method, '-', $mod); |
| 33 |
}elseif(str_starts_with($mod, '_')){ |
| 34 |
return try_suffix($method, '-', $mod); |
| 35 |
} |
| 36 |
|
| 37 |
if(($action = str_replace('_'.$mod.'_', '_', $method)) != $method){ |
| 38 |
$method = $action; |
| 39 |
return true; |
| 40 |
} |
| 41 |
|
| 42 |
return static::mod($method, $mod.'_') || static::mod($method, '_'.$mod); |
| 43 |
} |
| 44 |
|
| 45 |
protected static function get_param($name='', $method='data'){ |
| 46 |
return wpjam_param($name, $method); |
| 47 |
} |
| 48 |
|
| 49 |
public static function get_called(){ |
| 50 |
return strtolower(static::class); |
| 51 |
} |
| 52 |
} |
| 53 |
|
| 54 |
trait WPJAM_Items_Trait{ |
| 55 |
use WPJAM_Call_Trait; |
| 56 |
|
| 57 |
public function get_items($field=''){ |
| 58 |
return $field == ':field' |
| 59 |
? (wpjam_get_annotation(static::class, 'items_field') ?: '_items') |
| 60 |
: ($this->{$field ?: $this->get_items(':field')} ?: []); |
| 61 |
} |
| 62 |
|
| 63 |
public function update_items($items, $field=''){ |
| 64 |
$this->{$field ?: $this->get_items(':field')} = $items; |
| 65 |
|
| 66 |
return $this; |
| 67 |
} |
| 68 |
|
| 69 |
public function process_items($cb, $field='', ...$args){ |
| 70 |
$field = $field ?: $this->get_items(':field'); |
| 71 |
$items = $this->get_items($field); |
| 72 |
|
| 73 |
try{ |
| 74 |
if(count($args) == 3){ |
| 75 |
[$item, $key, $action] = $args; |
| 76 |
|
| 77 |
$args[] = $field; |
| 78 |
$add = $action === 'add'; |
| 79 |
|
| 80 |
if(isset($key) ? wpjam_exists($items, $key) === $add : !$add){ |
| 81 |
wpjam_throw('invalid_item_key', isset($key) ? '「'.$key.'」'.($add ? '已' : '不').'存在,无法'.(['add'=>'添加', 'update'=>'编辑', 'delete'=>'删除'][$action] ?? '操作') : 'key不能为空'); |
| 82 |
} |
| 83 |
|
| 84 |
if(isset($item)){ |
| 85 |
if($add && ($max = wpjam_get_annotation(static::class, 'max_items')) && count($items) >= $max){ |
| 86 |
wpjam_throw('quota_exceeded', '最多'.$max.'个'); |
| 87 |
} |
| 88 |
|
| 89 |
if(method_exists($this, 'validate_item')){ |
| 90 |
wpjam_if_error($this->validate_item(...$args), 'throw'); |
| 91 |
} |
| 92 |
|
| 93 |
if(method_exists($this, 'sanitize_item')){ |
| 94 |
$args[0] = $this->sanitize_item(...$args); |
| 95 |
} |
| 96 |
} |
| 97 |
} |
| 98 |
|
| 99 |
return $this->update_items(wpjam_call($cb, $items, ...$args), $field); |
| 100 |
}catch(Exception $e){ |
| 101 |
return wpjam_catch($e); |
| 102 |
} |
| 103 |
} |
| 104 |
|
| 105 |
public function get_item($key, $field=''){ |
| 106 |
return wpjam_get($this->get_items($field), $key); |
| 107 |
} |
| 108 |
|
| 109 |
public function get_item_arg($key, $arg, $field=''){ // deprecated |
| 110 |
return $this->get_item($key.'.'.$arg, $field); |
| 111 |
} |
| 112 |
|
| 113 |
public function add_item($key, ...$args){ |
| 114 |
[$key, $item] = ($args && !is_bool($key) && (is_scalar($key) || is_null($key))) ? [$key, array_shift($args)] : [null, $key]; |
| 115 |
|
| 116 |
return $this->process_items(fn($items, $item)=> wpjam_add_at($items, count($items), $key, $item), $args[0] ?? '', $item, $key, 'add'); |
| 117 |
} |
| 118 |
|
| 119 |
public function add_items($items, $field=''){ |
| 120 |
return wpjam_map($items, fn(...$args)=> $this->add_item(...[...array_pad($args, -2, null), $field]), wp_is_numeric_array($items) ? 'v' : 'kv'); |
| 121 |
} |
| 122 |
|
| 123 |
public function remove_item($item, $field=''){ |
| 124 |
return $this->process_items(fn($items)=> array_diff($items, [$item]), $field); |
| 125 |
} |
| 126 |
|
| 127 |
public function edit_item($key, $item, $field=''){ |
| 128 |
return $this->update_item($key, $item, $field); |
| 129 |
} |
| 130 |
|
| 131 |
public function update_item($key, $item, $field='', $action='update'){ |
| 132 |
return $this->process_items(fn($items, $item)=> array_replace($items, [$key=>$item]), $field, $item, $key, $action); |
| 133 |
} |
| 134 |
|
| 135 |
public function set_item($key, $item, $field=''){ |
| 136 |
return $this->update_item($key, $item, $field, 'set'); |
| 137 |
} |
| 138 |
|
| 139 |
public function delete_item($key, $field=''){ |
| 140 |
return wpjam_tap( |
| 141 |
$this->process_items(fn($items)=> wpjam_except($items, $key), $field, null, $key, 'delete'), |
| 142 |
fn()=> wpjam_call_method($this, 'after_delete_item', $key, $field) |
| 143 |
); |
| 144 |
} |
| 145 |
|
| 146 |
public function del_item($key, $field=''){ |
| 147 |
return $this->delete_item($key, $field); |
| 148 |
} |
| 149 |
|
| 150 |
public function move_item($orders, $field=''){ |
| 151 |
return $this->process_items(fn($items)=> array_merge(wpjam_pull($items, $orders), $items), $field); |
| 152 |
} |
| 153 |
|
| 154 |
public static function get_item_actions(){ |
| 155 |
$args = [ |
| 156 |
'row_action' => false, |
| 157 |
'value_callback'=> fn()=> '', |
| 158 |
'data_callback' => fn($id)=> wpjam_try([static::class, 'get_item'], $id, static::get_param('i'), static::get_param('_field')), |
| 159 |
'callback' => fn($id, $data, $action)=> wpjam_try([static::class, $action], $id, static::get_param($action == 'move_item' ? 'item' : 'i'), ...[...($action == 'del_item' ? [] : [$data]), static::get_param('_field')]) |
| 160 |
]; |
| 161 |
|
| 162 |
return [ |
| 163 |
'add_item' =>['page_title'=>'新增项目', 'title'=>'新增', 'dismiss'=>true]+array_merge($args, ['data_callback'=> fn()=> []]), |
| 164 |
'edit_item' =>['page_title'=>'修改项目', 'dashicon'=>'edit']+$args, |
| 165 |
'del_item' =>['page_title'=>'删除项目', 'dashicon'=>'no-alt', 'class'=>'del-icon', 'direct'=>true, 'confirm'=>true]+$args, |
| 166 |
'move_item' =>['page_title'=>'移动项目', 'dashicon'=>'move', 'class'=>'move-item', 'direct'=>true]+$args, |
| 167 |
]; |
| 168 |
} |
| 169 |
} |
| 170 |
|
| 171 |
class WPJAM_Args implements ArrayAccess, IteratorAggregate, JsonSerializable{ |
| 172 |
use WPJAM_Call_Trait; |
| 173 |
|
| 174 |
protected $args; |
| 175 |
|
| 176 |
public function __construct($args=[]){ |
| 177 |
$this->args = $args; |
| 178 |
} |
| 179 |
|
| 180 |
public function __get($key){ |
| 181 |
$args = $this->get_args(); |
| 182 |
|
| 183 |
return wpjam_exists($args, $key) ? $args[$key] : ($key == 'args' ? $args : null); |
| 184 |
} |
| 185 |
|
| 186 |
public function __set($key, $value){ |
| 187 |
$this->filter_args(); |
| 188 |
|
| 189 |
$this->args[$key] = $value; |
| 190 |
} |
| 191 |
|
| 192 |
public function __isset($key){ |
| 193 |
return wpjam_exists($this->get_args(), $key) ?: ($this->$key !== null); |
| 194 |
} |
| 195 |
|
| 196 |
public function __unset($key){ |
| 197 |
$this->filter_args(); |
| 198 |
|
| 199 |
unset($this->args[$key]); |
| 200 |
} |
| 201 |
|
| 202 |
#[ReturnTypeWillChange] |
| 203 |
public function offsetGet($key){ |
| 204 |
return $this->__get($key); |
| 205 |
} |
| 206 |
|
| 207 |
#[ReturnTypeWillChange] |
| 208 |
public function offsetSet($key, $value){ |
| 209 |
$this->__set($key, $value); |
| 210 |
} |
| 211 |
|
| 212 |
#[ReturnTypeWillChange] |
| 213 |
public function offsetExists($key){ |
| 214 |
return $this->__isset($key); |
| 215 |
} |
| 216 |
|
| 217 |
#[ReturnTypeWillChange] |
| 218 |
public function offsetUnset($key){ |
| 219 |
$this->__unset($key); |
| 220 |
} |
| 221 |
|
| 222 |
#[ReturnTypeWillChange] |
| 223 |
public function getIterator(){ |
| 224 |
return new ArrayIterator($this->get_args()); |
| 225 |
} |
| 226 |
|
| 227 |
#[ReturnTypeWillChange] |
| 228 |
public function jsonSerialize(){ |
| 229 |
return $this->get_args(); |
| 230 |
} |
| 231 |
|
| 232 |
protected function filter_args(){ |
| 233 |
return $this->args = $this->args ?: []; |
| 234 |
} |
| 235 |
|
| 236 |
public function get_args(){ |
| 237 |
return $this->filter_args(); |
| 238 |
} |
| 239 |
|
| 240 |
public function update_args($args, $replace=null){ |
| 241 |
$this->args = $replace === true ? $args : ($replace === false ? 'wp_parse_args' : 'array_replace')($this->get_args(), $args); |
| 242 |
|
| 243 |
return $this; |
| 244 |
} |
| 245 |
|
| 246 |
public function process_arg($key, $cb){ |
| 247 |
$value = wpjam_call($cb, $this->get_arg($key)); |
| 248 |
|
| 249 |
return is_null($value) ? $this->delete_arg($key) : $this->update_arg($key, $value); |
| 250 |
} |
| 251 |
|
| 252 |
public function get_arg($key, $default=null, $callback=false){ |
| 253 |
$value = wpjam_get($this->get_args(), $key); |
| 254 |
|
| 255 |
if($callback){ |
| 256 |
$value ??= is_string($key) ? wpjam_callback([$this->model, 'get_'.$key]) : null; |
| 257 |
$value = is_closure($value) ? $value->bindTo($this, $this) : $value; |
| 258 |
$value = $callback === 'callback' ? maybe_callback($value, $this->name) : $value; |
| 259 |
} |
| 260 |
|
| 261 |
return $value ?? $default; |
| 262 |
} |
| 263 |
|
| 264 |
public function update_arg($key, $value){ |
| 265 |
return $this->update_args(wpjam_set($this->get_args(), $key, $value), true); |
| 266 |
} |
| 267 |
|
| 268 |
public function delete_arg($key, ...$args){ |
| 269 |
return $this->update_args(wpjam_except($this->get_args(), $key, ...$args), true); |
| 270 |
} |
| 271 |
|
| 272 |
public function pull($key, ...$args){ |
| 273 |
$this->filter_args(); |
| 274 |
|
| 275 |
return wpjam_pull($this->args, $key, ...$args); |
| 276 |
} |
| 277 |
|
| 278 |
public function pick($keys){ |
| 279 |
return wpjam_pick($this, $keys); |
| 280 |
} |
| 281 |
|
| 282 |
public function to_array(){ |
| 283 |
return $this->get_args(); |
| 284 |
} |
| 285 |
|
| 286 |
public function sandbox($cb, ...$args){ |
| 287 |
try{ |
| 288 |
$archive = $this->get_args(); |
| 289 |
|
| 290 |
return wpjam_call($cb, ...$args); |
| 291 |
}finally{ |
| 292 |
$this->args = $archive; |
| 293 |
} |
| 294 |
} |
| 295 |
|
| 296 |
public function is_active(){ |
| 297 |
return true; |
| 298 |
} |
| 299 |
|
| 300 |
protected function parse_method($name){ |
| 301 |
$cb = array_find([[$this->model, $name], $this->$name], fn($v)=> wpjam_callback($v)); |
| 302 |
|
| 303 |
return is_closure($cb) ? $cb->bindTo($this, $this) : $cb; |
| 304 |
} |
| 305 |
|
| 306 |
public function call_method($name, ...$args){ |
| 307 |
return ($cb = $this->parse_method($name)) ? wpjam_try($cb, ...$args) : (str_starts_with($name, 'filter_') ? array_shift($args) : null); |
| 308 |
} |
| 309 |
} |
| 310 |
|
| 311 |
class WPJAM_Register extends WPJAM_Args{ |
| 312 |
use WPJAM_Items_Trait; |
| 313 |
|
| 314 |
public function __construct($name, $args=[]){ |
| 315 |
$this->args = $args = ['name'=>$name]+$args; |
| 316 |
|
| 317 |
if($this->is_active() || !empty($args['active'])){ |
| 318 |
$config = static::registry('get_arg', 'config') ?: []; |
| 319 |
$model = empty($config['model']) ? '' : ($args['model'] ?? ''); |
| 320 |
$file = ($model || !empty($args['hooks']) || !empty($args['init'])) ? wpjam_pull($args, 'file') : ''; |
| 321 |
|
| 322 |
$file && is_file($file) && include_once $file; |
| 323 |
|
| 324 |
if($model){ |
| 325 |
if(is_subclass_of($model, self::class)){ |
| 326 |
trigger_error('「'.(is_object($model) ? get_class($model) : $model).'」是 '.self::class.' 子类'); |
| 327 |
} |
| 328 |
|
| 329 |
if($config['model'] === 'object' && !is_object($model)){ |
| 330 |
if(class_exists($model, true)){ |
| 331 |
$model = $args['model'] = new $model(array_merge($args, ['object'=>$this])); |
| 332 |
}else{ |
| 333 |
trigger_error('model 无效'); |
| 334 |
} |
| 335 |
} |
| 336 |
|
| 337 |
foreach(['hooks'=>'add_hooks', 'init'=>'init'] as $k => $m){ |
| 338 |
if(($args[$k] ?? ($k == 'hooks' || ($config[$k] ?? false))) === true){ |
| 339 |
$args[$k] = wpjam_callback([$model, $m]); |
| 340 |
} |
| 341 |
} |
| 342 |
} |
| 343 |
} |
| 344 |
|
| 345 |
$this->args = $args; |
| 346 |
} |
| 347 |
|
| 348 |
protected function filter_args(){ |
| 349 |
$name = $this->args['name']; |
| 350 |
|
| 351 |
return in_array($name, static::registry('get_arg', 'filtered[]')) |
| 352 |
? $this->args |
| 353 |
: ($this->args = apply_filters(static::registry('update_arg', 'filtered[]', $name)->name.'_args', $this->args, $name)); |
| 354 |
} |
| 355 |
|
| 356 |
public function get_arg($key, $default=null, $callback=true){ |
| 357 |
return parent::get_arg($key, $default, $callback ? 'callback' : 'parse'); |
| 358 |
} |
| 359 |
|
| 360 |
public function get_parent(){ |
| 361 |
return $this->sub_name ? self::get($this->name) : null; |
| 362 |
} |
| 363 |
|
| 364 |
public function get_sub($name){ |
| 365 |
return self::get($this->name.':'.$name); |
| 366 |
} |
| 367 |
|
| 368 |
public function get_subs(){ |
| 369 |
return wpjam_array(self::get_by(['name'=>$this->name]), fn($k, $v)=> $v->sub_name); |
| 370 |
} |
| 371 |
|
| 372 |
public function register_sub($name, $args){ |
| 373 |
return self::register($this->name.':'.$name, new static($this->name, array_merge($args, ['sub_name'=>$name]))); |
| 374 |
} |
| 375 |
|
| 376 |
public function unregister_sub($name){ |
| 377 |
return self::unregister($this->name.':'.$name); |
| 378 |
} |
| 379 |
|
| 380 |
public static function registry($method, ...$args){ |
| 381 |
$called = static::class; |
| 382 |
$registry = wpjam_registry($called); |
| 383 |
|
| 384 |
if(!$registry->config){ |
| 385 |
$registry->config = wpjam_get_annotation($called, 'config')+['model'=>true]; |
| 386 |
$registry->defaults = method_exists($called, 'get_defaults') ? static::get_defaults() : []; |
| 387 |
} |
| 388 |
|
| 389 |
return wpjam_catch([$registry, $method], ...$args); |
| 390 |
} |
| 391 |
|
| 392 |
public static function register($name, $args=[]){ |
| 393 |
return static::registry('add_object', $name, $args); |
| 394 |
} |
| 395 |
|
| 396 |
public static function unregister($name, $args=[]){ |
| 397 |
static::registry('remove_object', $name, $args); |
| 398 |
} |
| 399 |
|
| 400 |
public static function get_registereds($args=[], $output='objects', $operator='and'){ |
| 401 |
wpjam_map(static::registry('pull', 'defaults'), [static::class, 'register'], 'kv'); |
| 402 |
|
| 403 |
$objects = static::registry('get_objects', $args, $operator); |
| 404 |
|
| 405 |
return $output == 'names' ? array_keys($objects) : $objects; |
| 406 |
} |
| 407 |
|
| 408 |
public static function get_by(...$args){ |
| 409 |
return self::get_registereds(...((!$args || is_array($args[0])) ? $args : [[$args[0]=> $args[1]]])); |
| 410 |
} |
| 411 |
|
| 412 |
public static function get($name, $by='registered', $top=''){ |
| 413 |
if($name && $by == 'registered'){ |
| 414 |
return static::registry('get_object', $name) ?: static::register($name, static::registry('pull', 'defaults['.$name.']')); |
| 415 |
} |
| 416 |
|
| 417 |
if($name && $by == 'model' && strcasecmp($name, $top) !== 0){ |
| 418 |
return array_find(static::get_registereds(), fn($v)=> is_string($v->model) && strcasecmp($name, $v->model) === 0) ?: static::get(get_parent_class($name), $by, $top); |
| 419 |
} |
| 420 |
} |
| 421 |
|
| 422 |
public static function get_setting_fields($args=[]){ |
| 423 |
$objects = array_filter(static::get_registereds(wpjam_pull($args, 'filter_args')), fn($v)=> !isset($v->active)); |
| 424 |
$options = wpjam_options($objects, $args); |
| 425 |
|
| 426 |
if(($args['type'] ?? '') == 'select'){ |
| 427 |
$name = wpjam_pull($args, 'name'); |
| 428 |
$args += ['options'=>$options]; |
| 429 |
|
| 430 |
return $name ? [$name => $args] : $args; |
| 431 |
} |
| 432 |
|
| 433 |
return $options; |
| 434 |
} |
| 435 |
|
| 436 |
public static function get_active($key=null){ |
| 437 |
return wpjam_array(static::get_registereds(), fn($k, $v)=> ($v->active ?? $v->is_active()) ? [$k, $key ? $v->get_arg($key) : $v] : null, true); |
| 438 |
} |
| 439 |
|
| 440 |
public static function by_active(...$args){ |
| 441 |
return self::call_active((did_action(current_filter()) ? 'on_' : 'filter_').wpjam_suffix(current_filter(), '-', 'wpjam_'), ...$args); |
| 442 |
} |
| 443 |
|
| 444 |
public static function call_active($method, ...$args){ |
| 445 |
$type = array_find(['filter', 'get'], fn($t)=> str_starts_with($method, $t.'_')); |
| 446 |
|
| 447 |
foreach(static::get_active() as $object){ |
| 448 |
$res = $object->call_method($method, ...$args); |
| 449 |
|
| 450 |
if($type == 'filter'){ |
| 451 |
$args[0] = $res; |
| 452 |
}elseif($type == 'get'){ |
| 453 |
$return = array_merge($return ?? [], is_array($res) ? $res : []); |
| 454 |
} |
| 455 |
} |
| 456 |
|
| 457 |
if($type == 'filter'){ |
| 458 |
return $args[0]; |
| 459 |
}elseif($type == 'get'){ |
| 460 |
return $return ?? []; |
| 461 |
} |
| 462 |
} |
| 463 |
} |
| 464 |
|
| 465 |
class WPJAM_Registry extends WPJAM_Args{ |
| 466 |
public function add_object(...$args){ |
| 467 |
$count = count($this->objects ?: []); |
| 468 |
$called = $this->called ?: 'WPJAM_Args'; |
| 469 |
|
| 470 |
if(is_object($args[0]) || is_array($args[0])){ |
| 471 |
$v = $args[0]; |
| 472 |
$k = is_object($v) ? $v->name : (wpjam_pull($v, 'name') ?: ($args[1] ?: '__'.$count)); |
| 473 |
}else{ |
| 474 |
[$k, $v] = $args; |
| 475 |
} |
| 476 |
|
| 477 |
if(is_null($v)){ |
| 478 |
return; |
| 479 |
} |
| 480 |
|
| 481 |
if($e = $k ? (is_numeric($k) ? '「'.$k.'」为纯数字' : (is_string($k) ? '' : '「'.var_export($k, true).'」不为字符串')) : '为空'){ |
| 482 |
return trigger_error($this->name.'的注册 name'.$e) && false; |
| 483 |
} |
| 484 |
|
| 485 |
if(is_array($v)){ |
| 486 |
if(!empty($v['admin']) && !is_admin()){ |
| 487 |
return; |
| 488 |
} |
| 489 |
|
| 490 |
$v = new $called(...(is_subclass_of($called, 'WPJAM_Register') ? [$k, $v] : [$v+['name'=>$k]])); |
| 491 |
} |
| 492 |
|
| 493 |
$this->get_object($k) && trigger_error($this->name.'「'.$k.'」已经注册。'); |
| 494 |
|
| 495 |
$this->update_arg('objects['.$k.']', $v); |
| 496 |
|
| 497 |
if(wpjam_call_method($v, 'is_active') || $v->active){ |
| 498 |
wpjam_hooks(maybe_callback($v->pull('hooks'))); |
| 499 |
|
| 500 |
wpjam_init($v->pull('init')); |
| 501 |
|
| 502 |
wpjam_call_method($v, 'registered'); |
| 503 |
} |
| 504 |
|
| 505 |
$count == 0 && wpjam_hooks($called.'::add_hooks'); |
| 506 |
|
| 507 |
return $v; |
| 508 |
} |
| 509 |
|
| 510 |
public function remove_object($k){ |
| 511 |
$this->delete_arg('objects['.$k.']'); |
| 512 |
} |
| 513 |
|
| 514 |
public function get_object($k){ |
| 515 |
return $this->get_arg('objects['.$k.']'); |
| 516 |
} |
| 517 |
|
| 518 |
public function get_objects(...$args){ |
| 519 |
$objects = wpjam_filter($this->objects ?: [], ...$args); |
| 520 |
$by = $this->get_arg('config[orderby]'); |
| 521 |
|
| 522 |
return $by ? wpjam_sort($objects, ($by === true ? 'order' : $by), ($this->get_arg('config[order]') ?? 'DESC'), 10) : $objects; |
| 523 |
} |
| 524 |
|
| 525 |
public function on(...$args){ |
| 526 |
foreach($this as $name => $registry){ |
| 527 |
foreach(current_action() == 'wpjam_api' ? ['register_json'] : ['menu_page', 'admin_load'] as $key){ |
| 528 |
if($registry->get_arg('config['.$key.']')){ |
| 529 |
if($key == 'register_json'){ |
| 530 |
[$registry->called, 'call_active']('register_json', $args[0]); |
| 531 |
}else{ |
| 532 |
wpjam_add($key, array_values([$registry->called, 'get_active']($key))); |
| 533 |
} |
| 534 |
} |
| 535 |
} |
| 536 |
} |
| 537 |
} |
| 538 |
|
| 539 |
public static function get_instance($name, $args=[]){ |
| 540 |
static $object; |
| 541 |
$object ??= new static(); |
| 542 |
|
| 543 |
if(!$object->get_args()){ |
| 544 |
wpjam_hooks('wpjam_api, wpjam_admin_init', [$object, 'on']); |
| 545 |
} |
| 546 |
|
| 547 |
return $object->$name ??= new static(['name'=>$name, 'called'=> is_subclass_of($name, 'WPJAM_Args') ? $name : null]+$args); |
| 548 |
} |
| 549 |
} |
| 550 |
|
| 551 |
class WPJAM_Data_Type extends WPJAM_Args{ |
| 552 |
public function get_path($args, $item){ |
| 553 |
return wpjam_if_error(wpjam_call_method($this->model.'::get_path', $args, $item), 'throw'); |
| 554 |
} |
| 555 |
|
| 556 |
public function with_field($action, $value, $field){ |
| 557 |
$res = ($cb = $this->model.'::with_field') && wpjam_callback($cb) ? wpjam_try($cb, $action, $field, $value) : ($this->{$action.'_value'} ? $this->call($action.'_value', $value, $field) : $value); |
| 558 |
|
| 559 |
return $action == 'validate' && is_null($res) ? wpjam_throw('invalid_field_value', $field->_title.'「'.$value.'」的值无效') : $res; |
| 560 |
} |
| 561 |
|
| 562 |
public function query_label($value){ |
| 563 |
if($value && $this->model && $this->label_field){ |
| 564 |
if(is_array($value)){ |
| 565 |
wpjam_call_method($this->model.'::update_caches', $value); |
| 566 |
|
| 567 |
return array_map(fn($v)=> ($l = $this->query_label($v)) ? ['label'=>$l, 'value'=>$v] : $v, $value); |
| 568 |
} |
| 569 |
|
| 570 |
return ($this->model::get($value) ?: [])[$this->label_field] ?? null; |
| 571 |
} |
| 572 |
} |
| 573 |
|
| 574 |
public function query_items($args){ |
| 575 |
$args = array_filter($args ?: [], fn($v)=> !is_null($v))+['number'=>10, 'data_type'=>true]; |
| 576 |
|
| 577 |
if($this->query_items){ |
| 578 |
return wpjam_try($this->query_items, $args); |
| 579 |
} |
| 580 |
|
| 581 |
if($this->model){ |
| 582 |
$args = isset($args['model']) ? wpjam_except($args, ['data_type', 'model', 'label_field', 'id_field']) : $args; |
| 583 |
$res = wpjam_try($this->model.'::query_items', $args, 'items'); |
| 584 |
$items = wp_is_numeric_array($res) ? $res : ($res['items'] ?? []); |
| 585 |
|
| 586 |
return $this->label_field ? wpjam_column($items, ['label'=>$this->label_field, 'value'=>$this->id_field]) : $items; |
| 587 |
} |
| 588 |
|
| 589 |
return []; |
| 590 |
} |
| 591 |
|
| 592 |
public function nonce_action($args){ |
| 593 |
return $this->name.':'.wpjam_json_encode(wpjam_sort(wpjam_except($args, ['search', 'exclude', 'parent']), 'k')); |
| 594 |
} |
| 595 |
|
| 596 |
public static function register($name, $args=[]){ |
| 597 |
return wpjam_register(static::class, $name, $args); |
| 598 |
} |
| 599 |
|
| 600 |
public static function get_instance($name, $args=[]){ |
| 601 |
if(!$name){ |
| 602 |
return; |
| 603 |
} |
| 604 |
|
| 605 |
$model = ''; |
| 606 |
|
| 607 |
if($name == 'model'){ |
| 608 |
$model = $args[$name] ?? ''; |
| 609 |
$name = $model && class_exists($model) ? wpjam_join(':', $model, $args['label_field'], $args['id_field']) : ''; |
| 610 |
} |
| 611 |
|
| 612 |
if($object = wpjam_get_registered(static::class, $name) ?? self::register($name, $model ? $args : ([ |
| 613 |
'post_type' => ['model'=>'WPJAM_Post', 'schema'=>['type'=>'integer'], 'label_field'=>'post_title', 'id_field'=>'ID'], |
| 614 |
'taxonomy' => ['model'=>'WPJAM_Term', 'schema'=>['type'=>'integer'], 'label_field'=>'name', 'id_field'=>'term_id'], |
| 615 |
'author' => ['model'=>'WPJAM_User', 'schema'=>['type'=>'integer'], 'label_field'=>'display_name', 'id_field'=>'ID'], |
| 616 |
'video' => ['parse_value'=>'wpjam_get_video_mp4'], |
| 617 |
][$name] ?? null))){ |
| 618 |
if($model){ |
| 619 |
$object->validate_value ??= fn($v)=> wpjam_try($args['model'].'::get', $v) ? $v : null; |
| 620 |
} |
| 621 |
|
| 622 |
if($object->model){ |
| 623 |
$object->meta_type ??= wpjam_call_method($object->model.'::get_meta_type') ?: ''; |
| 624 |
} |
| 625 |
} |
| 626 |
|
| 627 |
return $object; |
| 628 |
} |
| 629 |
} |
| 630 |
|
| 631 |
class WPJAM_JSON extends WPJAM_Register{ |
| 632 |
public function __invoke(){ |
| 633 |
$method = $this->method ?: $_SERVER['REQUEST_METHOD']; |
| 634 |
$attr = $method != 'POST' && !str_ends_with($this->name, '.config') ? ['page_title', 'share_title', 'share_image'] : []; |
| 635 |
$response = wpjam_try('apply_filters', 'wpjam_pre_json', [], $this, $this->name); |
| 636 |
$response += ['errcode'=>0, 'current_user'=>wpjam_try('wpjam_get_current_user', $this->pull('auth'))]+$this->pick($attr); |
| 637 |
|
| 638 |
if($this->modules){ |
| 639 |
$modules = maybe_callback($this->modules, $this->name, $this->args); |
| 640 |
$results = array_map([static::class, 'parse_module'], wp_is_numeric_array($modules) ? $modules : [$modules]); |
| 641 |
}elseif($this->callback){ |
| 642 |
$fields = wpjam_try('maybe_callback', $this->fields ?: [], $this->name); |
| 643 |
$data = $this->fields ? ($fields ? wpjam_params($method, $fields) : []) : $this->args; |
| 644 |
$results[] = wpjam_try($this->pull('callback'), $data, $this->name); |
| 645 |
}elseif($this->template){ |
| 646 |
$results[] = is_file($this->template) ? include $this->template : ''; |
| 647 |
}else{ |
| 648 |
$results[] = wpjam_except($this->args, 'name'); |
| 649 |
} |
| 650 |
|
| 651 |
foreach($results as $v){ |
| 652 |
if(is_array($v)){ |
| 653 |
$response += wpjam_pull($v, $attr); |
| 654 |
$response = array_merge($response, $v); |
| 655 |
} |
| 656 |
} |
| 657 |
|
| 658 |
$response = apply_filters('wpjam_json', $response, $this->args, $this->name); |
| 659 |
|
| 660 |
foreach($attr as $k){ |
| 661 |
if(($v = $response[$k] ?? '') || $k != 'share_image'){ |
| 662 |
$response[$k] = $k == 'share_image' ? wpjam_get_thumbnail($v, '500x400') : html_entity_decode($v ?: wp_get_document_title()); |
| 663 |
} |
| 664 |
} |
| 665 |
|
| 666 |
return $response; |
| 667 |
} |
| 668 |
|
| 669 |
public static function redirect($name){ |
| 670 |
header('X-Content-Type-Options: nosniff'); |
| 671 |
|
| 672 |
rest_send_cors_headers(false); |
| 673 |
|
| 674 |
if('OPTIONS' === $_SERVER['REQUEST_METHOD']){ |
| 675 |
status_header(403); |
| 676 |
exit; |
| 677 |
} |
| 678 |
|
| 679 |
ini_set('display_errors', 0); |
| 680 |
|
| 681 |
wpjam_hook('wp_die_'.(array_find(['jsonp_', 'json_'], fn($v)=> wpjam_call('wp_is_'.$v.'request')) ?: '').'handler', fn()=> 'wpjam_die_handler'); |
| 682 |
|
| 683 |
if(!try_prefix($name, '-', 'mag.')){ |
| 684 |
return; |
| 685 |
} |
| 686 |
|
| 687 |
$name = wpjam_prefix($name, '-', 'mag.'); // � |
| 688 |
�容 |
| 689 |
$name = str_replace('/', '.', $name); |
| 690 |
|
| 691 |
($user = wpjam_get_current_user()) && ($user_id = $user['user_id'] ?? '') && wp_set_current_user($user_id); |
| 692 |
|
| 693 |
do_action('wpjam_api', wpjam_var('json', $name)); |
| 694 |
|
| 695 |
wpjam_send_json(wpjam_catch(self::get($name) ?: wp_die('接口未定义', 'invalid_api'))); |
| 696 |
} |
| 697 |
|
| 698 |
public static function get_defaults(){ |
| 699 |
return array_fill_keys(['post.list', 'post.calendar', 'post.get'], ['modules'=>[static::class, 'callback']])+[ |
| 700 |
'media.upload' => ['modules'=>['callback'=>[static::class, 'media']]], |
| 701 |
'site.config' => ['modules'=>['type'=>'config']], |
| 702 |
]; |
| 703 |
} |
| 704 |
|
| 705 |
public static function get_current(){ |
| 706 |
return wpjam_var('json'); |
| 707 |
} |
| 708 |
|
| 709 |
public static function get_rewrite_rule(){ |
| 710 |
return [ |
| 711 |
['api/([^/]+)/(.*?)\.json?$', ['module'=>'json', 'action'=>'mag.$matches[1].$matches[2]'], 'top'], |
| 712 |
['api/([^/]+)\.json?$', 'index.php?module=json&action=$matches[1]', 'top'], |
| 713 |
]; |
| 714 |
} |
| 715 |
|
| 716 |
public static function parse_module($module){ |
| 717 |
$type = wpjam_pull($module, 'type'); |
| 718 |
$cb = wpjam_pull($module, 'callback'); |
| 719 |
$args = $module['args'] ?? $module; |
| 720 |
$args = is_array($args) ? $args : wpjam_parse_shortcode_attr(stripslashes_deep($args), 'module'); |
| 721 |
|
| 722 |
if($cb){ |
| 723 |
return wpjam_try($cb, $args); |
| 724 |
} |
| 725 |
|
| 726 |
if($type == 'data_type'){ |
| 727 |
return wpjam_query('data_type', $args+['search'=>wpjam_param('s')]); |
| 728 |
}elseif($type == 'setting'){ |
| 729 |
return wpjam_setting($args); |
| 730 |
}elseif($type == 'config'){ |
| 731 |
return wpjam_config($args['group'] ?? ''); |
| 732 |
}elseif(in_array($type, ['post_type', 'taxonomy', 'media'])){ |
| 733 |
return wpjam_try(static::class.'::'.$type, $args); |
| 734 |
} |
| 735 |
} |
| 736 |
|
| 737 |
public static function post_type($args){ |
| 738 |
$action = wpjam_pull($args, 'action'); |
| 739 |
$output = wpjam_pull($args, 'output'); |
| 740 |
|
| 741 |
if($action == 'upload'){ |
| 742 |
return wpjam_media($args['media'] ?? '', ['media'=>true, 'output'=>$output, 'post_id'=>(int)wpjam_param('post_id', 'post')]); |
| 743 |
} |
| 744 |
|
| 745 |
$wp = $GLOBALS['wp']; |
| 746 |
$query = $GLOBALS['wp_query']; |
| 747 |
$object = wpjam_get_json('object'); |
| 748 |
$vars = $object->query_vars ??= $wp->query_vars; |
| 749 |
|
| 750 |
if(in_array($action, ['list', 'calendar'])){ |
| 751 |
$sub = $action == 'calendar' ? false : wpjam_pull($args, 'sub'); |
| 752 |
$args = array_diff_key($args, WPJAM_Post::get_default_args()); |
| 753 |
|
| 754 |
if($sub){ |
| 755 |
$query = wpjam_query($args); |
| 756 |
}else{ |
| 757 |
$vars = array_merge(wpjam_except($vars, ['module', 'action']), $args); |
| 758 |
$args += ['format'=>($action == 'calendar' ? 'date' : $action)]; |
| 759 |
|
| 760 |
$wp->query_vars = $vars = wpjam_parse_query_vars($vars, $action); |
| 761 |
$wp->query_posts(); |
| 762 |
} |
| 763 |
|
| 764 |
$parsed = wpjam_get_posts($query, $args); |
| 765 |
$result = []; |
| 766 |
|
| 767 |
if(!$sub && $action != 'calendar'){ |
| 768 |
$is = wpjam_is($query); |
| 769 |
$paged = $query->get('nopaging') ? 0 : ($query->get('paged') ?: 1); |
| 770 |
$result = (is_string($is) ? ['is'=>$is] : [])+['total'=>$query->found_posts]; |
| 771 |
$result += ['total_pages'=>$paged ? $query->max_num_pages : ($result['total'] ? 1 : 0), 'current_page'=>$paged ?: 1]; |
| 772 |
|
| 773 |
if($paged == 1 && !$query->get('s') && in_array($query->get('orderby') ?: 'date', ['date', 'post_date'], true)){ |
| 774 |
$result += ['next_cursor'=>($parsed && $result['total_pages'] > 1) ? array_last($parsed)['timestamp'] : 0]; |
| 775 |
} |
| 776 |
|
| 777 |
if($queried = $query->get_queried_object()){ |
| 778 |
if(in_array($is, ['category', 'tag', 'tax'], true)){ |
| 779 |
$result += ['current_taxonomy'=>$queried->taxonomy, 'current_term'=>wpjam_get_term($queried, $queried->taxonomy)]; |
| 780 |
}elseif($is === 'author'){ |
| 781 |
$result += ['current_author'=>wpjam_get_user($query->get('author'))]; |
| 782 |
}elseif($is === 'post_type_archive'){ |
| 783 |
$result += ['current_post_type'=>$queried->name]; |
| 784 |
} |
| 785 |
} |
| 786 |
} |
| 787 |
|
| 788 |
if(!$output && !$sub && ($type = $query->get('post_type')) && is_string($type)){ |
| 789 |
$output = wpjam_get_post_type_setting($type, 'plural'); |
| 790 |
} |
| 791 |
|
| 792 |
$output = $output ?: 'posts'; |
| 793 |
|
| 794 |
return apply_filters('wpjam_posts_json', $result+[$output=>$parsed], $query, $output); |
| 795 |
}elseif($action == 'get'){ |
| 796 |
$type = $args['post_type'] ??= ''; |
| 797 |
$type = $type === 'any' ? '' : $type; |
| 798 |
$status = $args['post_status'] ?? ''; |
| 799 |
$vars = ['cache_results'=>true]+($status ? ['status'=>$status] : [])+$vars; |
| 800 |
|
| 801 |
if($type){ |
| 802 |
!post_type_exists($type) && wp_die('invalid_post_type'); |
| 803 |
|
| 804 |
$name = $vars[(is_post_type_hierarchical($type) ? 'pagename' : 'name')] ?? ''; |
| 805 |
}else{ |
| 806 |
$map = wp_list_pluck(get_post_types(['_builtin'=>false, 'query_var'=>true], 'objects'), 'query_var')+['post'=>'name', 'page'=>'pagename']; |
| 807 |
|
| 808 |
$type = array_find_key($map, fn($v)=> !empty($vars[$v])); |
| 809 |
$name = $type ? $vars[$map[$type]] : null; |
| 810 |
} |
| 811 |
|
| 812 |
if(!$name){ |
| 813 |
$id = ($args['id'] ?? 0) ?: (int)wpjam_param('id', ['required'=>true]); |
| 814 |
$type ??= get_post_type($id); |
| 815 |
$vars = ['p'=>($type && (get_post_type($id) == $type)) ? $id : wp_die('invalid_post_id')]+$vars; |
| 816 |
} |
| 817 |
|
| 818 |
$vars['post_type'] = $type; |
| 819 |
$wp->query_vars = $vars; |
| 820 |
$wp->query_posts(); |
| 821 |
|
| 822 |
if(empty($id) && !$status && !$query->have_posts()){ |
| 823 |
$id = apply_filters('old_slug_redirect_post_id', null) ?: wp_die('invalid_post_id'); |
| 824 |
|
| 825 |
$wp->query_vars = ['post_type'=>'any', 'p'=>$id]+wpjam_except($vars, ['name', 'pagename']); |
| 826 |
$wp->query_posts(); |
| 827 |
} |
| 828 |
|
| 829 |
$parsed = $query->have_posts() ? array_first(wpjam_get_posts($query, $args)) : wp_die('invalid_parameter'); |
| 830 |
$output = $output ?: $parsed['post_type']; |
| 831 |
|
| 832 |
return wpjam_pull($parsed, ['share_title', 'share_image', 'share_data'])+[$output => $parsed]; |
| 833 |
} |
| 834 |
} |
| 835 |
|
| 836 |
public static function taxonomy($args){ |
| 837 |
$object = wpjam_get_taxonomy(wpjam_get($args, 'taxonomy')) ?: wpjam_throw('invalid_taxonomy'); |
| 838 |
$mapping = wpjam_array(wp_parse_args(wpjam_pull($args, 'mapping') ?: []), fn($k, $v)=> [$k, wpjam_param($v)], true); |
| 839 |
|
| 840 |
return [(wpjam_pull($args, 'output') ?: $object->plural) => array_values(wpjam_query('term', array_merge($args, $mapping)))]; |
| 841 |
} |
| 842 |
|
| 843 |
public static function media($args){ |
| 844 |
return wpjam_media($args['media'] ?? '', $args); |
| 845 |
} |
| 846 |
|
| 847 |
public static function callback($name, $args=[]){ |
| 848 |
$output = $args['output'] ?? null; |
| 849 |
|
| 850 |
[$type, $action] = explode('.', $name); |
| 851 |
|
| 852 |
if($type == 'post'){ |
| 853 |
$type = wpjam_param('post_type'); |
| 854 |
$output ??= $action == 'get' ? 'post' : 'posts'; |
| 855 |
} |
| 856 |
|
| 857 |
$modules[] = array_filter(['type'=>'post_type', 'post_type'=>$type, 'action'=>$action, 'output'=>$output]+array_intersect_key($args, WPJAM_Post::get_default_args()), fn($v)=> !is_null($v)); |
| 858 |
|
| 859 |
foreach($action == 'list' && $type && is_string($type) && !str_contains($type, ',') ? get_object_taxonomies($type) : [] as $tax){ |
| 860 |
if(is_taxonomy_hierarchical($tax) && wpjam_get_taxonomy_setting($tax, 'show_in_posts_rest')){ |
| 861 |
$modules[] = ['type'=>'taxonomy', 'taxonomy'=>$tax, 'hide_empty'=>0]; |
| 862 |
} |
| 863 |
} |
| 864 |
|
| 865 |
return $modules; |
| 866 |
} |
| 867 |
|
| 868 |
public static function add_hooks(){ |
| 869 |
wpjam_is_json_request() && wpjam_hooks('-', [ |
| 870 |
['the_title', 'convert_chars'], |
| 871 |
['init', ['wp_widgets_init', 'maybe_add_existing_user_to_blog']], |
| 872 |
['wp_loaded', ['_custom_header_background_just_in_time', '_add_template_loader_filters']], |
| 873 |
['plugins_loaded', ['wp_maybe_load_widgets', 'wp_maybe_load_embeds', '_wp_customize_include', '_wp_theme_json_webfonts_handler']] |
| 874 |
]); |
| 875 |
} |
| 876 |
|
| 877 |
public static function __callStatic($method, $args){ |
| 878 |
if(in_array($method, ['parse_post_list_module', 'parse_post_get_module'])){ |
| 879 |
return wpjam_catch('WPJAM_JSON::parse_module', [ |
| 880 |
'type' => 'post_type', |
| 881 |
'action' => str_replace(['parse_post_', '_module'], '', $method) |
| 882 |
]+($args[0] ?? [])); |
| 883 |
} |
| 884 |
} |
| 885 |
} |
| 886 |
|
| 887 |
/** |
| 888 |
* @config menu_page, admin_load, register_json, init, orderby |
| 889 |
**/ |
| 890 |
#[config('menu_page', 'admin_load', 'register_json', 'init', 'orderby')] |
| 891 |
class WPJAM_Option_Setting extends WPJAM_Register{ |
| 892 |
public function __invoke(){ |
| 893 |
flush_rewrite_rules(); |
| 894 |
|
| 895 |
$submit = $_POST['submit'] ?? ''; |
| 896 |
$values = $this->validate_by_fields(wpjam_params('data')) ?: []; |
| 897 |
$fix = is_network_admin() ? 'site_option' : 'option'; |
| 898 |
|
| 899 |
if($this->option_type == 'array'){ |
| 900 |
if($submit == 'reset'){ |
| 901 |
$values = wpjam_diff([$this, 'get_'.$fix](), $values, 'key'); |
| 902 |
}else{ |
| 903 |
$values = wpjam_filter(array_merge([$this, 'get_'.$fix](), $values), fn($v)=> !is_null($v), true); |
| 904 |
$values = $this->call_method('sanitize_callback', $values, $this->name) ?? $values; |
| 905 |
} |
| 906 |
|
| 907 |
$cb = $this->update_callback; |
| 908 |
$cb ? $cb($this->name, $values) : [$this, 'update_'.$fix]($values); |
| 909 |
}else{ |
| 910 |
wpjam_map($values, ...($submit == 'reset' ? ['delete_'.$fix, 'k'] : ['update_'.$fix, 'kv'])); |
| 911 |
} |
| 912 |
|
| 913 |
$errors = array_filter(get_settings_errors(), fn($e)=> !in_array($e['type'], ['updated', 'success', 'info'])); |
| 914 |
$errors && wp_die(implode(' ', array_column($errors, 'message'))); |
| 915 |
|
| 916 |
return [ |
| 917 |
'type' => (!$this->ajax || $submit == 'reset') ? 'redirect' : $submit, |
| 918 |
'notice' => $submit == 'reset' ? '设置已重置。' : '设置已保存。' |
| 919 |
]; |
| 920 |
} |
| 921 |
|
| 922 |
public function __call($method, $args){ |
| 923 |
$parts = explode('_', $method); |
| 924 |
$action = array_shift($parts); |
| 925 |
$type = array_pop($parts); |
| 926 |
|
| 927 |
if($type == 'fields'){ |
| 928 |
$fields = $action == 'render' ? array_shift($args) : array_merge(...array_column($this->get_sections($action !== 'validate'), 'fields')); |
| 929 |
|
| 930 |
return $action == 'get' ? $fields : wpjam_fields($fields, ['value_callback'=>[$this, 'value_callback']])->$action(...$args); |
| 931 |
}elseif($type == 'option' || $type == 'setting'){ |
| 932 |
$part = $parts ? '_'.$parts[0] : ''; |
| 933 |
|
| 934 |
if($part != '_site'){ |
| 935 |
$blog_id = $part == '_blog' ? array_shift($args) : $this->blog_id; |
| 936 |
$part = $blog_id && is_multisite() ? '_blog' : ''; |
| 937 |
} |
| 938 |
|
| 939 |
$params = $part == '_blog' ? [$blog_id] : []; |
| 940 |
|
| 941 |
if($type == 'option'){ |
| 942 |
$args = $action == 'update' ? [wpjam_if_error($args[0], [])] : []; |
| 943 |
$res = wpjam_call($action.$part.'_option', ...[...$params, $this->name, ...$args]); |
| 944 |
|
| 945 |
return $action == 'get' ? (wpjam_if_error($res, []) ?: []) : $res; |
| 946 |
} |
| 947 |
|
| 948 |
$name = $args[0] ?? null; |
| 949 |
$data = [$this, 'get'.$part.'_option'](...$params) ?: []; |
| 950 |
|
| 951 |
if($action == 'get'){ |
| 952 |
if(is_array($name)){ |
| 953 |
return wpjam_fill(array_filter($name), fn($n)=> [$this, 'get'.$part.'_setting'](...[...$params, $n])); |
| 954 |
} |
| 955 |
|
| 956 |
$site_default = $part != '_site' && is_multisite() && $this->site_default; |
| 957 |
|
| 958 |
if(!$name){ |
| 959 |
return $data+($site_default ? $this->get_site_option() : []); |
| 960 |
} |
| 961 |
|
| 962 |
$value = wpjam_if_error(wpjam_get(is_array($data) ? $data : [], $name), null); |
| 963 |
|
| 964 |
if(is_null($value)){ |
| 965 |
if($site_default){ |
| 966 |
return $this->get_site_setting(...$args); |
| 967 |
} |
| 968 |
|
| 969 |
if(count($args) >= 2){ |
| 970 |
return $args[1]; |
| 971 |
} |
| 972 |
|
| 973 |
if($this->field_default){ |
| 974 |
return wpjam_get(($this->_defaults ??= $this->get_defaults_by_fields()), $name); |
| 975 |
} |
| 976 |
} |
| 977 |
|
| 978 |
return is_string($value) ? str_replace("\r\n", "\n", trim($value)) : $value; |
| 979 |
} |
| 980 |
|
| 981 |
return [$this, 'update'.$part.'_option'](...[...$params, ($action == 'update' |
| 982 |
? wpjam_reduce(is_array($name) ? $name : [$name=>$args[1]], fn($c, $v, $n)=> wpjam_set($c, $n, $v), $data) |
| 983 |
: wpjam_except($data, $name) |
| 984 |
)]); |
| 985 |
} |
| 986 |
} |
| 987 |
|
| 988 |
public function get_arg($key, $default=null, $callback=true){ |
| 989 |
$value = parent::get_arg($key, $default, $callback); |
| 990 |
|
| 991 |
if($key == 'menu_page'){ |
| 992 |
if(!$this->name || (is_network_admin() && !$this->site_default)){ |
| 993 |
return; |
| 994 |
} |
| 995 |
|
| 996 |
if(!$value){ |
| 997 |
if(!$this->post_type || !$this->title){ |
| 998 |
return $value; |
| 999 |
} |
| 1000 |
|
| 1001 |
$value = ['parent'=>wpjam_get_post_type_setting($this->post_type, 'plural'), 'order'=>1]; |
| 1002 |
} |
| 1003 |
|
| 1004 |
if(wp_is_numeric_array($value)){ |
| 1005 |
return wpjam_array($value, function($k, $v){ |
| 1006 |
if(!empty($v['tab_slug']) && !empty($v['plugin_page'])){ |
| 1007 |
return [$k, $v]; |
| 1008 |
}elseif(!empty($v['menu_slug'])){ |
| 1009 |
return [$k, $v+($v['menu_slug'] == $this->name ? ['menu_title'=>$this->title] : [])]; |
| 1010 |
} |
| 1011 |
}); |
| 1012 |
} |
| 1013 |
|
| 1014 |
$value += ($value['function'] ??= 'option') == 'option' ? ['option_name'=>$this->name] : []; |
| 1015 |
|
| 1016 |
if(!empty($value['tab_slug'])){ |
| 1017 |
return ($value['plugin_page'] ??= $this->plugin_page) ? $value+['title'=>$this->title] : null; |
| 1018 |
} |
| 1019 |
|
| 1020 |
$value += ['menu_slug'=>$this->plugin_page ?: $this->name, 'menu_title'=>$this->title]; |
| 1021 |
}elseif($key == 'admin_load'){ |
| 1022 |
$value = wp_is_numeric_array($value) ? $value : ($value ? [$value] : []); |
| 1023 |
$value = array_map(fn($v)=> ($this->model && !isset($v['callback']) && !isset($v['model'])) ? $v+['model'=>$this->model] : $v, $value); |
| 1024 |
}elseif($key == 'sections'){ |
| 1025 |
if(!$value || !is_array($value)){ |
| 1026 |
$id = $this->type == 'section' ? (string)$this->section_id : ($this->current_tab ?: $this->sub_name ?: $this->name); |
| 1027 |
$value = [$id=>array_filter(['fields'=>$this->get_arg('fields', null, false)]) ?: $this->get_arg('section') ?: []]; |
| 1028 |
} |
| 1029 |
|
| 1030 |
$value = wpjam_array($value, fn($k, $v)=> is_array($v) && isset($v['fields']) ? [$k, ['fields'=>maybe_callback($v['fields'] ?? [], $k, $this->name)]+$v] : null); |
| 1031 |
} |
| 1032 |
|
| 1033 |
return $value; |
| 1034 |
} |
| 1035 |
|
| 1036 |
public function get_current($output=''){ |
| 1037 |
$args = wpjam_pick(wpjam_admin('vars'), ['plugin_page', 'current_tab']); |
| 1038 |
|
| 1039 |
return $output === 'args' ? $args : ($this->get_sub(wpjam_join(':', $args)) ?: $this); |
| 1040 |
} |
| 1041 |
|
| 1042 |
protected function get_sections($all=false, $filter=true){ |
| 1043 |
$sections = $this->get_arg('sections'); |
| 1044 |
$sections = count($sections) == 1 ? array_map(fn($s)=> $s+['title'=>$this->title ?: ''], $sections) : $sections; |
| 1045 |
$sections = array_reduce($all ? $this->get_subs() : [], fn($c, $v)=> array_merge($c, $v->get_sections(false, false)), $sections); |
| 1046 |
|
| 1047 |
if(!$filter){ |
| 1048 |
return $sections; |
| 1049 |
} |
| 1050 |
|
| 1051 |
$args = $all ? [] : wpjam_map(self::get_current('args'), fn($v)=> ['value'=>$v, 'if_null'=>true]); |
| 1052 |
$objects = wpjam_sort(self::get_by(['type'=>'section', 'name'=>$this->name]+$args), 'order', 'desc', 10); |
| 1053 |
|
| 1054 |
foreach(array_reverse(array_filter($objects, fn($v)=> $v->order > 10))+$objects as $object){ |
| 1055 |
foreach(($object->get_arg('sections') ?: []) as $id => $section){ |
| 1056 |
$id = $id ?: array_key_first($sections); |
| 1057 |
$exist = isset($sections[$id]) ? ($object->order > 10 ? wpjam_merge($section, $sections[$id]) : $sections[$id]) : []; // 字段靠前 |
| 1058 |
$sections = wpjam_set($sections, $id, wpjam_merge($exist, $section)); |
| 1059 |
} |
| 1060 |
} |
| 1061 |
|
| 1062 |
return apply_filters('wpjam_option_setting_sections', array_filter($sections, fn($v)=> isset($v['title'], $v['fields'])), $this->name); |
| 1063 |
} |
| 1064 |
|
| 1065 |
public function add_section(...$args){ |
| 1066 |
$keys = ['model', 'fields', 'section']; |
| 1067 |
$args = is_array($args[0]) ? $args[0] : ['section_id'=>$args[0]]+(array_any($keys, fn($k)=> isset($args[1][$k])) ? $args[1] : ['fields'=>$args[1]]); |
| 1068 |
$args = array_any([...$keys, 'sections'], fn($k)=>isset($args[$k])) ? $args : ['sections'=>$args]; |
| 1069 |
|
| 1070 |
return self::register(md5(wpjam_serialize($args)), new static($this->name, $args+['type'=>'section'])); |
| 1071 |
} |
| 1072 |
|
| 1073 |
public function value_callback($name=''){ |
| 1074 |
return $this->option_type == 'array' ? (is_network_admin() ? $this->get_site_setting($name) : $this->get_setting($name)) : get_option($name, null); |
| 1075 |
} |
| 1076 |
|
| 1077 |
public function render($page){ |
| 1078 |
$nav = $page->tab_slug ? '' : wpjam_tag('h2', ['nav-tab-wrapper', 'wp-clearfix']); |
| 1079 |
$form = wpjam_tag('form', ['method'=>'POST', 'id'=>'wpjam_option', 'novalidate']); |
| 1080 |
$tabs = []; |
| 1081 |
|
| 1082 |
foreach($this->get_sections() as $id => $sec){ |
| 1083 |
$nav && $nav->append('a', ['class'=>'nav-tab', 'href'=>'#tab_'.$id, 'data'=>wpjam_pick($sec, ['show_if'])], $sec['title']); |
| 1084 |
|
| 1085 |
$tabs[] = wpjam_tag($nav ? 'div' : '', ['id'=>'tab_'.$id, 'class'=>'tab'])->append([ |
| 1086 |
[$nav ? 'h2' : 'h3', [], $sec['title']], |
| 1087 |
wpjam_ob($sec['callback'] ?? '', $sec), |
| 1088 |
wpautop($sec['summary'] ?? ''), |
| 1089 |
$this->render_fields($sec['fields']) |
| 1090 |
]); |
| 1091 |
} |
| 1092 |
|
| 1093 |
$form->data('nonce', wp_create_nonce($this->option_group))->append([ |
| 1094 |
...(count($tabs) == 1 ? [$tabs[0]->tag('')] : $tabs), |
| 1095 |
wpjam_tag('p', ['submit'])->append([ |
| 1096 |
get_submit_button('', 'primary', 'save', false), |
| 1097 |
$this->reset ? get_submit_button('重置选项', 'secondary', 'reset', false) : '' |
| 1098 |
]) |
| 1099 |
]); |
| 1100 |
|
| 1101 |
return count($tabs) > 1 && $nav ? $form->before($nav)->wrap('div', ['tabs']) : $form; |
| 1102 |
} |
| 1103 |
|
| 1104 |
public function page_load(){ |
| 1105 |
wpjam_ajax('wpjam-option-action', [ |
| 1106 |
'admin' => true, |
| 1107 |
'callback' => $this, |
| 1108 |
'nonce_action' => fn()=> $this->option_group, |
| 1109 |
'allow' => fn()=> current_user_can($this->capability) |
| 1110 |
]); |
| 1111 |
} |
| 1112 |
|
| 1113 |
public static function create($name, $args){ |
| 1114 |
$args = maybe_callback($args, $name)+[ |
| 1115 |
'option_group' => $name, |
| 1116 |
'option_page' => $name, |
| 1117 |
'option_type' => 'array', |
| 1118 |
'capability' => 'manage_options', |
| 1119 |
'ajax' => true |
| 1120 |
]; |
| 1121 |
|
| 1122 |
if($sub = wpjam_pick($args, ['plugin_page', 'current_tab'])){ |
| 1123 |
$rest = wpjam_except($args, ['model', 'menu_page', 'admin_load', 'plugin_page', 'current_tab']); |
| 1124 |
}else{ |
| 1125 |
$args = ['primary'=>true]+$args; |
| 1126 |
} |
| 1127 |
|
| 1128 |
if($object = self::get($name)){ |
| 1129 |
if(!$sub && $object->primary && trigger_error('option_setting'.'「'.$name.'」已经注册。'.var_export($args, true))){ |
| 1130 |
return $object; |
| 1131 |
} |
| 1132 |
|
| 1133 |
$object->update_args($sub ? wpjam_except($rest, 'title') : $args); |
| 1134 |
}else{ |
| 1135 |
$args['option_type'] == 'array' && !doing_filter('sanitize_option_'.$name) && is_null(get_option($name, null)) && add_option($name, []); |
| 1136 |
|
| 1137 |
$object = self::register($name, $sub ? $rest : $args); |
| 1138 |
} |
| 1139 |
|
| 1140 |
return $sub ? $object->register_sub(wpjam_join(':', $sub), $args) : $object; |
| 1141 |
} |
| 1142 |
|
| 1143 |
public static function get_instance($name, ...$args){ |
| 1144 |
if($args && in_array($args[0], ['model', 'registered'], true)){ |
| 1145 |
return self::get($name, ...$args); |
| 1146 |
}elseif($args && $args[0] === 'object'){ |
| 1147 |
array_shift($args); |
| 1148 |
} |
| 1149 |
|
| 1150 |
$blog_id = is_multisite() ? ($args[0] ?? 0) : 0; |
| 1151 |
$object = $blog_id ? (!is_numeric($blog_id) && trigger_error($name.':'.$blog_id) && false) : self::get($name); |
| 1152 |
|
| 1153 |
return $object ?: wpjam_var('option:'.wpjam_join('-', $name, $blog_id), fn()=> new static($name, ['blog_id'=>$blog_id])); |
| 1154 |
} |
| 1155 |
} |
| 1156 |
|
| 1157 |
class WPJAM_Meta_Type extends WPJAM_Register{ |
| 1158 |
public function __call($method, $args){ |
| 1159 |
if(in_array($method, ['get_data', 'add_data', 'update_data', 'delete_data', 'data_exists'])){ |
| 1160 |
$args = [$this->name, ...$args]; |
| 1161 |
$cb = str_replace('data', 'metadata', $method); |
| 1162 |
}elseif($this->mod($method, '_by_mid')){ |
| 1163 |
$args = [$this->name, ...$args]; |
| 1164 |
$cb = $method.'_metadata_by_mid'; |
| 1165 |
}elseif($this->mod($method, '_meta')){ |
| 1166 |
$cb = [$this, $method.'_data']; |
| 1167 |
}elseif($this->mod($method, 'meta')){ |
| 1168 |
$cb = [$this, $method]; |
| 1169 |
} |
| 1170 |
|
| 1171 |
return $cb(...$args); |
| 1172 |
} |
| 1173 |
|
| 1174 |
public function get_options($args=[]){ |
| 1175 |
if($this->name == 'post'){ |
| 1176 |
$key = 'post_type'; |
| 1177 |
$cb = 'wpjam_get_post_type_object'; |
| 1178 |
}elseif($this->name == 'term'){ |
| 1179 |
$key = 'taxonomy'; |
| 1180 |
$cb = 'wpjam_get_taxonomy'; |
| 1181 |
} |
| 1182 |
|
| 1183 |
if(isset($key) && isset($args[$key])){ |
| 1184 |
$args[$key] = ['value'=>($value = $args[$key]), 'if_null'=>true, 'callable'=>true]; |
| 1185 |
$object = $cb($value); |
| 1186 |
|
| 1187 |
$object && ($this->call_option($value.'_base') || $this->call_option($value.'_base', [ |
| 1188 |
$key => $value, |
| 1189 |
'title' => $this->name == 'post' ? '基础信息' : '快速编辑', |
| 1190 |
'row_action' => $this->name == 'term', |
| 1191 |
'action_name' => 'set', |
| 1192 |
'page_title' => '设置'.$object->title, |
| 1193 |
'fields' => [$object, 'get_fields'], |
| 1194 |
'list_table' => $object->show_ui, |
| 1195 |
'order' => 99, |
| 1196 |
])); |
| 1197 |
} |
| 1198 |
|
| 1199 |
if(isset($args['list_table'])){ |
| 1200 |
$args['title'] = true; |
| 1201 |
$args['list_table'] = $args['list_table'] ? true : ['compare'=>'!==', 'value'=>'only']; |
| 1202 |
} |
| 1203 |
|
| 1204 |
return wpjam_sort(wpjam_filter($this->get_arg('options[]'), $args), 'order', 'DESC', 10); |
| 1205 |
} |
| 1206 |
|
| 1207 |
public function call_option($name, ...$args){ |
| 1208 |
$del = try_prefix($name, '-', '-'); |
| 1209 |
$key = 'options['.$name.']'; |
| 1210 |
|
| 1211 |
if($del){ |
| 1212 |
return $this->delete_arg($key) && true; |
| 1213 |
} |
| 1214 |
|
| 1215 |
if($args){ |
| 1216 |
$args = $args[0]; |
| 1217 |
|
| 1218 |
if($this->name == 'post'){ |
| 1219 |
$args += ['fields'=>[], 'priority'=>'default']; |
| 1220 |
|
| 1221 |
$args['post_type'] ??= wpjam_pull($args, 'post_types') ?: null; |
| 1222 |
}elseif($this->name == 'term'){ |
| 1223 |
$args['taxonomy'] ??= wpjam_pull($args, 'taxonomies') ?: null; |
| 1224 |
|
| 1225 |
if(!isset($args['fields'])){ |
| 1226 |
$args['fields'] = [$name => wpjam_except($args, 'taxonomy')]; |
| 1227 |
$args['from_field'] = true; |
| 1228 |
} |
| 1229 |
} |
| 1230 |
|
| 1231 |
$this->update_arg($key, new WPJAM_Meta_Option(['name'=>$name, 'meta_type'=>$this->name]+$args)); |
| 1232 |
} |
| 1233 |
|
| 1234 |
return $this->get_arg($key); |
| 1235 |
} |
| 1236 |
|
| 1237 |
public function get_table(){ |
| 1238 |
return _get_meta_table($this->name); |
| 1239 |
} |
| 1240 |
|
| 1241 |
public function get_column($name='object_id'){ |
| 1242 |
return $name == 'id' |
| 1243 |
? ('user' == $this->name ? 'umeta_id' : 'meta_id') |
| 1244 |
: ($name == 'object_id' ? $this->name.'_id' : $name); |
| 1245 |
} |
| 1246 |
|
| 1247 |
public function get_data_with_default($id, ...$args){ |
| 1248 |
if(!$args){ |
| 1249 |
return $this->get_data($id); |
| 1250 |
} |
| 1251 |
|
| 1252 |
if($id && $args[0]){ |
| 1253 |
if(is_array($args[0])){ |
| 1254 |
return wpjam_array($args[0], fn($k, $v)=> [is_numeric($k) ? $v : $k, $this->get_data_with_default($id, ...(is_numeric($k) ? [$v, null] : [$k, $v]))]); |
| 1255 |
} |
| 1256 |
|
| 1257 |
if($args[0] == 'meta_input'){ |
| 1258 |
trigger_error('meta_input'); |
| 1259 |
return wpjam_map($this->get_data($id), fn($v, $k)=> $this->get_data($id, $k, true)); |
| 1260 |
} |
| 1261 |
|
| 1262 |
if($this->data_exists($id, $args[0])){ |
| 1263 |
return $this->get_data($id, $args[0], true); |
| 1264 |
} |
| 1265 |
} |
| 1266 |
|
| 1267 |
return is_array($args[0]) ? [] : ($args[1] ?? null); |
| 1268 |
} |
| 1269 |
|
| 1270 |
public function get_by_key($key, $value=null, $column=null){ |
| 1271 |
global $wpdb; |
| 1272 |
|
| 1273 |
$where = array_filter([ |
| 1274 |
$key ? $wpdb->prepare('meta_key=%s', $key) : '', |
| 1275 |
is_null($value) ? '' : $wpdb->prepare('meta_value=%s', maybe_serialize($value)) |
| 1276 |
]); |
| 1277 |
|
| 1278 |
if($where){ |
| 1279 |
$table = $this->get_table(); |
| 1280 |
$where = implode(' AND ', $where); |
| 1281 |
$data = $wpdb->get_results("SELECT * FROM {$table} WHERE {$where}", ARRAY_A) ?: []; |
| 1282 |
|
| 1283 |
return $data && $column ? array_first($data)[$this->get_column($column)] : array_map(fn($v)=> ['meta_value'=>maybe_unserialize($v['meta_value'])]+$v, $data); |
| 1284 |
} |
| 1285 |
|
| 1286 |
return $column ? null : []; |
| 1287 |
} |
| 1288 |
|
| 1289 |
public function update_data_with_default($id, $key, ...$args){ |
| 1290 |
if(is_array($key)){ |
| 1291 |
if(wpjam_is_assoc_array($key)){ |
| 1292 |
$defaults = $args && is_array($args[0]) ? $args[0] : []; |
| 1293 |
|
| 1294 |
if(isset($key['meta_input']) && wpjam_is_assoc_array($key['meta_input'])){ |
| 1295 |
$this->update_data_with_default($id, wpjam_pull($key, 'meta_input'), wpjam_pull($defaults, 'meta_input')); |
| 1296 |
} |
| 1297 |
|
| 1298 |
wpjam_map($key, fn($v, $k)=> $this->update_data_with_default($id, $k, $v, wpjam_pull($defaults, $k))); |
| 1299 |
} |
| 1300 |
|
| 1301 |
return true; |
| 1302 |
} |
| 1303 |
|
| 1304 |
[$value, $default] = array_pad($args, 2, null); |
| 1305 |
|
| 1306 |
if(is_closure($value)){ |
| 1307 |
$value = $value($this->get_data_with_default($id, $key, $default), $key, $id); |
| 1308 |
} |
| 1309 |
|
| 1310 |
if(is_array($value)){ |
| 1311 |
if($value && (!is_array($default) || array_diff_assoc($default, $value))){ |
| 1312 |
return $this->update_data($id, $key, $value); |
| 1313 |
} |
| 1314 |
}else{ |
| 1315 |
if(isset($value) && ((is_null($default) && ($value || is_numeric($value))) || (!is_null($default) && $value != $default))){ |
| 1316 |
return $this->update_data($id, $key, $value); |
| 1317 |
} |
| 1318 |
} |
| 1319 |
|
| 1320 |
return $this->delete_data($id, $key); |
| 1321 |
} |
| 1322 |
|
| 1323 |
public function delete_empty_data(){ |
| 1324 |
$wpdb = $GLOBALS['wpdb']; |
| 1325 |
$mids = $wpdb->get_col("SELECT ".$this->get_column('id')." FROM ".$this->get_table()." WHERE meta_value = ''") ?: []; |
| 1326 |
|
| 1327 |
array_walk($mids, [$this, 'delete_by_mid']); |
| 1328 |
} |
| 1329 |
|
| 1330 |
public function delete_by_key($key, $value=''){ |
| 1331 |
return delete_metadata($this->name, null, $key, $value, true); |
| 1332 |
} |
| 1333 |
|
| 1334 |
public function delete_by_id($id){ |
| 1335 |
$wpdb = $GLOBALS['wpdb']; |
| 1336 |
$table = $this->get_table(); |
| 1337 |
$column = $this->get_column(); |
| 1338 |
$mids = $wpdb->get_col($wpdb->prepare("SELECT meta_id FROM {$table} WHERE {$column} = %d ", $id)) ?: []; |
| 1339 |
|
| 1340 |
array_walk($mids, [$this, 'delete_by_mid']); |
| 1341 |
} |
| 1342 |
|
| 1343 |
public function update_cache($ids){ |
| 1344 |
update_meta_cache($this->name, $ids); |
| 1345 |
} |
| 1346 |
|
| 1347 |
public function cleanup(){ |
| 1348 |
$wpdb = $GLOBALS['wpdb']; |
| 1349 |
$key = $this->object_key; |
| 1350 |
$table = $key ? $wpdb->{$this->name.'s'} : ''; |
| 1351 |
|
| 1352 |
if(!$key){ |
| 1353 |
$model = $this->object_model; |
| 1354 |
|
| 1355 |
if(!$model || !is_callable([$model, 'get_table'])){ |
| 1356 |
return; |
| 1357 |
} |
| 1358 |
|
| 1359 |
$table = $model::get_table(); |
| 1360 |
$key = $model::get_primary_key(); |
| 1361 |
} |
| 1362 |
|
| 1363 |
if(is_multisite() && !str_starts_with($this->get_table(), $wpdb->prefix) && wpjam_lock($this->name.':meta_type:cleanup', DAY_IN_SECONDS, true)){ |
| 1364 |
return; |
| 1365 |
} |
| 1366 |
|
| 1367 |
$mids = $wpdb->get_col("SELECT m.".$this->get_column('id')." FROM ".$this->get_table()." m LEFT JOIN ".$table." t ON t.".$key." = m.".$this->get_column()." WHERE t.".$key." IS NULL") ?: []; |
| 1368 |
|
| 1369 |
array_walk($mids, [$this, 'delete_by_mid']); |
| 1370 |
} |
| 1371 |
|
| 1372 |
public function create_table(){ |
| 1373 |
$table = $this->get_table(); |
| 1374 |
$column = $this->name.'_id'; |
| 1375 |
|
| 1376 |
if($table != $GLOBALS['wpdb']->get_var("show tables like '{$table}'")){ |
| 1377 |
$GLOBALS['wpdb']->query("CREATE TABLE {$table} ( |
| 1378 |
meta_id bigint(20) unsigned NOT NULL auto_increment, |
| 1379 |
{$column} bigint(20) unsigned NOT NULL default '0', |
| 1380 |
meta_key varchar(255) default NULL, |
| 1381 |
meta_value longtext, |
| 1382 |
PRIMARY KEY (meta_id), |
| 1383 |
KEY {$column} ({$column}), |
| 1384 |
KEY meta_key (meta_key(191)) |
| 1385 |
)"); |
| 1386 |
} |
| 1387 |
} |
| 1388 |
|
| 1389 |
public function register_keys(){ |
| 1390 |
if($this->name == 'post'){ |
| 1391 |
foreach(get_post_types(['show_in_rest'=>true]) as $post_type){ |
| 1392 |
foreach($this->get_options(['post_type'=>$post_type]) as $option){ |
| 1393 |
if(wpjam_is_assoc_array($option->fields)){ |
| 1394 |
wpjam_fields($option->fields)->register_meta($this->name, $post_type); |
| 1395 |
} |
| 1396 |
} |
| 1397 |
} |
| 1398 |
} |
| 1399 |
} |
| 1400 |
|
| 1401 |
public function delete_if_default($check, $id, $key, $value){ |
| 1402 |
$type = $this->name; |
| 1403 |
$subtype = $type == 'post' ? get_post_type($id) : ($type == 'term' ? get_term_taxonomy($id) : ''); |
| 1404 |
$registered = $subtype ? (get_registered_meta_keys($type, $subtype)[$key] ?? null) : null; |
| 1405 |
$registered ??= get_registered_meta_keys($type)[$key] ?? null; |
| 1406 |
|
| 1407 |
return $registered && array_key_exists('default', $registered) && $value === $registered['default'] |
| 1408 |
? (delete_metadata($type, $id, $key) || true) |
| 1409 |
: $check; |
| 1410 |
} |
| 1411 |
|
| 1412 |
public function registered(){ |
| 1413 |
add_action('init', [$this, 'register_keys'], 99); |
| 1414 |
|
| 1415 |
wpjam_hooks('add_'.$this->name.'_metadata, update_'.$this->name.'_metadata', [$this, 'delete_if_default'], 10, 4); |
| 1416 |
} |
| 1417 |
|
| 1418 |
public static function get_defaults(){ |
| 1419 |
return array_merge([ |
| 1420 |
'post' => ['object_model'=>'WPJAM_Post', 'object_column'=>'title', 'object_key'=>'ID'], |
| 1421 |
'term' => ['object_model'=>'WPJAM_Term', 'object_column'=>'name', 'object_key'=>'term_id'], |
| 1422 |
'user' => ['object_model'=>'WPJAM_User', 'object_column'=>'display_name','object_key'=>'ID'], |
| 1423 |
], (is_multisite() ? [ |
| 1424 |
'blog' => ['object_key'=>'blog_id'], |
| 1425 |
'site' => [], |
| 1426 |
] : [])); |
| 1427 |
} |
| 1428 |
} |
| 1429 |
|
| 1430 |
class WPJAM_Meta_Option extends WPJAM_Args{ |
| 1431 |
public function __get($key){ |
| 1432 |
$value = parent::__get($key); |
| 1433 |
|
| 1434 |
if(isset($value)){ |
| 1435 |
return $value; |
| 1436 |
} |
| 1437 |
|
| 1438 |
if($key == 'list_table'){ |
| 1439 |
return did_action('current_screen') && !empty($GLOBALS['plugin_page']); |
| 1440 |
}elseif($key == 'show_in_rest'){ |
| 1441 |
return true; |
| 1442 |
}elseif($key == 'show_in_posts_rest'){ |
| 1443 |
return $this->show_in_rest; |
| 1444 |
} |
| 1445 |
} |
| 1446 |
|
| 1447 |
public function __call($method, $args){ |
| 1448 |
if($method == 'prepare' && ($this->callback || $this->update_callback)){ |
| 1449 |
return []; |
| 1450 |
} |
| 1451 |
|
| 1452 |
$id = array_shift($args); |
| 1453 |
$fields = maybe_callback($this->fields, $id, $this->name); |
| 1454 |
|
| 1455 |
if($method == 'get_fields'){ |
| 1456 |
return $fields; |
| 1457 |
} |
| 1458 |
|
| 1459 |
$object = wpjam_fields($fields, array_merge($this->get_args(), ['id'=>$id])); |
| 1460 |
|
| 1461 |
if($method == 'callback'){ |
| 1462 |
$data = wpjam_catch([$object, 'validate'], ...$args); |
| 1463 |
|
| 1464 |
if(!wpjam_if_error($data, '')){ |
| 1465 |
return $data ?: true; |
| 1466 |
} |
| 1467 |
|
| 1468 |
if($callback = $this->callback ?: $this->update_callback){ |
| 1469 |
$res = is_callable($callback) ? call_user_func($callback, $id, $data, $fields) : false; |
| 1470 |
|
| 1471 |
return $res === false ? new WP_Error('invalid_callback') : $res; |
| 1472 |
} |
| 1473 |
|
| 1474 |
return wpjam_update_metadata($this->meta_type, $id, $data, $object->get_defaults()); |
| 1475 |
} |
| 1476 |
|
| 1477 |
$res = $object->$method(...$args); |
| 1478 |
|
| 1479 |
return $method == 'render' ? wpjam_echo(wpautop($this->summary ?: '').$res) : $res; |
| 1480 |
} |
| 1481 |
} |