403Webshell
Server IP : 43.141.49.92  /  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-api.php
<?php
class WPJAM_API{
	public static function activation($action='', $callback='', $hook=null){
		$transient	= 'wpjam-actives';
		$handler	= wpjam_get_handler($transient, ['items_type'=>'transient', 'transient'=>$transient]);

		if($action == 'add'){
			if($callback){
				$handler->add([($hook ?: 'wp_loaded'), $callback]);
			}
		}else{
			$items	= $handler->empty();

			if($items){
				wpjam_map($items, fn($active)=> add_action(...$active));
			}
		}
	}

	public static function on_plugins_loaded(){
		self::activation();

		add_filter('query_vars',	fn($vars)=> ['module', 'action', 'term_id', ...$vars]);

		add_filter('register_post_type_args',	['WPJAM_Post_Type', 'filter_register_args'], 999, 2);
		add_filter('register_taxonomy_args',	['WPJAM_Taxonomy', 'filter_register_args'], 999, 3);

		add_filter('request',			['WPJAM_Posts', 'parse_query_vars']);
		add_filter('posts_clauses',		['WPJAM_Posts', 'filter_clauses'], 1, 2);
		add_filter('content_save_pre',	['WPJAM_Posts', 'filter_content_save_pre'], 1);

		add_filter('wp_video_shortcode_override', fn($override, $attr, $content)=> WPJAM_Video::render($content, $attr) ?: $override, 10, 3);
	}

	public static function __callStatic($method, $args){
		$function	= 'wpjam_'.$method;

		if(function_exists($function)){
			return $function(...$args);
		}
	}

	public static function get_apis(){	// 兼容
		return WPJAM_JSON::get_registereds();
	}
}

class WPJAM_Route{
	public static function __callStatic($method, $args){
		array_map('wpjam_'.$method, array_column(wpjam_get_items('route'), wpjam_remove_prefix($method, 'add_')));
	}

	public static function add($name, $args){
		if(!$name){
			return;
		}

		if(!wpjam_get_items('route')){
			add_action('wp_loaded',		[self::class, 'add_rewrite_rule']);
			add_action('parse_request',	[self::class, 'request'], 1);

			if(is_admin()){
				add_action('wpjam_admin_init',	[self::class, 'add_menu_page']);
				add_action('wpjam_admin_init',	[self::class, 'add_admin_load']);
			
				if(wp_doing_ajax()){
					add_action('admin_init', fn()=> self::request('data'));
				}
			}
		}

		if(!is_array($args) || wp_is_numeric_array($args)){
			$args	= is_callable($args) ? ['callback'=>$args] : (array)$args;
		}elseif(!empty($args['model'])){
			$model	= wpjam_pull($args, 'model');
			$map	= ['callback'=>'redirect', 'rewrite_rule'=>'get_rewrite_rule'];
			$args	= wpjam_array($map, fn($k, $v)=> (empty($args[$k]) && method_exists($model, $v)) ? [$k, [$model, $v]] : null)+$args;
		}

		wpjam_add_item('route', $name, $args);
	}

	public static function request($wp){
		$args	= ['method'=> is_object($wp) ? 'GET' : $wp];

		foreach(wpjam_get_items('route') as $module => $item){
			if(!empty($item['query_var'])){
				$action	= wpjam_get_parameter($module, $args);

				if($action){
					self::dispatch($module, $action);
				}
			}
		}

		if(is_object($wp)){
			$module	= $wp->query_vars['module'] ?? '';

			if($module){
				remove_action('template_redirect',	'redirect_canonical');

				self::dispatch($module, $wp->query_vars['action'] ?? '');
			}
		}
	}

	public static function dispatch($module, $action){
		$item	= wpjam_get_item('route', $module);

		if($item){
			if(!empty($item['callback']) && is_callable($item['callback'])){
				$item['callback']($action, $module);
			}

			if(!empty($item['query_var'])){
				$GLOBALS['wp']->set_query_var($module, $action);
			}
		}

		if(!is_admin()){
			if($item && !empty($item['file'])){
				$file	= $item['file'];
			}else{
				$file	= STYLESHEETPATH.'/template/'.$module.'/'.($action ?: 'index').'.php';
				$file	= apply_filters('wpjam_template', $file, $module, $action);
			}

			if(is_file($file)){
				add_filter('template_include',	fn()=> $file);
			}
		}
	}
}

class WPJAM_JSON extends WPJAM_Register{
	public function response(){
		$method		= $this->method ?: $_SERVER['REQUEST_METHOD'];
		$response	= apply_filters('wpjam_pre_json', [], $this->args, $this->name);
		$response	= wpjam_throw_if_error($response);
		$response	= array_merge($response, [
			'errcode'		=> 0,
			'current_user'	=> wpjam_try('wpjam_get_current_user', $this->pull('auth'))
		]);

		if($method != 'POST' && !str_ends_with($this->name, '.config')){
			$response	+= wp_array_slice_assoc($this, ['page_title', 'share_title', 'share_image']);
		}

		if($this->fields){
			$fields	= $this->fields;
			$fields	= is_callable($fields) ? wpjam_try($fields, $this->name) : $fields;
			$data	= wpjam_get_fields_parameter($fields, $method);
		}

		if($this->modules){
			$modules	= self::parse_modules($this->modules, $this->name);
			$results	= array_map([self::class, 'parse_module'], $modules);
		}else{
			$results	= [];
			$callback	= $this->pull('callback');

			if($callback){
				if(is_callable($callback)){
					$results[]	= wpjam_try($callback, ($this->fields ? $data : $this->args), $this->name);
				}
			}elseif($this->template){
				if(is_file($this->template)){
					$results[]	= include $this->template;
				}
			}else{
				$results[]	= $this->args;
			}
		}

		foreach($results as $result){
			wpjam_throw_if_error($result);

			if(is_array($result)){
				$attr		= wp_array_slice_assoc($response, ['page_title', 'share_title', 'share_image']);
				$response	= array_merge($response, array_diff_key($result, array_filter($attr)));
			}
		}

		$response	= apply_filters('wpjam_json', $response, $this->args, $this->name);

		if($method != 'POST' && !str_ends_with($this->name, '.config')){
			foreach(['page_title', 'share_title'] as $title_key){
				if(empty($response[$title_key])){
					$response[$title_key]	= html_entity_decode(wp_get_document_title());
				}
			}

			if(!empty($response['share_image'])){
				$response['share_image']	= wpjam_get_thumbnail($response['share_image'], '500x400');
			}
		}

		return $response;
	}

	public static function parse_modules($modules, $name){
		$modules	= is_callable($modules) ? $modules($name) : $modules;

		return wp_is_numeric_array($modules) ? $modules : [$modules];
	}

