403Webshell
Server IP : 43.141.49.107  /  Your IP : 113.219.202.173
Web Server : Apache
System : Linux VM-8-5-opencloudos 6.6.34-9.oc9.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jun 19 19:35:45 CST 2024 x86_64
User : www ( 1000)
PHP Version : 8.1.27
Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /www/wwwroot/wordpress/wordpress/wp-content/plugins/wpjam-basic/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /www/wwwroot/wordpress/wordpress/wp-content/plugins/wpjam-basic/includes/class-wpjam-register.php
<?php
trait WPJAM_Call_Trait{
	protected static $_closures	= [];

	protected static function get_called(){
		return strtolower(get_called_class());
	}

	protected function bind_if_closure($closure){
		return is_closure($closure) ? $closure->bindTo($this, get_called_class()) : $closure;
	}

	public static function dynamic_method($action, $method, ...$args){
		if(!$method){
			return;
		}

		$name	= self::get_called();

		if($action == 'add'){
			if(is_closure($args[0])){
				self::$_closures[$name][$method]	= $args[0];
			}
		}elseif($action == 'remove'){
			unset(self::$_closures[$name][$method]);
		}elseif($action == 'get'){
			$closure	= self::$_closures[$name][$method] ?? null;

			if(!$closure){
				$parent		= get_parent_class($name);
				$closure	= $parent ? $parent::dynamic_method('get', $method) : null;
			}

			return $closure;
		}
	}

	public static function add_dynamic_method($method, $closure){
		self::dynamic_method('add', $method, $closure);
	}

	public static function remove_dynamic_method($method){
		self::dynamic_method('remove', $method);
	}

	protected function call_dynamic_method($method, ...$args){
		$closure	= is_closure($method) ? $method : self::dynamic_method('get', $method);
		$callback	= $closure ? $this->bind_if_closure($closure) : null;

		return $callback ? $callback($args) : null;
	}
}

trait WPJAM_Items_Trait{
	public function get_items($field=''){
		return $this->{$field ?: '_items'} ?: [];
	}

	public function update_items($items, $field=''){
		$this->{$field ?: '_items'}	= $items;

		return $this;
	}

	public function item_exists($key, $field=''){
		return $this->item_action('exists', $key, null, $field);
	}

	public function get_item($key, $field=''){
		return $this->item_action('get', $key, null, $field);
	}

	public function get_item_arg($key, $arg, $field=''){
		$item	= $this->get_item($key, $field);

		return $item ? wpjam_get($item, $arg) : null;
	}

	public function has_item($item, $field=''){
		return $this->item_action('has', null, $item, $field);
	}

	public function add_item($key, ...$args){
		if(!$args || !$this->is_keyable($key)){
			$item	= $key;
			$key	= null;
		}else{
			$item	= array_shift($args);
		}

		$cb		= ($args && is_closure($args[0])) ? array_shift($args) : '';
		$field	= array_shift($args) ?: '';

		return $this->item_action('add', $key, $item, $field, $cb);
	}

	public function is_keyable($key){
		return is_int($key) || is_string($key) || is_null($key);
	}

	public function remove_item($item, $field=''){
		return $this->item_action('remove', null, $item, $field);
	}

	public function edit_item($key, $item, $field=''){
		return $this->item_action('edit', $key, $item, $field);
	}

	public function replace_item($key, $item, $field=''){
		return $this->item_action('replace', $key, $item, $field);
	}

	public function set_item($key, $item, $field=''){
		return $this->item_action('set', $key, $item, $field);
	}

	public function delete_item($key, $field=''){
		$result	= $this->item_action('delete', $key, null, $field);

		if(!is_wp_error($result)){
			$this->after_delete_item($key, $field);
		}

		return $result;
	}

	public function del_item($key, $field=''){
		return $this->delete_item($key, $field);
	}

	public function move_item($orders, $field=''){
		$items	= $this->get_items($field);
		$items	= array_merge(wpjam_pull($items, $orders), $items);

		return $this->update_items($items, $field);
	}

	protected function item_action($action, $key, $item, $field='', $cb=false){
		$items	= $this->get_items($field);

		if($action == 'get'){
			return $items[$key] ?? null;
		}elseif($action == 'exists'){
			return array_key_exists($key, $items);
		}elseif($action == 'has'){
			return in_array($item, $items);
		}

		$result	= $this->validate_item($item, $key, $action, $field);

		if(is_wp_error($result)){
			return $result;
		}

		$invalid	= fn($title)=> new WP_Error('invalid_item_key', $title);

		if(isset($item)){
			$item	= $this->sanitize_item($item, $key, $action, $field);
			$index	= $cb ? wpjam_find($items, $cb, 'index') : false;
		}

		if(isset($key)){
			if($this->item_exists($key, $field)){
				if($action == 'add'){
					return $invalid('「'.$key.'」已存在,无法添加');
				}
			}else{
				if(in_array($action, ['edit', 'replace'])){
					return $invalid('「'.$key.'」不存在,无法编辑');
				}elseif($action == 'delete'){
					return $invalid('「'.$key.'」不存在,无法删除');
				}
			}

			if(isset($item)){
				if($index !== false){
					$items	= wpjam_add_at($items, $index, $key, $item);
				}else{
					$items[$key]	= $item;
				}
			}else{
				unset($items[$key]);
			}
		}else{
			if($action == 'add'){
				if($index !== false){
					array_splice($items, $index, 0, [$item]);
				}else{
					array_push($items, $item);
				}
			}elseif($action == 'remove'){
				$items	= array_diff($items, [$item]);
			}else{
				return $invalid('key不能为空');
			}
		}

		return $this->update_items($items, $field);
	}

	protected function validate_item($item, $key, $action='', $field=''){
		return true;
	}

	protected function sanitize_item($item, $key, $action='', $field=''){
		return $item;
	}

	protected function after_delete_item($key, $field=''){
		return true;
	}

	protected static function get_instance_for_item($id){
		if(!method_exists(get_called_class(), 'get_instance')){
			wp_die($model.'->get_instance() 未定义');
		}

		$object	= static::get_instance($id);

		return $object ?: wp_die('invaid_id');
	}

	public static function item_list_action($id, $data, $action=''){
		$object	= self::get_instance_for_item($id);
		$i		= wpjam_get_data_parameter('i');
		$field	= wpjam_get_data_parameter('_field');

		if($action == 'del_item'){
			return $object->del_item($i, $field);
		}elseif($action == 'move_item'){
			return $object->move_item(wpjam_get_data_parameter('item') ?: [], $field);
		}elseif(method_exists($object, $action)){	// 'add_item' 'edit_item'
			return $object->$action($i, $data, $field);
		}
	}

	public static function item_data_action($id){
		$object	= self::get_instance_for_item($id);
		$i		= wpjam_get_data_parameter('i');

		return isset($i) ? $object->get_item($i) : [];
	}

	public static function get_item_actions(){
		$item_action	= [
			'callback'		=> [self::class, 'item_list_action'],
			'data_callback'	=> [self::class, 'item_data_action'],
			'value_callback'=> fn()=> '',
			'row_action'	=> false,
		];

		return [
			'add_item'	=>['page_title'=>'新增项目',	'title'=>'新增',	'dismiss'=>true]+$item_action,
			'edit_item'	=>['page_title'=>'修改项目',	'dashicon'=>'edit']+$item_action,
			'del_item'	=>['page_title'=>'删除项目',	'dashicon'=>'no-alt',	'class'=>'del-icon',	'direct'=>true,	'confirm'=>true]+$item_action,
			'move_item'	=>['page_title'=>'移动项目',	'dashicon'=>'move',		'class'=>'move-item',	'direct'=>true]+$item_action,
		];
	}
}

class WPJAM_Args implements ArrayAccess, IteratorAggregate, JsonSerializable{
	use WPJAM_Call_Trait;

	protected $args;

	public function __construct($args=[]){
		$this->args	= $args;
	}

	public function __get($key){
		$args	= $this->get_args();

		return array_key_exists($key, $args) ? $args[$key] : ($key == 'args' ? $args : null);
	}

	public function __set($key, $value){
		$this->filter_args();

		$this->args[$key]	= $value;
	}

	public function __isset($key){
		if(array_key_exists($key, $this->get_args())){
			return true;
		}

		return $this->$key !== null;
	}

	public function __unset($key){
		$this->filter_args();

		unset($this->args[$key]);
	}

	#[ReturnTypeWillChange]
	public function offsetGet($key){
		return $this->get_args()[$key] ?? null;
	}

	#[ReturnTypeWillChange]
	public function offsetSet($key, $value){
		$this->filter_args();

		if(is_null($key)){
			$this->args[]		= $value;
		}else{
			$this->args[$key]	= $value;
		}
	}

	#[ReturnTypeWillChange]
	public function offsetExists($key){
		return array_key_exists($key, $this->get_args());
	}

	#[ReturnTypeWillChange]
	public function offsetUnset($key){
		$this->filter_args();

		unset($this->args[$key]);
	}

	#[ReturnTypeWillChange]
	public function getIterator(){
		return new ArrayIterator($this->get_args());
	}

	#[ReturnTypeWillChange]
	public function jsonSerialize(){
		return $this->get_args();
	}

	protected function filter_args(){
		if(!$this->args && !is_array($this->args)){
			$this->args = [];
		}

		return $this->args;
	}

	public function get_args(){
		return $this->filter_args();
	}

	public function set_args($args){
		$this->args	= $args;

		return $this;
	}

	public function update_args($args, $replace=true){
		$callback	= $replace ? 'array_merge' : 'wp_parse_args';
		$this->args	= $callback($this->get_args(), $args);

		return $this;
	}

	public function get_arg($key, $default=null){
		return wpjam_get($this->get_args(), $key, $default);
	}

	public function update_arg($key, $value=null){
		$this->args	= wpjam_set($this->get_args(), $key, $value);

		return $this;
	}

	public function delete_arg($key){
		$this->args	= wpjam_except($this->get_args(), $key);

		return $this;
	}

	public function pull($key, $default=null){
		return isset($this->$key) ? wpjam_pull($this->args, $key) : $default;
	}

	public function to_array(){
		return $this->get_args();
	}

	public function sandbox($callback, ...$args){
		try{
			$archive	= $this->get_args();
			$callback	= $this->bind_if_closure($callback);

			return $callback(...$args);
		}finally{
			$this->args	= $archive;
		}
	}

	protected function parse_method($name, $type=null){
		if(!$type || $type != 'property'){
			$model	= ($type == 'model' || !$type) ? $this->model : $type;

			if($model && method_exists($model, $name)){
				return [$model, $name];
			}
		}

		if(!$type || $type == 'property'){
			if($this->$name && is_callable($this->$name)){
				return $this->bind_if_closure($this->$name);
			}
		}
	}

	public function call_method($method, ...$args){
		$called	= $this->parse_method($method);

		if($called){
			return $called(...$args);
		}

		if(str_starts_with($method, 'filter_')){
			return array_shift($args);
		}
	}

	protected function call_property($property, ...$args){
		$called	= $this->parse_method($property, 'property');

		return $called ? $called(...$args) : null;
	}

	protected function call_model($method, ...$args){
		$called	= $this->parse_method($method, 'model');

		return $called ? $called(...$args) : null;
	}

	protected function error($code, $msg){
		return new WP_Error($code, $msg);
	}
}

class WPJAM_Register extends WPJAM_Args{
	use WPJAM_Items_Trait;

	protected $name;
	protected $_group;
	protected $_filtered;

	public function __construct($name, $args=[], $group=''){
		$this->name		= $name;
		$this->args		= $args;
		$this->_group	= self::parse_group($group);

		if($this->is_active() || !empty($args['active'])){
			$this->args	= $this->preprocess_args($args);
		}

		$this->args	= array_merge($this->args, ['name'=>$name]);
	}

	protected function preprocess_args($args){
		$group	= $this->_group;
		$config	= $group->get_config('model') ?? true;
		$model	= $config ? wpjam_get($args, 'model') : null;

		if($model || !empty($args['hooks']) || !empty($args['init'])){
			$file	= wpjam_pull($args, 'file');

			if($file && is_file($file)){
				include_once $file;
			}
		}

		if($model && is_subclass_of($model, 'WPJAM_Register')){
			trigger_error('「'.(is_object($model) ? get_class($model) : $model).'」是 WPJAM_Register 子类');
		}

		if($model){
			if($config === 'object'){
				if(!is_object($model)){
					if(class_exists($model, true)){
						$model = $args['model']	= new $model(array_merge($args, ['object'=>$this]));
					}else{
						trigger_error('model 无效');
					}
				}
			}else{
				$group->handle_model('add', $model, $this);
			}

			foreach([
				['hooks', 'add_hooks', true],
				['init', 'init', $group->get_config('init')],
			] as list($key, $method, $default)){
				if(($args[$key] ?? $default) === true){
					$args[$key]	= $this->parse_method($method, $model);	
				} 
			}
		}

		wpjam_hooks(wpjam_pull($args, 'hooks'));
		wpjam_load('init', wpjam_pull($args, 'init'));

		return $args;
	}

	protected function filter_args(){
		if(!$this->_filtered){
			$this->_filtered	= true;

			$class		= self::get_called();
			$filter		= $class == 'wpjam_register' ? 'wpjam_'.$this->_group->name.'_args' : $class.'_args';
			$this->args	= apply_filters($filter, $this->args, $this->name);
		}

		return $this->args;
	}

	public function get_arg($key, $default=null, $do_callback=true){
		$value	= parent::get_arg($key);

		if(is_null($value)){
			if($this->model && $key && is_string($key) && !str_contains($key, '.')){
				$value	= $this->parse_method('get_'.$key, 'model');
			}
		}elseif(is_callable($value)){
			$value	= $this->bind_if_closure($value);
		}

		if($do_callback && is_callable($value)){
			return $value($this->name);
		}

		return $value ?? $default;
	}

	public function get_parent(){
		return $this->sub_name ? self::get($this->name) : null;
	}

	public function is_sub(){
		return (bool)$this->sub_name;
	}

	public function get_sub($name){
		return $this->get_item($name, 'subs');
	}

	public function get_subs(){
		return $this->get_items('subs');
	}

	public function register_sub($name, $args){
		$args	= array_merge($args, ['sub_name'=>$name]);
		$sub	= new static($this->name, $args);

		$this->add_item($name, $sub, 'subs');

		return self::register($this->name.':'.$name, $sub);
	}

	public function unregister_sub($name){
		$this->delete_item($name, 'subs');

		return self::unregister($this->name.':'.$name);
	}

	public function is_active(){
		return true;
	}

	public static function validate_name($name){
		$prefix	= self::class.'的注册 name';

		if(empty($name)){
			trigger_error($prefix.' 为空');
			return;
		}elseif(is_numeric($name)){
			trigger_error($prefix.'「'.$name.'」'.'为纯数字');
			return;
		}elseif(!is_string($name)){
			trigger_error($prefix.'「'.var_export($name, true).'」不为字符串');
			return;
		}

		return true;
	}

	protected static function get_defaults(){
		return [];
	}

	protected static function parse_group($name=''){
		$called	= get_called_class();
		$group	= WPJAM_Register_Group::get_instance(strtolower($name ?: $called));

		if(!$group->called){
			$group->init($called, $called::get_defaults());
		}

		return $group;
	}

	public static function call_group($method, ...$args){
		[$method, $group]	= str_contains($method, '_by_') ? explode('_by_', $method) : [$method, ''];

		return (self::parse_group($group))->$method(...$args);
	}

	public static function register($name, $args=[]){
		return self::call_group('add_object', $name, $args);
	}

	public static function re_register($name, $args, $merge=true){
		self::unregister($name);

		return self::register($name, $args);
	}

	public static function unregister($name){
		self::call_group('remove_object', $name);
	}

	public static function get_registereds($args=[], $output='objects', $operator='and'){
		$objects	= self::call_group('get_objects', $args, $operator);

		return $output == 'names' ? array_keys($objects) : $objects;
	}

	public static function get_by(...$args){
		$args	= $args ? (is_array($args[0]) ? $args[0] : [$args[0] => $args[1]]) : [];

		return self::get_registereds($args);
	}

	public static function get($name, $by='', $top=''){
		return self::call_group('get_object', $name, $by, $top);
	}

	public static function exists($name){
		return (bool)self::get($name);
	}

	public static function get_setting_fields($args=[]){
		return self::call_group('get_fields', $args);
	}

	public static function get_active($key=null){
		return self::call_group('get_active', $key);
	}

	public static function call_active($method, ...$args){
		return self::call_group('call_active', $method, ...$args);
	}

	public static function by_active(...$args){
		$name	= current_filter();
		$method = (did_action($name) ? 'on_' : 'filter_').(wpjam_remove_prefix($name, 'wpjam_'));

		return self::call_active($method, ...$args);
	}
}

class WPJAM_Register_Group extends WPJAM_Args{
	use WPJAM_Items_Trait;

	public function init($called, $defaults){
		$this->called	= $called;
		$this->defaults	= $defaults;

		wpjam_register_route($this->get_config('route'), ['model'=>$called]);
	}

	public function get_objects($args=[], $operator='AND'){
		wpjam_map(($this->pull('defaults') ?: []), [$this, 'add_object']);

		$objects	= $this->get_items();

		return $args ? wpjam_filter($objects, $args, $operator) : $objects;
	}

	public function get_object($name, $by='', $top=''){
		if(!$name){
			return;
		}

		if($by == 'model'){
			if($name && strcasecmp($name, $top) !== 0){
				return $this->handle_model('get', $name) ?: $this->get_object(get_parent_class($name), $by, $top);
			}
		}else{
			$object	= $this->get_item($name);

			if(!$object){
				$defaults	= $this->defaults;

				if($defaults && isset($defaults[$name])){
					$args	= wpjam_pull($defaults, $name);
					$object	= $this->add_object($name, $args);

					$this->defaults	= $defaults;
				}
			}

			return $object;
		}
	}

	public function add_object($name, $object){
		$class	= $this->called;
		$count	= count($this->get_items());

		if(is_object($name)){
			$object	= $name;
			$name	= $object->name ?? null;
		}elseif(is_array($name)){
			[$object, $name]	= [$name, $object];

			$name	= wpjam_pull($object, 'name') ?: ($name ?: '__'.$count);
		}

		if(!$class::validate_name($name)){
			return;
		}

		if($this->get_item($name)){
			trigger_error($this->name.'「'.$name.'」已经注册。');
		}

		if(is_array($object)){
			if(!empty($object['admin']) && !is_admin()){
				return;
			}

			$object	= new $class($name, $object);
		}

		$orderby	= $this->get_config('orderby');

		if($orderby){
			$by		= $orderby === true ? 'order' : $orderby;
			$order	= $this->get_config('order') ?? 'DESC';
			$score	= wpjam_get($object, $by, 10);
			$comp	= ($order == 'DESC' ? '>' : '<');
			$args[]	= fn($v)=> wpjam_compare($score, $comp, wpjam_get($v, $by, 10));
		}else{
			$args	= [];
		}

		$this->add_item($name, $object, ...$args);

		if(method_exists($object, 'registered')){
			$object->registered($count+1);
		}

		return $object;
	}

	public function remove_object($name){
		$object	= $this->get_item($name);

		if($object){
			$this->handle_model('delete', $object->model);
			$this->delete_item($name);
		}
	}

	public function handle_model($action, $model, $object=null){
		$model	= ($model && is_string($model)) ? strtolower($model) : null;

		if($model){
			return $this->item_action($action, $model, $object, 'models');
		}
	}

	public function get_config($key){
		if($this->called == 'WPJAM_Register'){
			return;
		}

		$config	= $this->config;

		if(is_null($config)){
			$ref	= new ReflectionClass($this->called);

			if(method_exists($ref, 'getAttributes')){
				$attribute	= $ref->getAttributes('config');

				$args	= $attribute ? $attribute[0]->getArguments() : [];
				$args	= $args ? (is_array($args[0]) ? $args[0] : $args) : [];
			}else{
				$args	= preg_match_all('/@config\s+([^\r\n]*)/', $ref->getDocComment(), $matches) ? wp_parse_list($matches[1][0]) : [];
			}

			$config	= $this->config = wpjam_array($args, fn($k, $v)=> is_numeric($k) ? (str_contains($v, '=') ? explode('=', $v) : [$v, true]) : [$k, $v]);
		}

		return $config[$key] ?? null;
	}

	public function get_active($key=null){
		$objects	= array_filter($this->get_objects(), fn($object)=> $object->active ?? $object->is_active());

		return $key ? array_filter(array_map(fn($object)=> $object->get_arg($key), $objects), fn($v)=> !is_null($v)) : $objects;
	}

	public function call_active($method, ...$args){
		$type	= wpjam_find(['filter', 'get'], fn($type)=> str_starts_with($method, $type.'_'));

		foreach($this->get_active() as $object){
			$result	= $object->call_method($method, ...$args);	// 不能调用对象本身的方法,会死循环

			if(is_wp_error($result)){
				return $result;
			}

			if($type == 'filter'){
				$args[0]	= $result;
			}elseif($type == 'get'){
				if($result && is_array($result)){
					$return	= array_merge(($return ?? []), $result);
				}
			}
		}

		if($type == 'filter'){
			return $args[0];
		}elseif($type == 'get'){
			return $return ?? [];
		}
	}

	public function get_fields($args=[]){
		if($this->get_config('single')){
			$args	= wp_parse_args($args, [
				'name'				=> wpjam_remove_prefix(strtolower($this->called), 'wpjam_'),
				'title'				=> '',
				'title_field'		=> 'title',
				'show_option_none'	=> __('&mdash; Select &mdash;'),
				'option_none_value'	=> ''
			]);

			$options	= $args['show_option_none'] ? [$args['option_none_value']=> $args['show_option_none']] : [];
			$options	+= wpjam_map($this->get_objects(), fn($object)=>[
				'title'			=> $object->{$args['title_field']},
				'description'	=> $object->description,
				'fields'		=> $object->get_arg('fields') ?: []
			]);

			return [$args['name']=> ['title'=>$args['title'], 'type'=>'select', 'options'=>$options]];
		}

		return wpjam_array($this->get_objects(), fn($name, $object)=> isset($object->active) ? null : [$name, wp_parse_args(($object->field ?: []), ['type'=>'checkbox', 'label'=>$object->title])]);
	}

	protected static $_groups	= [];

	public static function __callStatic($method, $args){
		foreach(self::$_groups as $group){
			if($method == 'register_json'){
				if($group->get_config($method)){
					$group->call_active($method, $args[0]);
				}
			}elseif(in_array($method, ['add_menu_page', 'add_admin_load'])){
				$key	= wpjam_remove_prefix($method, 'add_');

				if($group->get_config($key)){
					array_map('wpjam_'.$method, $group->get_active($key));
				}
			}
		}
	}

	public static function get_instance($name){
		if(!self::$_groups){
			add_action('wpjam_api',	[self::class, 'register_json']);

			if(is_admin()){
				add_action('wpjam_admin_init',	[self::class, 'add_menu_page']);
				add_action('wpjam_admin_init',	[self::class, 'add_admin_load']);
			}
		}

		return self::$_groups[$name]	??= new self(['name'=>$name]);
	}
}

/**
* @config orderby
**/
#[config('orderby')]
class WPJAM_Meta_Type extends WPJAM_Register{
	public function __call($method, $args){
		if(str_ends_with($method, '_option')){
			$method	= wpjam_remove_postfix($method, '_option');	// get_option register_option unregister_option
			$name	= array_shift($args);

			if($method == 'register'){
				$args	= array_merge(array_shift($args), ['meta_type'=>$this->name]);

				if($this->name == 'post'){
					$args	= wp_parse_args($args, ['fields'=>[], 'priority'=>'default']);

					if(!isset($args['post_type']) && isset($args['post_types'])){
						$args['post_type']	= wpjam_pull($args, 'post_types') ?: null;
					}
				}elseif($this->name == 'term'){
					if(!isset($args['taxonomy']) && isset($args['taxonomies'])){
						$args['taxonomy']	= wpjam_pull($args, 'taxonomies') ?: null;
					}

					if(!isset($args['fields'])){
						$args['fields']		= [$name => wpjam_except($args, 'taxonomy')];
						$args['from_field']	= true;
					}
				}

				$args	= [new WPJAM_Meta_Option($name, $args)];
			}

			$args		= [$this->name.':'.$name, ...$args];
			$callback	= ['WPJAM_Meta_Option', $method];
		}elseif(in_array($method, ['get_data', 'add_data', 'update_data', 'delete_data', 'data_exists'])){
			$args		= [$this->name, ...$args];
			$callback	= str_replace('data', 'metadata', $method);
		}elseif(str_ends_with($method, '_by_mid')){
			$args		= [$this->name, ...$args];
			$callback	= str_replace('_by_mid', '_metadata_by_mid', $method);
		}elseif(str_ends_with($method, '_meta')){
			$callback	= [$this, str_replace('_meta', '_data', $method)];
		}elseif(str_contains($method, '_meta')){
			$callback	= [$this, str_replace('_meta', '', $method)];
		}

		if(empty($callback)){
			trigger_error('无效的方法'.$method);
			return;
		}

		return $callback(...$args);
	}

	protected function preprocess_args($args){
		$wpdb	= $GLOBALS['wpdb'];
		$table	= $args['table_name'] ?? $this->name.'meta';

		if(!isset($wpdb->$table)){
			$wpdb->$table = $args['table'] ?? $wpdb->prefix.$this->name.'meta';
		}

		return parent::preprocess_args($args);
	}

	public function lazyload_data($ids){
		wpjam_lazyload($this->name.'_meta', $ids);
	}

	public function get_options($args=[]){
		return wpjam_array(WPJAM_Meta_Option::get_by(array_merge($args, ['meta_type'=>$this->name])), fn($k, $v)=> $v->name);
	}

	public function get_table(){
		return _get_meta_table($this->name);
	}

	public function get_column($name='object'){
		if($name == 'object'){
			return $this->name.'_id';
		}elseif($name == 'id'){
			return 'user' == $this->name ? 'umeta_id' : 'meta_id';
		}
	}

	protected function parse_value($value){
		if(wp_is_numeric_array($value)){
			return maybe_unserialize($value[0]);
		}else{
			return array_merge($value, ['meta_value'=>maybe_unserialize($value['meta_value'])]);
		}
	}

	public function get_data_with_default($id, ...$args){
		if(!$args){
			return $this->get_data($id);
		}

		if(is_array($args[0])){
			$keys	= wpjam_array($args[0], fn($k, $v)=> is_numeric($k) ? [$v, null] : [$k, $v]);

			return ($id && $args[0]) ? wpjam_map($keys, fn($v, $k)=> $this->get_data_with_default($id, $k, $v)) : [];
		}else{
			if($id && $args[0]){
				if($args[0] == 'meta_input'){
					return array_map([$this, 'parse_value'], $this->get_data($id));
				}

				if($this->data_exists($id, $args[0])){
					return $this->get_data($id, $args[0], true);
				}
			}

			return $args[1] ?? null;
		}
	}

	public function get_by_key(...$args){
		global $wpdb;

		if(empty($args)){
			return [];
		}

		if(is_array($args[0])){
			$key	= $args[0]['meta_key'] ?? ($args[0]['key'] ?? '');
			$value	= $args[0]['meta_value'] ?? ($args[0]['value'] ?? '');
		}else{
			$key	= $args[0];
			$value	= $args[1] ?? null;
		}

		if($key){
			$where[]	= $wpdb->prepare('meta_key=%s', $key);
		}

		if(!is_null($value)){
			$where[]	= $wpdb->prepare('meta_value=%s', maybe_serialize($value));
		}

		if(empty($where)){
			return [];
		}

		$where	= implode(' AND ', $where);
		$table	= $this->get_table();
		$data	= $wpdb->get_results("SELECT * FROM {$table} WHERE {$where}", ARRAY_A) ?: [];

		return array_map([$this, 'parse_value'], $data);
	}

	public function update_data_with_default($id, ...$args){
		if(is_array($args[0])){
			$data	= $args[0];

			if(wpjam_is_assoc_array($data)){
				$defaults	= (isset($args[1]) && is_array($args[1])) ? $args[1] : [];

				if(isset($data['meta_input']) && wpjam_is_assoc_array($data['meta_input'])){
					$this->update_data_with_default($id, wpjam_pull($data, 'meta_input'), wpjam_pull($defaults, 'meta_input'));
				}

				wpjam_map($data, fn($v, $k)=> $this->update_data_with_default($id, $k, $v, wpjam_pull($defaults, $k)));
			}

			return true;
		}else{
			$key		= $args[0];
			$value		= $args[1];
			$default	= $args[2] ?? null;

			if(is_array($value)){
				if($value && (!is_array($default) || array_diff_assoc($default, $value))){
					return $this->update_data($id, $key, $value);
				}
			}else{
				if(isset($value) && ((is_null($default) && ($value || is_numeric($value))) || (!is_null($default) && $value != $default))){
					return $this->update_data($id, $key, $value);
				}
			}

			return $this->delete_data($id, $key);
		}
	}

	public function cleanup(){
		if($this->object_key){
			$object_key		= $this->object_key;
			$object_table	= $GLOBALS['wpdb']->{$this->name.'s'};
		}else{
			$object_model	= $this->object_model;

			if($object_model && is_callable([$object_model, 'get_table'])){
				$object_table	= $object_model::get_table();
				$object_key		= $object_model::get_primary_key();
			}else{
				$object_table	= '';
				$object_key		= '';
			}
		}

		$this->delete_orphan_data($object_table, $object_key);
	}

	public function delete_orphan_data($object_table=null, $object_key=null){
		if($object_table && $object_key){
			$wpdb	= $GLOBALS['wpdb'];
			$mids	= $wpdb->get_col("SELECT m.".$this->get_column('id')." FROM ".$this->get_table()." m LEFT JOIN ".$object_table." t ON t.".$object_key." = m.".$this->get_column('object')." WHERE t.".$object_key." IS NULL") ?: [];

			array_walk($mids, [$this, 'delete_by_mid']);
		}
	}

	public function delete_empty_data(){
		$wpdb	= $GLOBALS['wpdb'];
		$mids	= $wpdb->get_col("SELECT ".$this->get_column('id')." FROM ".$this->get_table()." WHERE meta_value = ''") ?: [];

		array_walk($mids, [$this, 'delete_by_mid']);
	}

	public function delete_by_key($key, $value=''){
		return delete_metadata($this->name, null, $key, $value, true);
	}

	public function delete_by_id($id){
		$wpdb	= $GLOBALS['wpdb'];
		$table	= $this->get_table();
		$column	= $this->get_column();
		$mids	= $wpdb->get_col($wpdb->prepare("SELECT meta_id FROM {$table} WHERE {$column} = %d ", $id)) ?: [];

		array_walk($mids, [$this, 'delete_by_mid']);
	}

	public function update_cache($ids){
		update_meta_cache($this->name, $ids);
	}

	public function create_table(){
		$table	= $this->get_table();

		if($GLOBALS['wpdb']->get_var("show tables like '{$table}'") != $table){
			$column	= $this->name.'_id';

			$GLOBALS['wpdb']->query("CREATE TABLE {$table} (
				meta_id bigint(20) unsigned NOT NULL auto_increment,
				{$column} bigint(20) unsigned NOT NULL default '0',
				meta_key varchar(255) default NULL,
				meta_value longtext,
				PRIMARY KEY (meta_id),
				KEY {$column} ({$column}),
				KEY meta_key (meta_key(191))
			)");
		}
	}

	public static function get_defaults(){
		return array_merge([
			'post'	=> ['order'=>50,	'object_model'=>'WPJAM_Post',	'object_column'=>'title',	'object_key'=>'ID'],
			'term'	=> ['order'=>40,	'object_model'=>'WPJAM_Term',	'object_column'=>'name',	'object_key'=>'term_id'],
			'user'	=> ['order'=>30,	'object_model'=>'WPJAM_User',	'object_column'=>'display_name','object_key'=>'ID'],
		], (is_multisite() ? [
			'blog'	=> ['order'=>5,	'object_key'=>'blog_id'],
			'site'	=> ['order'=>5],
		] : []));
	}
}

/**
* @config orderby
**/
#[config('orderby')]
class WPJAM_Meta_Option extends WPJAM_Register{
	public function __call($method, $args){
		if(str_ends_with($method, '_by_fields')){
			$id		= array_shift($args);
			$fields	= $this->get_fields($id);
			$object	= wpjam_fields($fields);
			$method	= wpjam_remove_postfix($method, '_by_fields');

			return $object->$method(...$args);
		}
	}

	public function __get($key){
		$value	= parent::__get($key);

		if($key == 'list_table'){
			if(is_null($value) && did_action('current_screen') && !empty($GLOBALS['plugin_page'])){
				return true;
			}
		}elseif($key == 'callback'){
			if(!$value){
				return $this->update_callback;
			}
		}

		return $value;
	}

	public function get_fields($id=null){
		$fields	= $this->fields;

		return is_callable($fields) ? $fields($id, $this->name) : $fields;
	}

	public function register_list_table_action(){
		return wpjam_register_list_table_action($this->action_name ?: 'set_'.$this->name, wp_parse_args($this->get_args(), [
			'page_title'	=> '设置'.$this->title,
			'submit_text'	=> '设置',
			'meta_type'		=> $this->name,
			'fields'		=> [$this, 'get_fields']
		]));
	}

	public function prepare($id=null){
		if($this->callback){
			return [];
		}

		return $this->prepare_by_fields($id, array_merge($this->get_args(), ['id'=>$id]));
	}

	public function validate($id=null, $data=null){
		return $this->validate_by_fields($id, $data);
	}

	public function render($id, $args=[]){
		if($this->meta_type == 'post' && isset($GLOBALS['current_screen'])){
			if($this->meta_box_cb){
				return call_user_func($this->meta_box_cb, $id, $args);
			}

			$args	= ['fields_type'=>$this->context == 'side' ? 'list' : 'table'];
			$id		= $GLOBALS['current_screen']->action == 'add' ? false : $id->ID;

			echo $this->summary ? wpautop($this->summary) : '';
		}

		echo $this->render_by_fields($id, array_merge($this->get_args(), ['id'=>$id], $args));
	}

	public function callback($id, $data=null){
		$fields	= $this->get_fields($id);
		$object	= wpjam_fields($fields);
		$data	= $object->validate($data);

		if(is_wp_error($data)){
			return $data;
		}elseif(!$data){
			return true;
		}

		if($this->callback){
			$result	= is_callable($this->callback) ? call_user_func($this->callback, $id, $data, $fields) : false;

			return $result === false ? new WP_Error('invalid_callback') : $result;
		}else{
			return wpjam_update_metadata($this->meta_type, $id, $data, $object->get_defaults());
		}
	}

	public static function create($name, $args){
		$meta_type	= wpjam_get($args, 'meta_type');

		if($meta_type){
			$object	= new self($name, $args);

			return self::register($meta_type.':'.$name, $object);
		}
	}

	public static function get_by(...$args){
		$args		= is_array($args[0]) ? $args[0] : [$args[0] => $args[1]];
		$list_table	= wpjam_pull($args, 'list_table');
		$meta_type	= wpjam_get($args, 'meta_type');

		if(!$meta_type){
			return [];
		}

		if(isset($list_table)){
			$args['title']		= true;
			$args['list_table']	= $list_table ? true : ['compare'=>'!=', 'strict'=>true, 'value'=>'only'];
		}

		if($meta_type == 'post'){
			$post_type	= wpjam_pull($args, 'post_type');

			if($post_type){
				$object	= wpjam_get_post_type_object($post_type);

				if($object){
					$object->register_option($list_table);
				}

				$args['post_type']	= ['value'=>$post_type, 'if_null'=>true, 'callable'=>true];
			}
		}elseif($meta_type == 'term'){
			$taxonomy	= wpjam_pull($args, 'taxonomy');
			$action		= wpjam_pull($args, 'action');

			if($taxonomy){
				$object	= wpjam_get_taxonomy_object($taxonomy);

				if($object){
					$object->register_option($list_table);
				}

				$args['taxonomy']	= ['value'=>$taxonomy, 'if_null'=>true, 'callable'=>true];
			}

			if($action){
				$args['action']		= ['value'=>$action, 'if_null'=>true, 'callable'=>true];
			}
		}

		return static::get_registereds($args);
	}
}

class WPJAM_AJAX extends WPJAM_Register{
	public function registered($count){
		wpjam_map($this->nopriv ? ['', 'nopriv_'] : [''], fn($part)=> add_action('wp_ajax_'.$part.$this->name, [$this, 'callback']));

		if($count == 1 && !is_admin()){
			wpjam_script('wpjam-ajax', [
				'for'		=> 'wp, login',
				'src'		=> wpjam_url(dirname(__DIR__).'/static/ajax.js'),
				'deps'		=> ['jquery'],
				'data'		=> 'var ajaxurl	= "'.admin_url('admin-ajax.php').'";',
				'position'	=> 'before',
				'priority'	=> 1
			]);

			if(!is_login()){
				add_filter('script_loader_tag', fn($tag, $handle)=> $handle == 'wpjam-ajax' && current_theme_supports('script', $handle) ? '' : $tag, 10, 2);
			}
		}
	}

	public function callback(){
		if(!$this->callback || !is_callable($this->callback)){
			wpjam_send_error_json('invalid_callback');
		}

		$data	= wpjam_get_data_parameter();
		$data	= array_merge($data, wpjam_except(wpjam_get_post_parameter(), ['action', 'defaults', 'data', '_ajax_nonce']));
		$result	= wpjam_catch([wpjam_fields($this->fields), 'validate'], $data, 'parameter');

		if(is_wp_error($result)){
			wpjam_send_json($result);
		}

		$data	= array_merge($data, $result);

		if($this->verify !== false && !check_ajax_referer($this->get_nonce_action($data), false, false)){
			wpjam_send_error_json('invalid_nonce');
		}

		$result	= wpjam_catch($this->callback, $data, $this->name);
		$result	= $result === true ? [] : $result;

		wpjam_send_json($result);
	}

	public function get_attr($data=[], $return=null){
		$attr	= ['action'=>$this->name, 'data'=>$data];
		$attr	= array_merge($attr, $this->verify !== false ? ['nonce'=> wp_create_nonce($this->get_nonce_action($data))] : []);

		return $return ? $attr : wpjam_attr($attr, 'data');
	}

	protected function get_nonce_action($data){
		$keys	= $this->nonce_keys ?: [];
		$data	= array_filter(wp_array_slice_assoc($data, $keys));

		return $this->name.($data ? ':'.implode(':', $data) : '');
	}
}

class WPJAM_Verify_TXT extends WPJAM_Register{
	public function get_fields(){
		return [
			'name'	=>['title'=>'文件名称',	'type'=>'text',	'required', 'value'=>$this->get_data('name'),	'class'=>'all-options'],
			'value'	=>['title'=>'文件内容',	'type'=>'text',	'required', 'value'=>$this->get_data('value')]
		];
	}

	public function get_data($key=''){
		$data	= wpjam_get_setting('wpjam_verify_txts', $this->name) ?: [];

		return $key ? ($data[$key] ?? '') : $data;
	}

	public function set_data($data){
		return wpjam_update_setting('wpjam_verify_txts', $this->name, $data) || true;
	}

	public static function __callStatic($method, $args){	// 放弃
		$name	= $args[0];

		if($object = self::get($name)){
			if(in_array($method, ['get_name', 'get_value'])){
				return $object->get_data(str_replace('get_', '', $method));
			}elseif($method == 'set' || $method == 'set_value'){
				return $object->set_data(['name'=>$args[1], 'value'=>$args[2]]);
			}
		}
	}

	public static function filter_root_rewrite_rules($root_rewrite){
		if(empty($GLOBALS['wp_rewrite']->root)){
			$home_path	= parse_url(home_url());

			if(empty($home_path['path']) || '/' == $home_path['path']){
				$root_rewrite	= array_merge(['([^/]+)\.txt?$'=>'index.php?module=txt&action=$matches[1]'], $root_rewrite);
			}
		}

		return $root_rewrite;
	}

	public static function get_rewrite_rule(){
		add_filter('root_rewrite_rules',	[self::class, 'filter_root_rewrite_rules']);
	}

	public static function redirect($action){
		$txts	= wpjam_get_option('wpjam_verify_txts');
		$txt	= $txts ? wpjam_find($txts, fn($v)=> $v['name'] == str_replace('.txt', '', $action).'.txt') : '';

		if($txt){
			header('Content-Type: text/plain');
			echo $txt['value'];

			exit;
		}
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit