HEX
Server: nginx/1.22.1
System: Linux VM-16-9-centos 3.10.0-1160.99.1.el7.x86_64 #1 SMP Wed Sep 13 14:19:20 UTC 2023 x86_64
User: www (1001)
PHP: 7.3.31
Disabled: 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
Upload Files
File: /www/wwwroot/softfox.com.cn/wp-content/plugins/wpjam-basic/includes/class-wpjam-admin.php
<?php
class WPJAM_Admin{
	public static function filter_admin_url($url, $path, $blog_id=null, $scheme='admin'){
		if($path && is_string($path) && str_starts_with($path, 'page=')){
			$url	= get_site_url($blog_id, 'wp-admin/', $scheme);
			$url	.= 'admin.php?'.$path;
		}

		return $url;
	}

	public static function filter_html($html){
		if(WPJAM_Plugin_Page::get_current()){
			$queried	= wpjam_get_items('queried_menu');
			$search		= array_column($queried, 'search');
			$replace	= array_column($queried, 'replace');
		}else{
			$search		= '<hr class="wp-header-end">';
			$replace	= $search.wpautop(get_screen_option('page_summary'));
		}

		return str_replace($search, $replace, $html);
	}

	public static function filter_parent_file($parent_file){
		if($GLOBALS['submenu_file']){
			$parent_files	= wpjam_get_items('parent_files');

			if(isset($parent_files[$GLOBALS['submenu_file']])){
				return $parent_files[$GLOBALS['submenu_file']];
			}
		}

		return $parent_file;
	}

	public static function on_current_screen($screen=null){
		$object	= WPJAM_Plugin_Page::get_current();

		if($object){
			if(wpjam_get_items('queried_menu')){
				add_filter('wpjam_html', [self::class, 'filter_html']);
			}

			$object->load($screen);
		}else{
			if(wpjam_get_items('parent_files')){
				add_filter('parent_file', [self::class, 'filter_parent_file']);
			}

			if($screen){
				WPJAM_Builtin_Page::init($screen);

				if(!wp_doing_ajax() && $screen->get_option('page_summary')){
					add_filter('wpjam_html', [self::class, 'filter_html']);
				}
			}
		}
	}
}

class WPJAM_Admin_Action extends WPJAM_Register{
	protected function parse_submit_button($button, $name=null, $render=true){
		$button	= $button ?: [];
		$button	= is_array($button) ? $button : [$this->name => $button];

		foreach($button as $key => &$item){
			$item	= is_array($item) ? $item : ['text'=>$item];
			$item	= wp_parse_args($item, ['response'=>($this->response ?? $this->name), 'class'=>'primary']);

			if($render){
				$item	= get_submit_button($item['text'], $item['class'], $key, false);
			}
		}

		if($name){
			if(!isset($button[$name])){
				wp_die('无效的提交按钮');
			}

			return $button[$name];
		}else{
			return $render ? implode('', $button) : $button;
		}
	}

	protected function parse_nonce_action($args=[]){
		$prefix	= $GLOBALS['plugin_page'] ?? $GLOBALS['current_screen']->id;
		$key	= $this->name;

		if($args){
			if(!empty($args['bulk'])){
				$key	= 'bulk_'.$key;
			}elseif(!empty($args['id'])){
				$key	= $key.'-'.$args['id'];
			}
		}

		return $prefix.'-'.$key;
	}

	public function create_nonce($args=[]){
		$action	= $this->parse_nonce_action($args);

		return wp_create_nonce($action);
	}

	public function verify_nonce($args=[]){
		$action	= $this->parse_nonce_action($args);

		return check_ajax_referer($action, false, false);
	}
}

class WPJAM_Page_Action extends WPJAM_Admin_Action{
	public function is_allowed($type=''){
		$capability	= $this->capability ?? ($type ? 'manage_options' : 'read');

		return current_user_can($capability, $this->name);
	}

	public function callback($type=''){
		if($type == 'form'){
			$page_title	= wpjam_get_post_parameter('page_title');

			if(!$page_title){
				foreach(['page_title', 'button_text', 'submit_text'] as $key){
					if(!empty($this->$key) && !is_array($this->$key)){
						$page_title	= $this->$key;
						break;
					}
				}
			}

			return [
				'form'			=> $this->get_form(),
				'width'			=> $this->width ?: 720,
				'modal_id'		=> $this->modal_id ?: 'tb_modal',
				'page_title'	=> $page_title
			];
		}

		if(!$this->verify_nonce()){
			wp_die('invalid_nonce');
		}

		if(!$this->is_allowed($type)){
			wp_die('access_denied');
		}

		$callback		= '';
		$submit_name	= null;

		if($type == 'submit'){
			$submit_name	= wpjam_get_post_parameter('submit_name',	['default'=>$this->name]);
			$submit_button	= $this->get_submit_button($submit_name);

			$callback	= $submit_button['callback'] ?? '';
			$response	= $submit_button['response'];
		}else{
			$response	= $this->response ?? $this->name;
		}

		$callback	= $callback ?: $this->callback;

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

		$cb_args	= [$this->name, $submit_name];

		if($this->validate){
			$data	= wpjam_get_data_parameter();
			$data	= $this->get_fields('object')->validate($data);

			$cb_args	= array_merge([$data], $cb_args);
		}

		$result		= wpjam_try($callback, ...$cb_args);
		$response	= ['type'=>$response];

		if(is_array($result)){
			$response	= array_merge($response, $result);
		}elseif($result === false || is_null($result)){
			$response	= new WP_Error('invalid_callback', ['返回错误']);
		}elseif($result !== true){
			if($this->response == 'redirect'){
				$response['url']	= $result;
			}else{
				$response['data']	= $result;
			}
		}

		return apply_filters('wpjam_ajax_response', $response);
	}

	public function get_data(){
		$data		= $this->data ?: [];
		$callback	= $this->data_callback;

		if($callback && is_callable($callback)){
			$_data	= wpjam_try($callback, $this->name, $this->get_fields());

			return array_merge($data, $_data);
		}

		return $data;
	}

	public function get_button($args=[]){
		if(!$this->is_allowed()){
			return '';
		}

		$data	= array_pull($args, 'data') ?: [];
		$data	= $this->generate_data_attr(['data'=>$data]);

		$this->update_args($args);

		$tag	= $this->tag ?: 'a';
		$text	= $this->button_text ?? '保存';
		$class	= $this->class ?? 'button-primary large';
		$attr	= [
			'title'	=> $this->page_title ?: $text,
			'class'	=> array_merge(array_wrap($class), ['wpjam-button']),
			'style'	=> $this->style,
			'data'	=> $data
		];

		return wpjam_tag($tag, $attr, $text);
	}

	public function get_form(){
		if(!$this->is_allowed()){
			return '';
		}

		$attr	= [
			'method'	=> 'post',
			'action'	=> '#',
			'id'		=> $this->form_id ?: 'wpjam_form',
			'data'		=> $this->generate_data_attr([], 'form')
		];

		$args	= array_merge($this->args, ['data'=>$this->get_data()]);
		$form	= $this->get_fields('object')->render($args, false)->wrap('form', $attr);
		$button	= $this->get_submit_button();

		if($button){
			$form->append('p', ['submit'], $button);
		}

		return $form;
	}

	protected function get_fields($output=''){
		$fields	= $this->fields;

		if($fields && is_callable($fields)){
			$fields	= wpjam_try($fields, $this->name);
		}

		$fields	= $fields ?: [];

		return $output == 'object' ? wpjam_fields($fields) : $fields;
	}

	protected function get_submit_button($name=null, $render=null){
		$render	= $render ?? is_null($name);

		if(!is_null($this->submit_text)){
			$button	= $this->submit_text;

			if($button && is_callable($button)){
				$button	= wpjam_try($button, $this->name);
			}
		}else{
			$button = wp_strip_all_tags($this->page_title);
		}

		return $this->parse_submit_button($button, $name, $render);
	}

	public function generate_data_attr($args=[], $type='button'){
		$attr	= [
			'action'	=> $this->name,
			'nonce'		=> $this->create_nonce()
		];

		if($type == 'button'){
			$args	= wp_parse_args($args, ['data'=>[]]);
			$data	= $this->data ?: [];

			return array_merge($attr, [
				'title'		=> $this->page_title ?: $this->button_text,
				'data'		=> wp_parse_args($args['data'], $data),
				'direct'	=> $this->direct,
				'confirm'	=> $this->confirm
			]);
		}

		return $attr;
	}
}

class WPJAM_Plugin_Page extends WPJAM_Register{
	protected function include(){
		if(!$this->_included){
			$this->_included	= true;

			$key	= $this->page_type.'_file';
			$file	= $this->$key ?: [];

			foreach((array)$file as $_file){
				include $_file;
			}
		}
	}

	protected function tab_load($screen){
		$tabs	= $this->tabs ?: [];
		$tabs	= is_callable($tabs) ? call_user_func($tabs, $this->name) : $tabs;
		$tabs	= apply_filters(wpjam_get_filter_name($this->name, 'tabs'), $tabs);
		
		array_walk($tabs, 'wpjam_add_tab_page');

		$current_tab	= wp_doing_ajax() ? wpjam_get_post_parameter('current_tab') : wpjam_get_parameter('tab');
		$current_tab	= sanitize_key($current_tab);

		$tabs	= [];

		foreach(WPJAM_Tab_Page::get_registereds() as $name => $tab){
			if($tab->plugin_page && $tab->plugin_page != $this->name){
				continue;
			}

			if($tab->network === false && is_network_admin()){
				continue;
			}

			if($tab->capability){
				if($tab->map_meta_cap && is_callable($tab->map_meta_cap)){
					wpjam_register_capability($tab->capability, $tab->map_meta_cap);
				}

				if(!current_user_can($tab->capability)){
					continue;
				}
			}

			if(!$current_tab){
				$current_tab	= $name;
			}

			if($tab->query_args){
				$query_data	= wpjam_generate_query_data($tab->query_args);

				if($null_queries = array_filter($query_data, 'is_null')){
					if($current_tab == $name){
						wp_die('「'.implode('」,「', array_keys($null_queries)).'」参数无法获取');
					}else{
						continue;
					}
				}else{
					if($current_tab == $name){
						$GLOBALS['current_admin_url']	= add_query_arg($query_data, $GLOBALS['current_admin_url']);
					}
				}

				$tab->query_data	= $query_data;
			}

			$tabs[$name]	= $tab;
		}

		if(!$tabs){
			throw new WPJAM_Exception('Tabs 未设置');
		}

		$this->tabs	= $tabs;

		$GLOBALS['current_tab']			= $current_tab;
		$GLOBALS['current_admin_url']	= $GLOBALS['current_admin_url'].'&tab='.$current_tab;

		$tab_object	= $tabs[$current_tab] ?? null;

		if(!$tab_object){
			throw new WPJAM_Exception('无效的 Tab');
		}elseif(!$tab_object->function){
			throw new WPJAM_Exception('Tab 未设置 function');
		}elseif(!$tab_object->function == 'tab'){
			throw new WPJAM_Exception('Tab 不能嵌套 Tab');
		}

		$tab_object->page_hook	= $this->page_hook;
		$this->tab_object		= $tab_object;

		$tab_object->load($screen);
	}

	protected function append_nav_tab($tag, $tab_object){
		$title	= $tab_object->tab_title ?: $tab_object->title;
		$url	= $this->admin_url.'&tab='.$tab_object->name;
		$class	= ['nav-tab'];

		if($this->tab_object && $this->tab_object->name == $tab_object->name){
			$class[]	= 'nav-tab-active';
		}

		if($tab_object->query_data){
			$url	= add_query_arg($tab_object->query_data, $url);
		}

		return $tag->append('a', ['class'=>$class, 'href'=>$url], $title);
	}

	public function load($screen){
		if($this->function != 'tab'){
			$page_model	= 'WPJAM_Admin_Page';
			$page_name	= null;

			if(!$this->function){
				$this->function	= wpjam_get_filter_name($this->name, 'page');
			}elseif(is_string($this->function)){
				$function	= $this->function == 'list' ? 'list_table' : $this->function;

				if(in_array($function, ['option', 'list_table', 'form', 'dashboard'])){
					$page_model	= 'WPJAM_'.ucwords($function, '_').'_Page';
					$page_name	= $this->{$function.'_name'} ?: $GLOBALS['plugin_page'];
				}
			}

			$args	= wpjam_try([$page_model, 'preprocess'], $page_name, $this);
			$args	= ($args && is_array($args)) ? wpjam_parse_data_type($args) : [];

			if($args){
				$this->update_args($args);
			}

			if($this->data_type){
				$data_type	= $this->data_type;
				$type_value	= $this->$data_type;
				$object		= wpjam_get_data_type_object($data_type);
				$meta_type	= $object ? $object->get_meta_type($args) : '';

				$screen->add_option('data_type', $data_type);

				if($meta_type){
					$screen->add_option('meta_type', $meta_type);
				}

				if(in_array($data_type, ['post_type', 'taxonomy']) && $type_value && !$screen->$data_type){
					$screen->$data_type	= $type_value;
				}
			}
		}

		do_action('wpjam_plugin_page_load', $GLOBALS['plugin_page'], $this->load_arg);

		wpjam_admin_load($GLOBALS['plugin_page'], $this->load_arg);

		// 一般 load_callback 优先于 load_file 执行
		// 如果 load_callback 不存在,尝试优先加载 load_file
		if($this->load_callback){
			$load_callback	= $this->load_callback;

			if(!is_callable($load_callback)){
				$this->include();
			}

			if(is_callable($load_callback)){
				call_user_func($load_callback, $this->name);
			}
		}

		$this->include();

		if($this->chart){
			WPJAM_Chart::init($this->chart);
		}

		if($this->editor){
			add_action('admin_footer', 'wp_enqueue_editor');
		}

		$this->set_defaults();

		try{
			if($this->function == 'tab'){
				return $this->tab_load($screen);
			}

			$object	= wpjam_try([$page_model, 'create'], $page_name, $this);

			if(wp_doing_ajax()){
				return $object->load();
			}

			add_action('load-'.$this->page_hook, [$object, 'load']);

			$this->page_object	= $object;

			if($page_name){
				$this->page_title	= $object->title ?: $this->page_title;
				$this->subtitle		= $object->get_subtitle() ?: $this->subtitle;
				$this->summary		= $this->summary ?: $object->get_summary();
				$this->query_data	= $this->query_data ?: [];
				$this->query_data	+= wpjam_generate_query_data($object->query_args);
			}
		}catch(WPJAM_Exception $e){
			wpjam_add_admin_error($e->get_wp_error());
		}
	}

	public function render(){
		$page_title	= $this->page_title ?? $this->title;
		$summary	= $this->summary;

		if($this->tab_page){
			$tag	= wpjam_tag('h2', [], $page_title.$this->subtitle);
		}else{
			$tag	= wpjam_tag('h1', ['wp-heading-inline'], $page_title)->after($this->subtitle)->after('hr', ['wp-header-end']);
		}

		if($summary){
			if(is_callable($summary)){
				$summary	= call_user_func($summary, $GLOBALS['plugin_page'], $this->load_arg);
			}elseif(is_array($summary)){
				$summ_arr	= $summary;
				$summary	= $summ_arr[0];

				if(!empty($summ_arr[1])){
					$summary	.= ',详细介绍请点击:'.wpjam_tag('a', ['href'=>$summ_arr[1], 'target'=>'_blank'], $this->menu_title);
				}
			}elseif(is_file($summary)){
				$summary	= wpjam_get_file_summary($summary);
			}
		}

		$summary	.= get_screen_option($this->page_type.'_summary');

		if($summary){
			$tag->after($summary, 'p');
		}

		if($this->function == 'tab'){
			$callback	= wpjam_get_filter_name($GLOBALS['plugin_page'], 'page');

			if(is_callable($callback)){
				$tag->after(wpjam_ob_get_contents($callback));	// 所有 Tab 页面都执行的函数
			}

			if(count($this->tabs) > 1){
				$nav	= wpjam_tag('nav', ['nav-tab-wrapper', 'wp-clearfix']);
				$tag->after($this->reduce($this->tabs, 'append_nav_tab', $nav));
			}

			if($this->tab_object){
				$tag->after($this->tab_object->render());
			}
		}else{
			$tag->after(wpjam_ob_get_contents([$this->page_object, 'render']));
		}

		if($this->tab_page){
			return $tag;
		}

		echo $tag->wrap('div', ['wrap']);
	}

	public function set_defaults($defaults=[]){
		$this->defaults	= $this->defaults ?: [];
		$this->defaults	= array_merge($this->defaults, $defaults);

		if($this->defaults){
			add_filter('wpjam_parameter_default', [$this, 'filter_parameter_default'], 10, 2);
		}
	}

	protected function preprocess_args($args){
		if(empty($args['tab_page'])){
			$args	= array_merge($args, [
				'page_type'	=> 'page',
				'load_arg'	=> '',
			]);
		}

		return parent::preprocess_args($args);
	}

	public static function get_current(){
		return self::get($GLOBALS['plugin_page']);
	}
}

class WPJAM_Tab_Page extends WPJAM_Plugin_Page{
	protected function preprocess_args($args){
		return parent::preprocess_args(array_merge($args, [
			'page_type'	=> 'tab',
			'tab_page'	=> true,
			'load_arg'	=> $this->name,
		]));
	}

	protected static function get_config($key){
		if($key == 'orderby'){
			return true;
		}elseif($key == 'model'){
			return false;
		}
	}
}

class WPJAM_Admin_Page extends WPJAM_Args{
	public function __call($method, $args){
		if($this->object && method_exists($this->object, $method)){
			return call_user_func_array([$this->object, $method], $args);
		}elseif(in_array($method, ['get_subtitle', 'get_summary'])){
			$key	= wpjam_remove_prefix($method, 'get_');

			return $this->$key;
		}
	}

	public function __get($key){
		if(empty($this->args['object']) || in_array($key, ['object', 'tab_page'])){
			return parent::__get($key);
		}else{
			return $this->object->$key;
		}
	}

	public function load(){
	}

	public function render(){
		if($this->chart){
			WPJAM_Chart::form();
		}

		if(is_callable($this->function)){
			call_user_func($this->function);
		}
	}

	public static function preprocess($name, $menu){
		return [];
	}

	public static function create($name, $menu){
		if(!is_callable($menu->function)){
			return new WP_Error('invalid_menu_page', ['函数', $menu->function]);
		}

		return new self($menu->to_array());
	}
}

class WPJAM_Form_Page extends WPJAM_Admin_Page{
	public function render(){
		try{
			echo $this->get_form();
		}catch(WPJAM_Exception $e){
			wp_die($e->get_wp_error());
		}
	}

	public static function preprocess($name, $menu){
		$object	= WPJAM_Page_Action::get($name);

		if($object){
			return $object->to_array();
		}

		if($menu->form && is_callable($menu->form)){
			$menu->form	= call_user_func($menu->form, $name);
		}

		return $menu->form;
	}

	public static function create($name, $menu){
		$object	= WPJAM_Page_Action::get($name);

		if(!$object){
			$args	= self::preprocess($name, $menu);
			$args	= $args ?: ($menu->callback ? $menu->to_array() : []);

			if(!$args){
				return new WP_Error('invalid_menu_page', ['Page Action', $name]);
			}

			$object	= WPJAM_Page_Action::register($name, $args);
		}

		return new self(array_merge($menu->to_array(), ['object'=>$object]));
	}
}

class WPJAM_Option_Page extends WPJAM_Admin_Page{
	public function __get($key){
		$value	= parent::__get($key);

		return $key == 'object' ? $value->get_current() : $value;
	}

	public function load(){
		if(wp_doing_ajax()){
			wpjam_add_admin_ajax('wpjam-option-action',	[$this, 'ajax_response']);
		}else{
			add_action('admin_action_update', [$this, 'register_settings']);

			if(isset($_POST['response_type'])) {
				$message	= $_POST['response_type'] == 'reset' ? '设置已重置。' : '设置已保存。';

				wpjam_add_admin_error($message);
			}

			$this->register_settings();
		}
	}

	public function render(){
		echo $this->render_sections($this->tab_page);
	}

	public static function preprocess($name, $menu){
		$object	= WPJAM_Option_Setting::get($name);

		if($object){
			return $object->to_array();
		}

		if($menu->option && is_callable($menu->option)){
			$menu->option	= call_user_func($menu->option, $name);
		}

		return $menu->option;
	}

	public static function create($name, $menu){
		$object	= WPJAM_Option_Setting::get($name);

		if(!$object){
			if($menu->model && method_exists($menu->model, 'register_option')){	// 舍弃 ing
				$object	= call_user_func([$menu->model, 'register_option'], $menu->delete_arg('model')->to_array());
			}else{
				$args	= self::preprocess($name, $menu);
				$args	= $args ?: (($menu->sections || $menu->fields) ? $menu->to_array() : []);

				if(!$args){
					$args	= apply_filters(wpjam_get_filter_name($name, 'setting'), []); // 舍弃 ing

					if(!$args){
						return new WP_Error('invalid_menu_page', ['Option', $name]);
					}
				}

				$object	= WPJAM_Option_Setting::create($name, $args);
			}
		}

		return new self(array_merge($menu->to_array(), ['object'=>$object]));
	}
}

class WPJAM_List_Table_Page extends WPJAM_Admin_Page{
	public function load(){
		if(wp_doing_ajax()){
			wpjam_add_admin_ajax('wpjam-list-table-action',	[$this, 'ajax_response']);
		}elseif(wpjam_get_parameter('export_action')){
			$this->export_action();
		}else{
			$result = wpjam_call([$this, 'prepare_items']);

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

	public function render(){
		$views	= wpjam_ob_get_contents([$this, 'views']);
		$form	= wpjam_ob_get_contents([$this, 'display']);

		if($this->is_searchable()){
			$form	= wpjam_ob_get_contents([$this, 'search_box'], '搜索', 'wpjam').$form;
		}

		$form	= wpjam_tag('form', ['action'=>'#', 'id'=>'list_table_form', 'method'=>'POST'], $form)->before($views);

		if($this->layout == 'left'){
			$form	= $form->wrap('div', ['list-table', 'col-wrap'])->wrap('div', ['id'=>'col-right']);
			$left	= wpjam_tag('div', ['left', 'col-wrap'], $this->get_col_left())->wrap('div', ['id'=>'col-left']);

			echo $form->before($left)->wrap('div', ['id'=>'col-container', 'class'=>'wp-clearfix']);
		}else{
			echo wpjam_tag('div', ['list-table', ($this->layout ? 'layout-'.$this->layout : '')], $form);
		}
	}

	public static function preprocess($name, $menu){
		$args	= wpjam_get_item('list_table', $name) ?: $menu->list_table;

		if($args){
			if(is_string($args) && class_exists($args) && method_exists($args, 'get_list_table')){
				$args	= [$args, 'get_list_table'];
			}

			if(is_callable($args)){
				$args	= call_user_func($args, $name);
			}

			return $menu->list_table = $args;
		}
	}

	public static function create($name, $menu){
		$args	= self::preprocess($name, $menu);

		if($args){
			if(isset($args['defaults'])){
				$menu->set_defaults($args['defaults']);
			}
		}else{
			if($menu->model){
				$args	= array_except($menu->to_array(), 'defaults');
			}else{
				$args	= apply_filters(wpjam_get_filter_name($name, 'list_table'), []);
			}

			if(!$args){
				return new WP_Error('invalid_menu_page', ['List Table', $name]);
			}
		}

		if(empty($args['model']) || !class_exists($args['model'])){
			return new WP_Error('invalid_menu_page', ['List Table 的 Model', $args['model']]);
		}

		foreach(['admin_head', 'admin_footer'] as $admin_hook){
			if(method_exists($args['model'], $admin_hook)){
				add_action($admin_hook,	[$args['model'], $admin_hook]);
			}
		}

		$args	= wp_parse_args($args, ['primary_key'=>'id', 'name'=>$name, 'singular'=>$name, 'plural'=>$name.'s', 'layout'=>'']);

		if($args['layout'] == 'left' || $args['layout'] == '2'){
			$args['layout']	= 'left';

			$object	= new WPJAM_Left_List_Table($args);
		}elseif($args['layout'] == 'calendar'){
			$args['query_args']	= $args['query_args'] ?? [];
			$args['query_args']	= array_merge($args['query_args'], ['year', 'month']);

			$object	= new WPJAM_Calendar_List_Table($args);
		}else{
			$object	= new WPJAM_List_Table($args);
		}

		return new self(array_merge($menu->to_array(), ['object'=>$object]));
	}
}

class WPJAM_Dashboard_Page extends WPJAM_Admin_Page{
	public function load(){
		require_once ABSPATH . 'wp-admin/includes/dashboard.php';
		// wp_dashboard_setup();

		wp_enqueue_script('dashboard');

		if(wp_is_mobile()){
			wp_enqueue_script('jquery-touch-punch');
		}

		$widgets	= $this->widgets ?: [];
		$widgets	= is_callable($widgets) ? call_user_func($widgets, $this->name) : $widgets;

		wpjam_dashboard_widget($this->name, $widgets);
	}

	public function render(){
		$tag	= wpjam_tag('div', ['id'=>'dashboard-widgets-wrap'], wpjam_ob_get_contents('wp_dashboard'));

		if($this->welcome_panel && is_callable($this->welcome_panel)){
			$welcome_panel	= wpjam_ob_get_contents($this->welcome_panel, $this->name);

			$tag->before('div', ['id'=>'welcome-panel', 'class'=>'welcome-panel wpjam-welcome-panel'], $welcome_panel);
		}

		echo $tag;
	}

	public static function preprocess($name, $menu){
		return wpjam_get_item('dashboard', $name) ?: $menu->dashboard;
	}

	public static function create($name, $menu){
		$args	= self::preprocess($name, $menu);
		$args	= $args ?: ($menu->widgets ? $menu->to_array() : []);

		if(!$args){
			return new WP_Error('invalid_menu_page', ['Dashboard', $name]);
		}

		return new self(array_merge($args, ['name'=>$name]));
	}
}

class WPJAM_Builtin_Page{
	protected $screen;

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

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

		if(isset($screen->$key)){
			return $screen->$key;
		}else{
			$object	= $screen->get_option('object');

			return $object ? $object->$key : null;
		}
	}

	public function __call($method, $args){
		$object	= $this->screen->get_option('object');

		if($object){
			return call_user_func_array([$object, $method], $args);
		}
	}

	public static function init($screen){
		$admin_url	= set_url_scheme('http://'.$_SERVER['HTTP_HOST'].parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));

		if($GLOBALS['plugin_page']){
			$admin_url	= add_query_arg(['page' => $GLOBALS['plugin_page']], $admin_url);
		}else{
			$args	= [];

			foreach(['taxonomy', 'post_type'] as $key){
				if($screen->$key && isset($_REQUEST[$key])){
					$args[$key]	= $_REQUEST[$key];
				}
			}

			if($args){
				$admin_url	= add_query_arg($args, $admin_url);
			}
		}

		$GLOBALS['current_admin_url']	= $admin_url;

		if(in_array($screen->base, ['edit', 'upload', 'post', 'term', 'edit-tags'])){
			if(in_array($screen->base, ['edit', 'upload', 'post'])){
				$object	= wpjam_get_post_type_object($screen->post_type);
			}elseif(in_array($screen->base, ['term', 'edit-tags'])){
				$object	= wpjam_get_taxonomy_object($screen->taxonomy);
			}

			if(!$object){
				return;
			}

			$screen->add_option('object', $object);
		}

		wpjam_add_admin_load([
			[
				'base'	=> 'post',
				'model'	=> 'WPJAM_Post_Builtin_Page'
			],
			[
				'base'	=> ['edit', 'upload'],
				'model'	=> 'WPJAM_Posts_List_Table'
			],
			[
				'base'	=> 'users',
				'model'	=> 'WPJAM_Users_List_Table'
			],
			[
				'base'	=> ['term', 'edit-tags'],
				'model'	=> 'WPJAM_Term_Builtin_Page'
			],
			[
				'base'	=> 'edit-tags',
				'model'	=> 'WPJAM_Terms_List_Table'
			],
		]);

		wpjam_admin_load($screen);
	}

	public static function load($screen){
		return new static($screen);
	}
}

class WPJAM_Post_Builtin_Page extends WPJAM_Builtin_Page{
	protected function __construct($screen){
		parent::__construct($screen);

		$edit_form_hook	= $GLOBALS['typenow'] == 'page' ? 'edit_page_form' : 'edit_form_advanced';

		add_action($edit_form_hook,			[$this, 'on_edit_form'], 99);
		add_action('add_meta_boxes',		[$this, 'on_add_meta_boxes']);
		add_action('wp_after_insert_post',	[$this, 'on_after_insert_post'], 999, 2);

		add_filter('post_updated_messages',		[$this, 'filter_updated_messages']);
		add_filter('redirect_post_location',	[$this, 'filter_redirect_location']);
		add_filter('admin_post_thumbnail_html',	[$this, 'filter_admin_thumbnail_html']);
	}

	public function on_edit_form($post){	// 下面代码 copy 自 do_meta_boxes
		$meta_boxes		= $GLOBALS['wp_meta_boxes'][$this->id]['wpjam'] ?? [];
		$tab_title		= wpjam_tag('ul');
		$tab_content	= wpjam_tag('div', ['inside']);
		$tab_count		= 0;

		foreach(wp_array_slice_assoc($meta_boxes, ['high', 'core', 'default', 'low']) as $_meta_boxes){
			foreach((array)$_meta_boxes as $meta_box){
				if(empty($meta_box['id']) || empty($meta_box['title'])){
					continue;
				}

				$tab_count++;

				$meta_id	= 'tab_'.$meta_box['id'];

				$tab_title->append('li', [], wpjam_tag('a', ['class'=>'nav-tab', 'href'=>'#'.$meta_id], $meta_box['title']));
				$tab_content->append('div', ['id'=>$meta_id], wpjam_ob_get_contents($meta_box['callback'], $post, $meta_box));
			}
		}

		if(!$tab_count){
			return;
		}

		if($tab_count == 1){
			$tab_title	= wpjam_tag('h2', ['hndle'], strip_tags($tab_title))->wrap('div', ['postbox-header']);
		}else{
			$tab_title->wrap('h2', ['nav-tab-wrapper']);
		}

		echo $tab_title->after($tab_content)->wrap('div', ['id'=>'wpjam', 'class'=>['postbox','tabs']])->wrap('div', ['id'=>'wpjam-sortables']);
	}

	public function meta_box_cb($post, $meta_box){
		$object	= array_shift($meta_box['args']);
		$id		= $GLOBALS['current_screen']->action == 'add' ? false : $post->ID;
		$type	= $object->context == 'side' ? 'list' : 'table';

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

		$object->render($id, ['fields_type'=>$type]);
	}

	public function on_add_meta_boxes($post_type){
		$context	= use_block_editor_for_post_type($post_type) ? 'normal' : 'wpjam';

		foreach(wpjam_get_post_options($post_type, ['list_table'=>false]) as $object){
			$context	= $object->context ?: $context;
			$callback	= $object->meta_box_cb ?: [$this, 'meta_box_cb'];

			add_meta_box($object->name, $object->title, $callback, $post_type, $context, $object->priority, [$object]);
		}
	}

	public function on_after_insert_post($post_id, $post){
		// 只有 POST 方法提交才处理,自动草稿、自动保存和预览情况下不处理
		if($_SERVER['REQUEST_METHOD'] != 'POST'
			|| $post->post_status == 'auto-draft'
			|| (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
			|| (!empty($_POST['wp-preview']) && $_POST['wp-preview'] == 'dopreview')
		){
			return;
		}

		foreach(wpjam_get_post_options($this->post_type, ['list_table'=>false]) as $object){
			$result	= $object->callback($post_id);

			wpjam_die_if_error($result);
		}
	}

	public function filter_updated_messages($messages){
		$key	= $this->hierarchical ? 'page' : 'post';

		if(isset($messages[$key])){
			$search		= $key == 'post' ? '文章':'页面';
			$replace	= $this->labels->name;

			foreach($messages[$key] as &$message){
				$message	= str_replace($search, $replace, $message);
			}
		}

		return $messages;
	}

	public function filter_admin_thumbnail_html($content){
		$size	= $this->thumbnail_size;

		return $content.($size ? wpautop('尺寸:'.$size) : '');
	}

	public function filter_redirect_location($location){
		if(parse_url($location, PHP_URL_FRAGMENT)){
			return $location;
		}

		if($fragment = parse_url(wp_get_referer(), PHP_URL_FRAGMENT)){
			return $location.'#'.$fragment;
		}

		return $location;
	}
}

class WPJAM_Term_Builtin_Page extends WPJAM_Builtin_Page{
	protected function __construct($screen){
		parent::__construct($screen);

		add_filter('term_updated_messages',	[$this, 'filter_updated_messages']);

		if($this->base == 'edit-tags'){
			if(wp_doing_ajax()){
				if($_POST['action'] == 'add-tag'){
					add_filter('pre_insert_term',	[$this, 'filter_pre_insert'], 10, 2);
					add_action('created_term',		[$this, 'on_created'], 10, 3);
				}
			}else{
				add_action('edited_term',	[$this, 'on_edited'], 10, 3);
			}

			add_action($GLOBALS['taxnow'].'_add_form_fields',	[$this, 'on_add_form_fields']);
		}else{
			add_action($GLOBALS['taxnow'].'_edit_form_fields',	[$this, 'on_edit_form_fields']);
		}
	}

	public function get_form_fields($action, $args){
		foreach(wpjam_get_term_options($this->taxonomy, ['action'=>$action, 'list_table'=>false]) as $object){
			$object->render($args['id'], wp_parse_args($args, $object->to_array()));
		}
	}

	protected function update_data($action, $term_id=null){
		foreach(wpjam_get_term_options($this->taxonomy, ['action'=>$action, 'list_table'=>false]) as $object){
			$result	= $term_id ? $object->callback($term_id) : $object->validate();

			wpjam_die_if_error($result);
		}

		return true;
	}

	public function on_add_form_fields($taxonomy){
		$this->get_form_fields('add', [
			'fields_type'	=> 'div',
			'wrap_class'	=> 'form-field',
			'id'			=> false,
		]);
	}

	public function on_edit_form_fields($term){
		$this->get_form_fields('edit', [
			'fields_type'	=> 'tr',
			'wrap_class'	=> 'form-field',
			'id'			=> $term->term_id,
		]);
	}

	public function on_created($term_id, $tt_id, $taxonomy){
		if($taxonomy == $this->taxonomy){
			$this->update_data('add', $term_id);
		}
	}

	public function on_edited($term_id, $tt_id, $taxonomy){
		if($taxonomy == $this->taxonomy){
			$list_table	= wpjam_get_builtin_list_table('WP_Terms_List_Table');

			if($list_table->current_action() == 'editedtag'){
				$this->update_data('edit', $term_id);
			}
		}
	}

	public function filter_pre_insert($term, $taxonomy){
		if($taxonomy == $this->taxonomy){
			$this->update_data('add');
		}

		return $term;
	}

	public function filter_updated_messages($messages){
		if(!in_array($this->taxonomy, ['post_tag', 'category'])){
			$label	= $this->labels->name;

			foreach($messages['_item'] as $key => $message){
				$messages[$this->taxonomy][$key]	= str_replace(['项目', 'Item'], [$label, ucfirst($label)], $message);
			}
		}

		return $messages;
	}
}

class WPJAM_Chart{
	private static $parameters	= [];
	private static $args		= [ 
		'show_form'			=> true,
		'show_date_type'	=> false,
		'show_compare'		=> false,
		'show_start_date'	=> true
	];

	private static $enqueued	= false;

	public static function line($counts_array, $labels, $args=[], $type='Line'){
		if(!$counts_array){
			return;
		}

		self::enqueue_script();

		global $current_admin_url;
		
		$args	= wp_parse_args($args, [
			'chart_id'		=>'daily-chart',
			'day_label'		=>'时间',
			'day_key'		=>'day',
			'day_labels'	=>[],
			'total_link'	=>$current_admin_url,
			'show_link'		=>false,
			'show_table'	=>true, 
			'show_chart'	=>true, 
			'show_sum'		=>true,
			'show_avg'		=>true,
		]);

		$day_labels	= $args['day_labels'];
		$day_label	= $args['day_label'];
		$day_key	= $args['day_key'];

		if($args['show_chart']){
			$morris_datas	= $morris_data = [];
			$labels2		= $labels;

			foreach ($labels as $key => $value) {
				if(strpos($value,'%') === false && strpos($value,'#') === false){ // %,# 数据不写入图
					$labels2[$key]		= $value;
					$morris_ykeys[]		= $key;
					$morris_labels[]	= $value;
				}
			}

			$data	= [];

			foreach ($counts_array as $day => $counts) {
				if(strpos($day,'%') === false && strpos($day,'#') === false){
					$counts	= (array)$counts;
					$day	= ($day_labels && isset($day_labels[$day])) ? $day_labels[$day] : $day;
					$item 	= [];

					$item[$day_key]	= $day;

					foreach($morris_ykeys as $morris_ykey){
						$item[$morris_ykey]	= $counts[$morris_ykey] ?? 0;
					}

					$data[]	= $item;	
				}
			}

			$morris	= [
				'element'	=> $args['chart_id'],
				'data'		=> $data,
				'xkey'		=> $day_key,
				'ykeys'		=> $morris_ykeys,
				'labels'	=> $morris_labels,
			];

			echo '<div id="'.$args['chart_id'].'"></div>';
			echo '
			<script type="text/javascript">
			jQuery(function($){
				Morris.'.$type.'('.wpjam_json_encode($morris).');
			});
			</script>
			';
		}

		if($args['show_table']){ 
			$totol_array	= []; 
			$toggle_row		= '<button type="button" class="toggle-row"><span class="screen-reader-text">显示详情</span></button>';
			
			echo '<table class="wp-list-table widefat striped" cellspacing="0">';
			echo '<thead>';
			echo '<tr>';
			echo '<th scope="col" id="'.$day_key.'" class="column-'.$day_key.' column-primary">'.$day_label.'</th>';

			foreach ($labels as $morris_ykey => $morris_label) { 
				if(strpos($labels[$morris_ykey], '%')===false && strpos($labels[$morris_ykey], '#')===false){
					$totol_array[$morris_ykey]	= 0;
				}

				echo '<th  scope="col" id="'.$morris_ykey.'" class="column-'.$morris_ykey.'">'.$morris_label.'</th>';
			}

			echo '</tr>';
			echo '</thead>';
			echo '<tbody>';

			foreach ($counts_array as $day=>$counts) {
				$counts		= (array)$counts;
				$day_value	= ($day_labels && isset($day_labels[$day]))?$day_labels[$day]:$day;

				if($args['show_link']){
					$day_value	= '<a href="'.$args['total_link'].'&'.$day_key.'='.$day.'">'.$day_value.'</a>';
				}

				echo '<tr>';	
				echo '<td class="column-'.$day_key.' column-primary" data-colname="'.$day_label.'">'.$day_value.$toggle_row.'</td>';
				
				foreach($labels as $morris_ykey => $morris_label){ 
					$count	= $counts[$morris_ykey] ?? 0; 
						
					if(isset($totol_array[$morris_ykey])){
						$totol_array[$morris_ykey] += $count;
					}

					echo '<td class="column-'.$morris_ykey.'" data-colname="'.$morris_label.'">'.$count.'</td>';
				}
				echo '</tr>';
			}

			if(count($counts_array) > 1){

				if($args['show_sum']){
					echo '<tr>';
					echo '<td class="column-'.$day_key.' column-primary" data-colname="'.$day_label.'">累加'.$toggle_row.'</td>';

					foreach($labels as $morris_ykey => $morris_label){
						echo '<td class="column-'.$morris_ykey.'" data-colname="'.$morris_label.'">';

						if(isset($totol_array[$morris_ykey])){
							echo $totol_array[$morris_ykey];
						}

						echo '</td>';
					}
					echo '</tr>';
				}

				if($args['show_avg']){
					echo '<tr>';
					echo '<td class="column-'.$day_key.' column-primary" data-colname="'.$day_label.'">平均'.$toggle_row.'</td>';

					$number	= count($counts_array);

					foreach($labels as $morris_ykey => $morris_label){
						echo '<td class="column-'.$morris_ykey.'" data-colname="'.$morris_label.'">';

						if(isset($totol_array[$morris_ykey])){
							echo round($totol_array[$morris_ykey]/$number);
						}

						echo '</td>';
					}
					echo '</tr>';
				}
			}

			echo '</tbody>';
			echo '</table>';
		}
	}

	public static function donut($counts, $args=[]){
		if(!$counts){
			return;
		}

		self::enqueue_script();

		global $current_admin_url;

		$args	= wp_parse_args($args, [
			'chart_id'		=>'',
			'total'			=>0,
			'title'			=>'名称',
			'key'			=>'type',
			'show_link'		=>false,
			'total_link'	=>$current_admin_url,
			'table_width'	=>'300',
			'chart_width'	=>'240', 
			'show_line_num'	=>false,
			'labels'		=>[]
		]);

		if($args['chart_id']){
			$chart_id	= $args['chart_id'];
		}else{
			static $chart_count;
			if(empty($chart_count)){
				$chart_count = 1;
			}else{
				$chart_count ++;
			}

			$chart_id	= 'chart_'.$chart_count;
		}

		$labels	= $args['labels'];

		echo '<div style="display:table; margin-bottom:20px;">';
		echo '<div style="display: table-row;">';
		echo '<div style="display: '.($args['table_width'] ? 'table-cell' : 'none').'; float:left; width:'.$args['table_width'].'px; margin-right:20px;">';
		echo '<table class="wp-list-table widefat striped" cellspacing="0">';
		echo '<thead>';
		echo '<tr>';
		
		if($args['show_line_num']){
			echo '<th style="width:40px;">排名</th>';
		}

		echo '<th>'.$args['title'].'</th>';
		echo '<th style="width:25%;">数量</th>';
		
		if($args['total']){
			echo '<th style="width:25%;">比例</th>';
		}

		echo '</tr>';
		echo '</thead>';
		echo '<tbody>';

		$data	= [];
		$i		= 0;

		foreach ($counts as $count) { 
			$i++; 

			$count	= (array)$count;
			$label 	= $count['label'] ?? '/';
			$link	= $count['link'] ?? '';

			$link	= '';

			if($args['show_link']){
				$value	= $count[$args['key']] ?? $label;
				$link	= $args['total_link'].'&'.$args['key'].'='.$value;
			}

			$label 	= ($labels && isset($labels[$label])) ? $labels[$label] : $label;
			$count 	= $count['count'];

			if($i<=30){
				$data[]= ['label'=>$label, 'value'=>$count];
			}

			echo '<tr>';

			if($args['show_line_num']){
				echo '<td>'.$i.'</td>'; 
			} 

			echo '<td>'.($link ? '<a href="'.$link.'">'.$label.'</a>' : $label).'</td>';
			echo '<td>'.$count.'</td>';

			if($args['total']){
				echo '<td>'.round($count/$args['total']*100,2).'%'.'</td>';
			}

			echo '</tr>';
		}

		if($args['total']){
			echo '<tr>';

			if($args['show_line_num']){
				echo '<td> </td>'; 
			}

			echo '<td>'.($args['show_link'] ? '<a href="'.$args['total_link'].'">所有</a>' : '所有').'</td>';
			echo '<td>'.$args['total'].'</td>';

			if($args['total']){
				echo '<td>100%</td>';
			}

			echo '</tr>';
		}
		
		echo '</tbody>';
		echo '</table>';
		echo '</div>';

		$morris	= ['element'=>$chart_id, 'data'=>$data];

		if($args['chart_width']){
			echo '<div id="'.$chart_id.'" style="display: table-cell; width:'.$args['chart_width'].'px; height:'.$args['chart_width'].'px; float:left;"></div>';

			echo '
			<script type="text/javascript">
			jQuery(function($){
				Morris.Donut('.wpjam_json_encode($morris).');
			});
			</script>
			';
		}

		echo '</div>';
		echo '</div>';
	}

	public static function init($args=[]){
		if(self::$parameters){
			return;
		}

		$args	= is_array($args) ? $args : [];

		self::$args	= wp_parse_args($args, self::$args);

		if(!self::$args['show_form']){
			return;
		}
		
		$offset	= (int)get_option('gmt_offset');
		$offset	= $offset >= 0 ? '+'.$offset.':00' : $offset.':00';
		
		$GLOBALS['wpdb']->query("SET time_zone = '{$offset}';");

		if(self::$args['show_start_date']){
			self::set_parameter('start_date',	wpjam_date('Y-m-d', time() - DAY_IN_SECONDS*30));
			self::set_parameter('end_date',		wpjam_date('Y-m-d', time()));

			if(self::$args['show_compare']){
				$time_diff	= self::get_parameter('end_timestamp') - self::get_parameter('start_timestamp');

				self::set_parameter('start_date_2',	date('Y-m-d', self::get_parameter('start_timestamp') - DAY_IN_SECONDS - $time_diff));
				self::set_parameter('end_date_2',	date('Y-m-d', self::get_parameter('start_timestamp') - DAY_IN_SECONDS));
				
				self::set_parameter('compare',		0);
			}
		}else{
			self::set_parameter('date',	wpjam_date('Y-m-d', time() - DAY_IN_SECONDS));
		}

		if(self::$args['show_date_type']){
			self::set_parameter('date_type', '按天');
		}
	}

	public static function get_parameter($key){
		if($key == 'start_timestamp'){
			return wpjam_strtotime(self::get_parameter('start_date').' 00:00:00');
		}elseif($key == 'timestamp'){
			return wpjam_strtotime(self::get_parameter('date').' 00:00:00');
		}elseif($key == 'end_timestamp'){
			return wpjam_strtotime(self::get_parameter('end_date').' 23:59:59');
		}elseif($key == 'start_timestamp_2'){
			return wpjam_strtotime(self::get_parameter('start_date_2').' 00:00:00');
		}elseif($key == 'end_timestamp_2'){
			return wpjam_strtotime(self::get_parameter('end_date_2').' 23:59:59');
		}elseif($key == 'date_format'){
			$date_type		= self::get_parameter('date_type');
			$date_type		= $date_type =='显示' ? '按天' : $date_type;

			$date_formats	= self::get_date_formats();

			return $date_formats[$date_type] ?? '%Y-%m-%d';
		}elseif($key == 'date_type'){
			if(self::$args['show_date_type']){
				return self::$parameters[$key] ?? '按天';
			}else{
				return '按天';
			}
		}else{
			return self::$parameters[$key] ?? '';
		}
	}

	public static function set_parameter($key, $default){
		if($value = wpjam_get_parameter($key, ['method'=>'POST'])){
			self::$parameters[$key]	= $value;
			wpjam_set_cookie($key, $value, HOUR_IN_SECONDS);
		}elseif(isset($_COOKIE[$key])) {
			self::$parameters[$key]	= wp_unslash($_COOKIE[$key]);
		}else{
			self::$parameters[$key]	= $default;
		}
	}

	public static function form(){
		global $current_admin_url;

		if(!self::$args['show_form']){
			return;
		}

		$current_type	= $_GET['type'] ?? '-1';
		$current_type	= $current_type == 'all' ? '-1' : $current_type;
		$action 		= $current_type == -1 ? $current_admin_url : $current_admin_url.'&type='.$current_type;

		$fields	= [];

		if(self::$args['show_start_date']){
			$fields['start_date']	= ['type'=>'date',	'before'=>'日期: ',	'value'=>self::get_parameter('start_date')];
			$fields['end_date']		= ['type'=>'date',	'before'=>'-',	'after'=>' ',	'value'=>self::get_parameter('end_date')];
		}else{
			$fields['date']			= ['type'=>'date',	'after'=>' ',	'value'=>self::get_parameter('date')];
		}

		if(self::$args['show_date_type']){
			foreach (self::get_date_formats(self::$args['show_date_type']) as $date_type => $date_format) { 
				$class	= self::get_parameter('date_type') == $date_type ? 'button button-primary' : 'button';
				$fields['date_type_'.$date_type]	= ['type'=>'submit',	'name'=>'date_type',	'afteer'=>' ',	'value'=>$date_type,	'class'=>$class];
			}
		}else{
			$fields['date_type']	= ['type'=>'submit', 'name'=>'date_type', 'after'=>' ', 'value'=>'显示',	'class'=>'button button-secondary'];
		}

		if($current_type !=-1 && self::$args['show_start_date'] && self::$args['show_compare']){
			$fields['start_date_2']	= ['type'=>'date',		'before'=>'对比: ',	'after'=>' ',	'value'=>self::get_parameter('start_date_2')];
			$fields['end_date_2']	= ['type'=>'date',		'after'=>' ',	'value'=>self::get_parameter('end_date_2')];
			$fields['compare']		= ['type'=>'checkbox',	'after'=>' ',	'value'=>self::get_parameter('compare')];
		}

		$fields	= apply_filters('wpjam_chart_fields', $fields);

		echo '<div style="margin:20px 0;">';
		echo '<form method="POST" action="'.$action.'" target="_self">';
		echo wpjam_fields($fields)->render(['fields_type'=>'']);
		echo '</form>';
		echo '</div>';
		echo '<div class="clear"></div>';
	}

	public static function get_date_formats($filter=1){
		if($filter == 1 || is_array($filter)){
			$date_formats	= [
				'按分钟'	=> '%Y-%m-%d %H:%i',
				'按小时'	=> '%Y-%m-%d %H:00',
				'按天'	=> '%Y-%m-%d',
				'按周'	=> '%Y%U',
				'按月'	=> '%Y-%m'
			];

			if(is_array($filter)){
				return wp_array_slice_assoc($date_formats, $filter);
			}else{
				return $date_formats;
			}
		}elseif($filter == 2){
			return [
				'按天'	=> '%Y-%m-%d',
				'按周'	=> '%Y%U',
				'按月'	=> '%Y-%m'
			];
		}
	}

	public static function enqueue_script(){
		if(self::$enqueued){
			return;
		}

		self::$enqueued	= true;

		wp_enqueue_style('morris',		'https://cdn.staticfile.org/morris.js/0.5.1/morris.css');
		wp_enqueue_script('raphael',	'https://cdn.staticfile.org/raphael/2.3.0/raphael.min.js');
		wp_enqueue_script('morris',		'https://cdn.staticfile.org/morris.js/0.5.1/morris.min.js', ['raphael']);
	}
}