	public static function parse_module($module){
		$args	= array_get($module, 'args', []);
		$args	= is_array($args) ? $args : wpjam_parse_shortcode_attr(stripslashes_deep($args), 'module');
		$parser	= array_get($module, 'parser') ?: wpjam_get_item('json_module_parser', array_get($module, 'type'));

		return $parser ? wpjam_catch($parser, $args) : $args;
	}

	public static function add_module_parser($type, $callback){
		wpjam_add_item('json_module_parser', $type, $callback);
	}

	public static function redirect($action){
		if(!wpjam_doing_debug()){
			header('X-Content-Type-Options: nosniff');

			rest_send_cors_headers(false); 

			if('OPTIONS' === $_SERVER['REQUEST_METHOD']){
				status_header(403);
				exit;
			}

			$type	= wp_is_jsonp_request() ? 'javascript' : 'json';

			@header('Content-Type: application/'.$type.'; charset='.get_option('blog_charset'));
		}

		if(!str_starts_with($action, 'mag.')){
			return;
		}

		$part	= wpjam_find(['_jsonp', '_json'], fn($v)=> call_user_func('wp_is'.$v.'_request')) ?: '';

		add_filter('wp_die'.$part.'_handler',	[self::class, 'filter_die_handler']);

		$name	= wpjam_remove_prefix($action, 'mag.');
		$name	= wpjam_remove_prefix($name, 'mag.');	// 兼容
		$name	= str_replace('/', '.', $name);
		$name	= apply_filters('wpjam_json_name', $name);
		$result	= wpjam_var('json', $name);
		$user	= wpjam_get_current_user();

		if($user && !empty($user['user_id'])){
			wp_set_current_user($user['user_id']);
		}

		wpjam_map([
			'post_type'	=> ['WPJAM_Posts',		'parse_json_module'],
			'taxonomy'	=> ['WPJAM_Terms',		'parse_json_module'],
			'setting'	=> ['WPJAM_Setting',	'parse_json_module'],
			'media'		=> ['WPJAM_Posts',		'parse_media_json_module'],
			'data_type'	=> ['WPJAM_Data_Type',	'parse_json_module'],
			'config'	=> 'wpjam_get_config'
		], fn($v, $k)=> self::add_module_parser($k, $v));

		do_action('wpjam_api', $name);

		$object	= self::get($name);
		$object	= $object ?: new WP_Error('invalid_api', '接口未定义');
		$result	= is_wp_error($object) ? $object : wpjam_catch([$object, 'response']);

		self::send($result);
	}

	public static function send($data=[], $status_code=null){
		$data	= wpjam_parse_error($data);
		$result	= self::encode($data);

		if(!headers_sent() && !wpjam_doing_debug()){
			if(!is_null($status_code)){
				status_header($status_code);
			}

			if(wp_is_jsonp_request()){
				$result	= '/**/' . $_GET['_jsonp'] . '(' . $result . ')';

				$type	= 'javascript';
			}else{
				$type	= 'json';
			}

			@header('Content-Type: application/'.$type.'; charset='.get_option('blog_charset'));
		}

		echo $result;

		exit;
	}

	public static function encode($data){
		return wp_json_encode($data, JSON_UNESCAPED_UNICODE);
	}

	public static function decode($json, $assoc=true){
		$json	= wpjam_strip_control_characters($json);

		if(!$json){
			return new WP_Error('json_decode_error', 'JSON 内容不能为空!');
		}

		$result	= json_decode($json, $assoc);

		if(is_null($result)){
			$result	= json_decode(stripslashes($json), $assoc);

			if(is_null($result)){
				if(wpjam_doing_debug()){
					print_r(json_last_error());
					print_r(json_last_error_msg());
				}
				trigger_error('json_decode_error '. json_last_error_msg()."\n".var_export($json,true));
				return new WP_Error('json_decode_error', json_last_error_msg());
			}
		}

		return $result;
	}

	public static function filter_die_handler(){
		return fn($message, $title='', $code=0)=> self::send(WPJAM_Error::convert($message, $title, $code));
	}

	public static function get_current($output='name'){
		$name	= wpjam_var('json');

		return $output == 'object' ? self::get($name) : $name;
	}

	public static function get_rewrite_rule(){
		return [
			['api/([^/]+)/(.*?)\.json?$',	['module'=>'json', 'action'=>'mag.$matches[1].$matches[2]'], 'top'],
			['api/([^/]+)\.json?$', 		'index.php?module=json&action=$matches[1]', 'top'],
		];
	}

	public static function get_defaults(){
		return [
			'post.list'		=> ['modules'=>['WPJAM_Posts', 'json_modules_callback']],
			'post.calendar'	=> ['modules'=>['WPJAM_Posts', 'json_modules_callback']],
			'post.get'		=> ['modules'=>['WPJAM_Posts', 'json_modules_callback']],
			'media.upload'	=> ['modules'=>['type'=>'media', 'args'=>['media'=>'media']]],
			'site.config'	=> ['modules'=>['type'=>'config']],
		];
	}

	public static function __callStatic($method, $args){
		if(in_array($method, ['parse_post_list_module', 'parse_post_get_module'])){
			$args	= $args[0] ?? [];
			$action	= str_replace(['parse_post_', '_module'], '', $method);

			return self::parse_module(['type'=>'post_type', 'args'=>array_merge($args, ['action'=>$action])]);
		}
	}
}

class WPJAM_Setting extends WPJAM_Args{
	private $values;

	public function __call($method, $args){
		if(str_ends_with($method, '_option')){
			$action		= wpjam_remove_postfix($method, '_option');
			$cb_args	= $this->type == 'blog_option' ? [$this->blog_id] : [];
			$cb_args[]	= $this->name;

			if($action == 'get'){
				if(isset($this->values)){
					return $this->values;
				}
			}elseif(in_array($action, ['add', 'update'])){
				$value		= array_shift($args);
				$cb_args[]	= $value ? $this->sanitize_option($value) : $value;
			}

			$cb		= $action.'_'.$this->type;
			$result	= $cb(...$cb_args);

			if($action == 'get'){
				$this->values	= $result = $result === false ? ($args ? $args[0] : []) : $this->sanitize_option($result);
			}else{
				$this->values	= null;
			}

			return $result;
		}elseif(str_ends_with($method, '_setting') || in_array($method, ['get', 'update', 'delete'])) {
			$action	= wpjam_remove_postfix($method, '_setting');
			$values	= $this->get_option();
			$name	= array_shift($args);

			if($action == 'get'){
				if(!$name){
					return $values;
				}

				if(is_array($name)){
					return wpjam_fill(array_filter($name), [$this, 'get']);
				}

				$value	= is_array($values) ? ($values[$name] ?? null) : null;

				if(is_null($value) || is_wp_error($value)){
					return null;
				}

				return is_string($value) ? str_replace("\r\n", "\n", trim($value)) : $value;
			}else{
				if($action == 'update'){
					$values	= array_replace($values, (is_array($name) ? $name : [$name=>array_shift($args)]));
				}else{
					$values	= wpjam_except($values, $name);
				}

				return $this->update_option($values);
			}
		}
	}

	public static function get_instance($type='', $name='', $blog_id=0){
		if(!in_array($type, ['option', 'site_option']) || !$name){
			return null;
		}

		$key	= $type.':'.$name;

		if(is_multisite() && $type == 'option'){
			$type		= 'blog_option';
			$blog_id	= (int)$blog_id ?: get_current_blog_id();
			$key		.= ':'.$blog_id;
		}

		return wpjam_get_instance('setting', $key, fn()=> new static([
			'type'		=> $type,
			'name'		=> $name,
			'blog_id'	=> $blog_id
		]));
	}

	public static function sanitize_option($value){
		return (is_wp_error($value) || !$value) ? [] : $value;
	}

	public static function parse_json_module($args){
		$option	= array_get($args, 'option_name');

		if($option){
			$setting	= array_get($args, 'setting_name') ?? array_get($args, 'setting');
			$output		= array_get($args, 'output') ?: ($setting ?: $option);
			$object 	= WPJAM_Option_Setting::get($option);
			$value		= $object ? $object->prepare() : wpjam_get_option($option);
			$value		= $setting ? ($value[$setting] ?? null) : $value;

			return [$output	=> $value];	
		}
	}
}

/**
* @config menu_page, admin_load, register_json, init, loaded, orderby
**/
#[config('menu_page', 'admin_load', 'register_json', 'init', 'orderby')]
class WPJAM_Option_Setting extends WPJAM_Register{
	protected function filter_args(){
		return $this->args;
	}

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

		if($value && $key == 'menu_page'){
			if(is_network_admin() && !$this->site_default){
				return;
			}

			if(wp_is_numeric_array($value)){
				foreach($value as &$m){
					if(!empty($m['tab_slug'])){
						if(empty($m['plugin_page'])){
							$m	= null;
						}
					}elseif(!empty($m['menu_slug']) && $m['menu_slug'] == $this->name){
						$m	= wp_parse_args($m, ['menu_title'=>$this->title]);
					}
				}

				return array_filter($value);
			}else{
				if(!empty($value['tab_slug'])){
					if(empty($value['plugin_page'])){
						return;
					}

					$defaults	= ['title'=>$this->title];
				}else{
					$defaults	= ['menu_slug'=>$this->name, 'menu_title'=>$this->title];
				}

				return wp_parse_args($value, $defaults);
			}
		}

		return $value;
	}

	public function get_current(){
		return self::get_sub(self::generate_sub_name()) ?: $this;
	}

	protected function get_sections($get_subs=false, $filter=true){
		$sections	= $this->get_arg('sections');
		$sections	= is_array($sections) ? $sections : [];

		if(!$sections){
			$fields	= $this->get_arg('fields', null, false);

			if(!is_null($fields)){
				$id			= $this->sub_name ?: $this->name;
				$sections	= [$id=> ['title'=>$this->title, 'fields'=>$fields]];
			}
		}

		$sections	= array_filter($sections, 'is_array');

		foreach($sections as $id => &$section){
			$section['fields']	= $section['fields'] ?? [];

			if(is_callable($section['fields'])){
				$section['fields']	= $section['fields']($id, $this->name);
			}
		}

		$subs		= $get_subs ? $this->get_subs() : [];
		$sections	= array_reduce($subs, fn($sections, $sub)=> array_merge($sections, $sub->get_sections(false, false)), $sections);

		return $filter ? WPJAM_Option_Section::filter($sections, $this->name) : $sections;
	}

	public function get_fields($get_subs=false){
		return array_merge(...array_column($this->get_sections($get_subs), 'fields'));
	}

	public function get_setting($name, ...$args){
		$null	= $name ? null : [];
		$type	= $this->option_type;
		$value	= wpjam_get_setting($this->name, $name);

		if($value !== $null){
			return $value; 
		}

		if($this->site_default && is_multisite()){
			$value	= wpjam_get_site_setting($this->name, $name);

			if($value !== $null){
				return $value; 
			}
		}

		if($args && $args[0] !== $null){
			return $args[0];
		}

		if($this->field_default){
			$this->_defaults ??= $this->call_fields('get_defaults');

			return $name ? array_get($this->_defaults, $name) : $this->_defaults;
		}

		return $null;
	}

	public function update_setting(...$args){
		return wpjam_update_setting($this->name, ...$args);	
	}

	public function delete_setting(...$args){
		return wpjam_delete_setting($this->name, ...$args);	
	}

	protected function call_fields($method, ...$args){
		$get_subs	= $method != 'validate';
		$fields		= $this->get_fields($get_subs);

		return wpjam_fields($fields)->$method(...$args);
	}

	public function prepare(){
		return $this->call_fields('prepare', ['value_callback'=>[$this, 'value_callback']]);
	}

	public function validate($value){
		return $this->call_fields('validate', $value);
	}

	public function value_callback($name=''){
		if($this->option_type == 'array'){
			return is_network_admin() ? wpjam_get_site_setting($this->name, $name) : $this->get_setting($name);
		}else{
			return get_option($name, null);
		}
	}

	public function render($page){
		$tab_page	= $page->tab_page;
		$sections	= $this->get_sections();
		$form		= wpjam_tag('form', ['action'=>'#', 'method'=>'POST', 'id'=>'wpjam_option']);

		foreach($sections as $id => $section){
			$tab	= wpjam_tag();

			if(count($sections) > 1){
				if(!$tab_page){
					$tab	= wpjam_tag('div', ['id'=>'tab_'.$id]);
					$attr	= !empty($section['show_if']) ? ['data-show_if'=>wpjam_parse_show_if($section['show_if'])] : [];
					$nav	??= wpjam_tag('ul');

					$nav->append([$section['title'], 'a', ['class'=>'nav-tab', 'href'=>'#tab_'.$id]], 'li', $attr);
				}

				if(!empty($section['title'])){
					$tab->append($section['title'], ($tab_page ? 'h3' : 'h2'));
				}
			}

			if(!empty($section['callback'])) {
				$tab->append(wpjam_ob_get_contents($section['callback'], $section));
			}

			if(!empty($section['summary'])) {
				$tab->append(wpautop($section['summary']));
			}

			$tab->append(wpjam_fields($section['fields'])->render(['value_callback'=>[$this, 'value_callback']]))->append_to($form);
		}

		$button	= wpjam_tag('p', ['submit'], get_submit_button('', 'primary', 'option_submit', false, ['data-action'=>'save']));

		if($this->reset){
			$button->append(get_submit_button('重置选项', 'secondary', 'option_reset', false, ['data-action'=>'reset']));
		}

		$form->append($button)->data('nonce', wp_create_nonce($this->option_group));

		if(isset($nav)){
			$form->before($nav, 'h2', ['nav-tab-wrapper', 'wp-clearfix'])->wrap('div', ['tabs']);
		}

		return $form;
	}

	public function page_load(){
		if(wp_doing_ajax()){
			wpjam_add_admin_ajax('wpjam-option-action',	[$this, 'ajax_response']);
		}
	}

	public function ajax_response(){
		if(!check_ajax_referer($this->option_group, false, false)){
			wp_die('invalid_nonce');
		}

		if(!current_user_can($this->capability)){
			wp_die('access_denied');
		}

		$action	= wpjam_get_post_parameter('option_action');
		$values	= wpjam_get_data_parameter();
		$values	= $this->validate($values) ?: [];
		$fix	= is_network_admin() ? 'site_option' : 'option';

		if($this->option_type == 'array'){
			$args		= [$this->name, &$values];
			$callback	= $this->update_callback;

			if($callback){
				if(!is_callable($callback)){
					wp_die('无效的回调函数');
				}

				$args[]		= is_network_admin();
			}else{
				$callback	= 'wpjam_update_'.$fix;
			}

			$current	= $this->value_callback();

			if($action == 'reset'){
				$values	= wpjam_diff($current, $values);
			}else{
				$values	= wpjam_filter(array_merge($current, $values), fn($v)=> !is_null($v), true);
				$result	= $this->call_method('sanitize_callback', $values, $this->name);
				$values	= wpjam_throw_if_error($result) ?? $values;
			}

			$callback(...$args);
		}else{
			foreach($values as $name => $value){
				$args	= [$name];

				if($action == 'reset'){
					$callback	= 'delete_'.$fix;
				}else{
					$args[]		= $value;
					$callback	= 'update_'.$fix;
				}

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

		$errors	= array_filter(get_settings_errors(), fn($e)=> !in_array($e['type'], ['updated', 'success', 'info']));

		if($errors){
			wp_die(implode('&emsp;', array_column($errors, 'message')));
		}

		return [
			'type'		=> $this->response ?? ($this->ajax ? $action : 'redirect'),
			'errmsg'	=> $action == 'reset' ? '设置已重置。' : '设置已保存。'
		];
	}

	public static function generate_sub_name($args=null){
		$args	??= $GLOBALS;
		$args	= wp_array_slice_assoc($args, ['plugin_page', 'current_tab']);

		return $args ? wpjam_join(':', $args) : '';
	}

	public static function create($name, $args){
		$args	= is_callable($args) ? $args($name) : $args;
		$args	= wp_parse_args($args, [
			'option_group'	=> $name, 
			'option_page'	=> $name, 
			'option_type'	=> 'array',
			'capability'	=> 'manage_options',
			'ajax'			=> true,
		]);

		$except	= ['title', 'model', 'menu_page', 'admin_load', 'plugin_page', 'current_tab'];
		$sub	= self::generate_sub_name($args);
		$object	= self::get($name);

		if($object){
			if($sub){
				$object->update_args(wpjam_except($args, $except));

				return $object->register_sub($sub, $args);
			}else{
				if(is_null($object->primary)){
					return self::re_register($name, array_merge($object->to_array(), $args, ['primary'=>true]));
				}else{
					trigger_error('option_setting'.'「'.$name.'」已经注册。'.var_export($args, true));

					return $object;
				}
			}
		}else{
			if($args['option_type'] == 'array' && !doing_filter('sanitize_option_'.$name) && is_null(get_option($name, null))){
				add_option($name, []);
			}

			if($sub){
				$object	= self::register($name, wpjam_except($args, $except));

				return $object->register_sub($sub, $args);
			}else{
				return self::register($name, array_merge($args, ['primary'=>true]));
			}
		}
	}
}

/**
* @config menu_page, admin_load, init, loaded, orderby
**/
#[config('menu_page', 'admin_load', 'init', 'orderby')]
class WPJAM_Option_Section extends WPJAM_Register{
	public static function filter($sections, $option_name){
		foreach(self::get_by('option_name', $option_name) as $object){
			$object_sections	= $object->get_arg('sections');
			$object_sections	= is_array($object_sections) ? $object_sections : [];

			foreach($object_sections as $id => $section){
				if(!empty($section['fields']) && is_callable($section['fields'])){
					$section['fields']	= $section['fields']($id, $option_name);
				}

				if(isset($sections[$id])){
					$sections[$id]	= wpjam_merge($sections[$id], $section);
				}else{
					if(isset($section['title']) && isset($section['fields'])){
						$sections[$id]	= $section;
					}
				}
			}
		}

		return apply_filters('wpjam_option_setting_sections', $sections, $option_name);
	}

	public static function add($option_name, ...$args){
		$args	= is_array($args[0]) ? $args[0] : [$args[0]=> isset($args[1]['fields']) ? $args[1] : ['fields'=>$args[1]]];
		$args	= isset($args['model']) || isset($args['sections']) ? $args : ['sections'=>$args];

		return self::register(array_merge($args, ['option_name'=>$option_name]));
	}
}

class WPJAM_Option_Model{
	protected static function call_method($method, ...$args){
		$object	= self::get_object();	

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

	protected static function get_object(){
		return WPJAM_Option_Setting::get(get_called_class(), 'model', 'WPJAM_Option_Model');
	}

	public static function get_setting($name='', $default=null){
		return self::call_method('get_setting', $name) ?? $default;
	}

	public static function update_setting(...$args){
		return self::call_method('update_setting', ...$args);
	}

	public static function delete_setting($name){
		return self::call_method('delete_setting', $name);
	}
}

class WPJAM_Extend extends WPJAM_Args{
	public function load(){
		if(is_callable($this->dir)){
			$this->dir	= call_user_func($this->dir);
		}

		if(!is_dir($this->dir)){
			return;
		}

		if($this->option && is_admin()){
			if($this->sitewide){
				$this->site_default	= true;

				if(is_network_admin()){
					$this->summary	= wpjam_join(',', [$this->summary, '在管理网络激活将整个站点都会激活!']);
				}
			}

			wpjam_register_option($this->option, array_merge($this->to_array(), ['model'=>$this, 'ajax'=>false]));
		}

		foreach($this->get_data() as $extend => $value){
			$file	= $this->parse_file($extend);

			if($file && (is_admin() || !str_ends_with($file, '-admin.php'))){
				include $file;
			}
		}
	}

	private function parse_file($extend){
		if(!$extend || in_array($extend, ['.', '..'])){
			return;
		}

		if($this->hierarchical){
			if(is_dir($this->dir.'/'.$extend)){
				$file	= $extend.'/'.$extend.'.php';
			}
		}else{
			if($this->option){
				$file	= $extend.'.php';
			}else{
				if(pathinfo($extend, PATHINFO_EXTENSION) == 'php'){
					$file	= $extend;
				}
			}
		}

		return (!empty($file) && is_file($this->dir.'/'.$file)) ? $this->dir.'/'.$file : '';
	}

	private function get_data($type=''){
		if($this->option){
			if(!$type){
				$data	= $this->get_data('option');

				if($this->sitewide && is_multisite()){
					$data	= array_merge($data, $this->get_data('site_option'));
				}
			}else{
				$cb		= 'wpjam_get_'.$type;
				$data	= $cb($this->option);
				$data	= $data ? array_filter($data) : [];
				$data	= $this->sanitize_callback($data);
			}
		}else{
			if($handle = opendir($this->dir)){
				while(false !== ($extend = readdir($handle))){
					if(!in_array($extend, ['.', '..'])){
						$data[$extend]	= true;
					}
				}

				closedir($handle);
			}
		}

		return $data ?? [];
	}

	public function get_fields(){
		$fields	= [];
		$values	= $this->get_data('option');

		if(is_multisite() && $this->sitewide){
			$sitewide	= $this->get_data('site_option');

			if(is_network_admin()){
				$values	= $sitewide;
			}
		}

		if($handle = opendir($this->dir)){
			while(false !== ($extend = readdir($handle))){
				if(!$this->hierarchical){
					$extend	= wpjam_remove_postfix($extend, '.php');
				}

				$file	= $this->parse_file($extend);
				$data	= $this->get_file_data($file);

				if($data && ($data['Name'] || $data['PluginName'])){
					if(is_multisite() && $this->sitewide && !is_network_admin()){
						if(!empty($sitewide[$extend])){
							continue;
						}
					}

					$title	= $data['Name'] ?: $data['PluginName'];
					$title	= $data['URI'] ? '<a href="'.$data['URI'].'" target="_blank">'.$title.'</a>' : $title;
					$value	= !empty($values[$extend]);

					$fields[$extend] = ['title'=>$title, 'type'=>'checkbox', 'value'=>$value, 'description'=>$data['Description']];
				}
			}

			closedir($handle);
		}

		return wpjam_sort($fields, ['value'=>'DESC']);
	}

	public function sanitize_callback($data){
		if($data && !$this->hierarchical){
			$update	= false;
			$data	= array_filter($data);
			$keys	= array_keys($data);

			foreach($keys as &$key){
				if(str_ends_with($key, '.php')){
					$key	= wpjam_remove_postfix($key, '.php');
					$update	= true;
				}
			}

			if($update){
				$keys	= array_unique($keys);
				$data	= array_fill_keys($keys, true);
			}
		}

		return $data;
	}

	public static function get_file_data($file){
		return $file ? get_file_data($file, [
			'Name'			=> 'Name',
			'URI'			=> 'URI',
			'PluginName'	=> 'Plugin Name',
			'PluginURI'		=> 'Plugin URI',
			'Version'		=> 'Version',
			'Description'	=> 'Description'
		]) : [];
	}

	public static function get_file_summay($file){
		$data		= self::get_file_data($file);
		$summary	= str_replace('。', ',', $data['Description']);
		$data		= wpjam_fill(['URI', 'Name'], fn($k)=> !empty($data[$k]) ? $data[$k] : ($data['Plugin'.$k] ?? ''));

		return $summary.'详细介绍请点击:<a href="'.$data['URI'].'" target="_blank">'.$data['Name'].'</a>。';
	}

	public static function create($dir, ...$args){
		if(is_array($dir)){
			$args	= $dir;
			$dir	= wpjam_pull($args, 'dir');
		}else{
			$args	= array_shift($args) ?: [];
		}

		$hook	= wpjam_pull($args, 'hook');
		$object	= new self(array_merge($args, ['dir'=>$dir]));

		if($hook){
			wpjam_load($hook, [$object, 'load'], ($object->priority ?? 10));
		}else{
			$object->load();
		}
	}
}

class WPJAM_Notice{
	public static function filter($items){
		return array_filter(($items ?: []), fn($v)=> $v['time']>time() - MONTH_IN_SECONDS*3 && trim($v['notice']));
	}

	public static function render($type=''){
		if(!in_array($type, ['user', 'admin'])){
			self::ajax_delete();
			self::render('user');

			if(current_user_can('manage_options')){
				self::render('admin');
			}
		}else{
			$object	= self::get_instance($type);

			foreach($object->get_items() as $key => $item){
				$item	= wp_parse_args($item, [
					'type'		=> 'info',
					'class'		=> 'is-dismissible',
					'admin_url'	=> '',
					'notice'	=> '',
					'title'		=> '',
					'modal'		=> 0,
				]);

				$notice	= trim($item['notice']);

				if($item['admin_url']){
					$notice	.= $item['modal'] ? "\n\n" : ' ';
					$notice	.= '<a style="text-decoration:none;" href="'.add_query_arg(['notice_key'=>$key, 'notice_type'=>$type], home_url($item['admin_url'])).'">点击查看<span class="dashicons dashicons-arrow-right-alt"></span></a>';
				}

				$data	= ['notice_key'=>$key, 'notice_type'=>$type];
				$notice	= wpautop($notice).wpjam_get_page_button('delete_notice', ['data'=>$data]);

				if($item['modal']){
					if(empty($modal)){	// 弹窗每次只显示一条
						$modal	= $notice;
						$title	= $item['title'] ?: '消息';

						echo '<div id="notice_modal" class="hidden" data-title="'.esc_attr($title).'">'.$modal.'</div>';
					}
				}else{
					echo '<div class="notice notice-'.$item['type'].' '.$item['class'].'">'.$notice.'</div>';
				}
			}
		}			
	}

	public static function add($item, $type='admin', $id=''){
		if($type == 'admin'){
			if(is_multisite()){
				if($id && !get_site($id)){
					return;
				}
			}else{
				$id	= 0;
			}
		}else{
			if($id && !get_userdata($user_id)){
				return;
			}
		}

		$item	= is_array($item) ? $item : ['notice'=>$item];
		$item	= wp_parse_args($item, ['type'=>'error', 'notice'=>'', 'time'=>time(), 'key'=>md5(serialize($item))]);

		return (self::get_instance($type, $id))->insert($item);
	}

	public static function ajax_delete(){
		$type	= wpjam_get_data_parameter('notice_type');
		$key	= wpjam_get_data_parameter('notice_key');

		if($key){
			if($type == 'admin' && !current_user_can('manage_options')){
				wpjam_send_error_json('bad_authentication');
			}

			(self::get_instance($type))->delete($key);

			wpjam_send_json();
		}
	}

	public static function get_instance($type='', $id=0){
		$type	= $type == 'user' ? 'user' : 'admin';
		$id		= (int)$id ?: ($type == 'user' ? get_current_user_id() : get_current_blog_id());
		$name	= 'notice:'.$type.':'.$id;

		if($type == 'user'){
			return wpjam_get_handler($name, [
				'meta_key'		=> 'wpjam_notices',
				'user_id'		=> $id,
				'primary_key'	=> 'key',
				'get_items'		=> fn()=> WPJAM_Notice::filter(get_user_meta($this->user_id, $this->meta_key, true)),
				'delete_items'	=> fn()=> delete_user_meta($this->user_id, $this->meta_key),
				'update_items'	=> fn($items)=> update_user_meta($this->user_id, $this->meta_key, $items),
			]);
		}else{
			return wpjam_get_handler($name, [
				'option_name'	=> 'wpjam_notices',
				'blog_id'		=> $id,
				'primary_key'	=> 'key',
				'get_items'		=> fn()=> WPJAM_Notice::filter(wpjam_call_for_blog($this->blog_id, 'get_option', $this->option_name)),
				'update_items'	=> fn($items)=> wpjam_call_for_blog($this->blog_id, 'update_option', $this->option_name, $items),
			]);
		}
	}

	public static function on_plugins_loaded(){
		wpjam_register_page_action('delete_notice', [
			'button_text'	=> '删除',
			'tag'			=> 'span',
			'class'			=> 'hidden delete-notice',
			'callback'		=> [self::class, 'ajax_delete'],
			'direct'		=> true,
		]);

		add_action('admin_notices', [self::class, 'render']);
	}
}

/**
* @config orderby=order order=ASC
**/
#[config(['orderby'=>'order', 'order'=>'ASC'])]
class WPJAM_Platform extends WPJAM_Register{
	public function __get($key){
		if($key == 'path'){
			return (bool)$this->get_items();
		}

		return parent::__get($key);
	}

	public function __call($method, $args){
		if(str_ends_with($method, '_by_page_type')){
			$method	= wpjam_remove_postfix($method, '_by_page_type');
			$item	= $this->get_item(array_shift($args));
			$object	= wpjam_get_data_type_object(wpjam_pull($item, 'page_type'), $item);

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

		return $this->call_dynamic_method($method, ...$args);
	}

	public function verify(){
		return call_user_func($this->verify);
	}

	public function get_tabbar($page_key){
		$item	= $this->get_item($page_key);

		if($item && !empty($item['tabbar'])){
			$tabbar	= $item['tabbar'] === true ? [] : $item['tabbar'];

			return $tabbar+['text'=>$item['title'] ?? ''];
		}
	}

	public function get_page($page_key){
		$path	= $this->get_item_arg($page_key, 'path');

		return $path ? explode('?', $path)[0] : '';
	}

	public function get_fields($page_key){
		$item	= $this->get_item($page_key);
		$fields	= $item['fields'] ?? '';

		if($fields){
			$fields	= is_callable($fields) ? $fields($item, $page_key) : $fields;
		}else{
			$fields	= $this->get_path_fields_by_page_type($page_key, $item);
		}

		return $fields ?: [];
	}

	public function has_path($page_key, $strict=false){
		$item	= $this->get_item($page_key);

		if(!$item || ($strict && isset($item['path']) && $item['path'] === false)){
			return false;
		}

		return isset($item['path']) || isset($item['callback']);
	}

	public function get_path($page_key, $args=[]){
		$item		= $this->get_item($page_key);
		$callback	= wpjam_pull($item, 'callback');
		$args		= is_array($args) ? wp_parse_args(array_filter($args, fn($v)=> !is_null($v)), $item) : $args;

		if($callback){
			if(is_callable($callback) && is_array($args)){
				return $callback($args, $page_key) ?: '';
			}
		}else{
			$path	= $this->get_path_by_page_type($page_key, $args, $item);

			if($path){
				return $path;
			}
		}

		if(isset($item['path'])){
			return (string)$item['path'];
		}
	}

	public function get_paths($page_key, $args=[]){
		$args	= array_merge($args, wp_array_slice_assoc($this->get_item($page_key), [$name]));
		$items	= $this->query_items_by_page_type($page_key, $args);

		if($items){
			$paths	= array_map(fn($item)=> $this->get_path($page_key, $item['value']), $items);
			$paths	= array_filter($paths, fn($path)=> $path && !is_wp_error($path));
		}

		return $paths ?? [];
	}

	public function parse_path($args, $postfix=''){
		$page_key	= wpjam_pull($args, 'page_key'.$postfix);

		if($page_key == 'none'){
			if(!empty($args['video'])){
				return [
					'type'	=> 'video',
					'video'	=> $args['video'],
					'vide'	=> wpjam_get_qqv_id($args['video'])
				];
			}

			return ['type'=>'none'];
		}elseif($page_key){
			if(!$this->get_item($page_key)){
				return [];
			}

			$args	= $postfix ? wpjam_map($this->get_fields($page_key), fn($v, $k)=> $args[$k.$postfix] ?? null) : $args;
			$path	= $this->get_path($page_key, $args);

			if(is_wp_error($path)){
				return $path;
			}elseif(is_array($path)){
				return $path;
			}elseif(isset($path)){
				return ['type'=>'', 'page_key'=>$page_key, 'path'=>$path];
			}
		}

		return [];
	}

	public function registered(){
		if($this->name == 'template'){
			wpjam_register_path('home',		'template',	['title'=>'首页',		'path'=>home_url(),	'group'=>'tabbar']);
			wpjam_register_path('category',	'template',	['title'=>'分类页',		'path'=>'',	'page_type'=>'taxonomy']);
			wpjam_register_path('post_tag',	'template',	['title'=>'标签页',		'path'=>'',	'page_type'=>'taxonomy']);
			wpjam_register_path('author',	'template',	['title'=>'作者页',		'path'=>'',	'page_type'=>'author']);
			wpjam_register_path('post',		'template',	['title'=>'文章详情页',	'path'=>'',	'page_type'=>'post_type']);
			wpjam_register_path('external', 'template',	['title'=>'外部链接',		'path'=>'',	'fields'=>['url'=>['type'=>'url', 'required'=>true, 'placeholder'=>'请输入链接地址。']],	'callback'=>fn($args)=> ['type'=>'external', 'url'=>$args['url']]]);
		}
	}

	public static function get_options($output=''){
		return wp_list_pluck(self::get_registereds(), 'title', $output);
	}

	public static function get_current($args=[], $output='object'){
		if($output == 'bit' && wp_is_numeric_array($args)){
			$bits	= wp_list_pluck(self::get_by(['path'=>true]), 'bit');
			$args	= array_values(wp_array_slice_assoc(array_flip($bits), $args));
		}

		$args	= $args ?: ['path'=>true];
		$object	= wpjam_find(self::get_by($args), fn($object)=> $object && $object->verify());

		if($object){
			if($output == 'bit'){
				return $object->bit;
			}elseif($output == 'object'){
				return $object;
			}else{
				return $object->name;
			}
		}
	}

	protected static function get_defaults(){
		return [
			'weapp'		=> ['bit'=>1,	'order'=>4,		'title'=>'小程序',	'verify'=>'is_weapp'],
			'weixin'	=> ['bit'=>2,	'order'=>4,		'title'=>'微信网页',	'verify'=>'is_weixin'],
			'mobile'	=> ['bit'=>4,	'order'=>8,		'title'=>'移动网页',	'verify'=>'wp_is_mobile'],
			'template'	=> ['bit'=>8,	'order'=>10,	'title'=>'网页',		'verify'=>'__return_true']
		];
	}
}

class WPJAM_Platforms{
	use WPJAM_Instance_Trait;

	private $platforms	= [];
	private $cache		= [];

	protected function __construct($platforms){
		$this->platforms	= $platforms;
	}

	public function __call($method, $args){
		return $this->call_dynamic_method($method, ...$args);
	}

	protected function has_path($page_key, $operator='AND', $strict=false){
		$fn	= fn($pf)=> $pf->has_path($page_key, $strict);

		if($operator == 'AND'){
			return wpjam_every($this->platforms, $fn);
		}elseif($operator == 'OR'){
			return wpjam_some($this->platforms, $fn);
		}
	}

	public function get_fields($args, $strict=false){
		$prepend	= wpjam_pull($args, 'prepend_name');
		$postfix	= wpjam_pull($args, 'postfix');
		$title		= wpjam_pull($args, 'title') ?: '页面';
		$key		= 'page_key'.$postfix;
		$backup		= (count($this->platforms) > 1 && !$strict) ? $key.'_backup' : '';
		$paths		= WPJAM_Path::get_by($args);
		$cache_key	= md5(serialize(['postfix'=>$postfix, 'strict'=>$strict, 'page_keys'=>array_keys($paths)]));
		$cache		= $this->cache[$cache_key] ?? [];

		if(!$cache){
			$groups	= WPJAM_Path::get_groups($strict);
			$cache	= ['options'=>$groups];
			$cache	+= $backup ? ['show_if'=>[], 'backup'=>$groups] : [];
			$parser	= fn($path, $postfix)=> [$path->name=> [
				'label'		=> $path->title,
				'fields'	=> wpjam_array($path->get_fields($this->platforms), fn($k, $v)=> [$k.$postfix, wpjam_except($v, 'title')])
			]];

			foreach($paths as $path){
				if($this->has_path($path->name, 'OR', $strict)){
					$group	= $path->group ?: ($path->tabbar ? 'tabbar' : 'others');

					$cache['options'][$group]['options']	+= $parser($path, $postfix);

					if($backup){
						if($this->has_path($path->name, 'AND')){
							$cache['backup'][$group]['options']	+= $parser($path, $postfix.'_backup');
						}else{
							$cache['show_if'][]	= $path->name;
						}
					}
				}
			}

			$this->cache[$cache_key] = $cache;
		}

		$fields	= [$key.'_set'=>['title'=>$title, 'type'=>'fieldset', 'fields'=>[$key=>['options'=>$cache['options']]]]];
		$fields	+= $backup ? [$backup.'_set'=>['title'=>'备用'.$title, 'type'=>'fieldset', 'fields'=>[$backup=>['options'=>$cache['backup']]], 'show_if'=>[$key, 'IN', $cache['show_if']]]] : [];

		return wpjam_map($fields, fn($field)=> $field+['prepend_name'=>$prepend]);
	}

	public function get_current($output='object'){
		if(count($this->platforms) == 1){
			return $output == 'object' ? reset($this->platforms) : reset($this->platforms)->name;
		}else{
			return WPJAM_Platform::get_current(array_keys($this->platforms), $output);
		}
	}

	public function parse_item($item, $postfix=''){
		$platform	= $this->get_current();
		$parsed		= $platform->parse_path($item, $postfix);

		if((!$parsed || is_wp_error($parsed)) && count($this->platforms) > 1){
			$parsed	= $platform->parse_path($item, $postfix.'_backup');
		}

		return ($parsed && !is_wp_error($parsed)) ? $parsed : ['type'=>'none'];
	}

	public function validate_item($item, $postfix='', $title=''){
		foreach($this->platforms as $platform){
			$result	= $platform->parse_path($item, $postfix);

			if(is_wp_error($result) || $result){
				if(!$result && count($this->platforms) > 1 && !str_ends_with($postfix, '_backup')){
					return $this->validate_item($item, $postfix.'_backup', '备用'.$title);
				}

				return $result ?: new WP_Error('invalid_page_key', '无效的'.$title.'页面。');
			}
		}

		return $result;
	}

	public static function get_instance($platforms=null){
		$args		= is_null($platforms) ? ['path'=>true] : (array)$platforms;
		$objects	= array_filter(WPJAM_Platform::get_by($args));

		if($objects){
			return self::instance(implode('-', array_keys($objects)), fn()=> new self($objects));
		}
	}
}

class WPJAM_Path extends WPJAM_Register{
	public function __get($key){
		if(in_array($key, ['platform', 'path_type'])){
			return array_keys($this->get_items());
		}

		return parent::__get($key);
	}

	public function get_fields($platforms){
		return array_reduce($platforms, fn($fields, $pf)=> array_merge($fields, $pf->get_fields($this->name)), []);
	}

	public static function get_groups($strict=false){
		$groups	= array_merge(
			['tabbar'=>['title'=>'菜单栏/常用', 'options'=>[]]],
			wpjam_get_items('path_group'),
			['others'=>['title'=>'其他页面', 'options'=>[]]]
		);

		if(!$strict){
			$groups['tabbar']['options']['none']	= '只展示不跳转';
		}

		return $groups;
	}

	public static function create($name, ...$args){
		$object	= self::get($name);
		$object	= $object ?: self::register($name, []);
		$args	= count($args) == 2 ? $args[1]+['platform'=>$args[0]] : $args[0];
		$args	= wp_is_numeric_array($args) ? $args : [$args];

		foreach($args as $_args){
			$pfs	= wp_array_slice_assoc($_args, ['platform', 'path_type']);
			$pfs	= array_merge(...array_map('wpjam_array', array_values($pfs)));

			foreach($pfs as $pf){
				$platform	= WPJAM_Platform::get($pf);

				if($platform){
					$page_type	= array_get($_args, 'page_type');

					if($page_type && in_array($page_type, ['post_type', 'taxonomy']) && empty($_args[$page_type])){
						$_args[$page_type]	= $name;
					}

					if(isset($_args['group']) && is_array($_args['group'])){
						$group	= wpjam_pull($_args, 'group');

						if(isset($group['key'], $group['title'])){
							wpjam_add_item('path_group', $group['key'], ['title'=>$group['title'], 'options'=>[]]);

							$_args['group']	= $group['key'];
						}
					}

					$_args	= array_merge($_args, ['platform'=>$pf, 'path_type'=>$pf]);

					$object->update_args($_args, false)->add_item($pf, $_args);

					$platform->add_item($name, $_args);
				}
			}
		}

		return $object;
	}

	public static function remove($name, $pf=''){
		if($pf){
			$object		= self::get($name);
			$platform	= WPJAM_Platform::get($pf);

			if($object){
				$object->delete_item($pf);
			}

			if($platform){
				$platform->delete_item($name);
			}
		}else{
			self::unregister($name);

			array_walk(WPJAM_Platform::get_registereds(), fn($pf)=> $pf->delete_item($name));
		}
	}
}

class WPJAM_Data_Type extends WPJAM_Register{
	public function __call($method, $args){
		return $this->call_method($method, ...$args);
	}

	public function prepare_value($value, $field){
		if($field->parse_required && $value){
			return $this->parse_value($value, $field) ?? $value;
		}

		return $value;
	}

	public function validate_value($value, $field){
		if($value){
			return $this->validate_by_field($value, $field) ?? $value;
		}
	}

	public function query_items($args){
		$args	= array_filter($args, fn($v)=> !is_null($v));
		$args	= wp_parse_args($args, ['number'=>10, 'data_type'=>true]);

		if($this->query_items){
			return wpjam_catch($this->query_items, $args);
		}elseif($this->model){
			$args	= isset($args['model']) ? wpjam_except($args, ['data_type', 'model', 'label_field', 'id_field']) : $args;
			$result	= wpjam_catch([$this->model, 'query_items'], $args, true);
			$items	= is_wp_error($result) ? $result : (wp_is_numeric_array($result) ? $result : $result['items']);

			if(is_wp_error($items) || !isset($items)){
				return $items ?: new WP_Error('undefined_method', ['query_items', '回调函数']);
			}

			return $this->label_field ? array_map(fn($item)=> [
				'label'	=> is_object($item) ? $item->{$this->label_field}	: $item[$this->label_field],
				'value'	=> is_object($item) ? $item->{$this->id_field}		: $item[$this->id_field]
			], $items) : $items;
		}
	}

	public function query_label($id, $field=null){
		if($this->query_label){
			return $id ? call_user_func($this->query_label, $id, $field) : '';
		}elseif($this->model && $this->label_field){
			if($id){
				$data	= $this->model::get($id);
				$value	= $data ? $data[$this->label_field] : null;

				return $value ?? $id;
			}

			return '';
		}
	}

	public static function parse_json_module($args){
		$name	= wpjam_pull($args, 'data_type');
		$args	= array_get($args, 'query_args', $args);
		$args	= $args ? wp_parse_args($args) : [];
		$object	= self::get_instance($name, $args);

		if(!$object){
			return new WP_Error('invalid_data_type');
		}

		$args	= array_merge($args, ['search'=>wpjam_get_parameter('s')]);
		$items	= $object->query_items($args);

		return ['items'=>is_wp_error($items) ? [] : $items];
	}

	public static function ajax_response($data){
		$name	= $data['data_type'];
		$args	= wpjam_pull($data, 'query_args');
		$object	= self::get_instance($name, $args);
		$items	= $object ? ($object->query_items($args) ?: []) : [];
		$items	= is_wp_error($items) ? [[$items->get_error_message()]] : $items;

		return ['items'=>$items];
	}

	public static function get_defaults(){
		return [
			'post_type'	=> [
				'model'			=> 'WPJAM_Post',
				'label_field'	=> 'post_title',
				'id_field'		=> 'ID',
				'meta_type'		=> 'post',
				'parse_value'	=> 'wpjam_get_post'
			],
			'taxonomy'	=> [
				'model'			=> 'WPJAM_Term',
				'label_field'	=> 'name',
				'id_field'		=> 'term_id',
				'meta_type'		=> 'term',
				'parse_value'	=> 'wpjam_get_term'
			],
			'author'	=> [
				'model'			=> 'WPJAM_User',
				'label_field'	=> 'display_name',
				'id_field'		=> 'ID',
				'meta_type'		=> 'user'
			],
			'model'		=> [],
			'video'		=> ['parse_value'=>'wpjam_get_video_mp4'],
		];
	}

	public static function get_instance($name, $args=[]){
		if(is_a($name, 'WPJAM_Field')){
			$field	= $name;
			$name	= $field->data_type;
			$object	= self::get($name);

			if($object){
				$args	= $field->query_args;
				$args	= $args ? wp_parse_args($args) : [];

				if($field->$name){
					$args[$name]	= $field->$name;
				}elseif(!empty($args[$name])){
					$field->$name	= $args[$name];
				}
			}
		}else{
			$object	= self::get($name);
		}

		if($object){
			if($name == 'model'){
				$model	= $args['model'];

				if(!$model || !class_exists($model)){
					return null;
				}

				$sub	= $object->get_sub($model);

				if($sub){
					return $sub;
				}

				$args['meta_type']		= $model::get_meta_type();
				$args['label_field']	??= wpjam_pull($args, 'label_key') ?: 'title';
				$args['id_field']		??= wpjam_pull($args, 'id_key') ?: $model::get_primary_key();

				$object	= $object->register_sub($model, $args);
				$args	= wpjam_except($args, 'meta_type');
			}

			if(isset($field) && $object->model){
				$field->query_args	= $args ?: new StdClass;
			}
		}

		return $object;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit