Plugin Directory

Changeset 3427357


Ignore:
Timestamp:
12/25/2025 03:32:07 PM (3 months ago)
Author:
denishua
Message:

version 6.9

Location:
wpjam-basic/trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • wpjam-basic/trunk/components/server-status.php

    r3356207 r3427357  
    240240                'direct'        => true,
    241241                'confirm'       => true,
    242                 'callback'      => fn() => opcache_reset() ? ['errmsg'=>'缓存重置成功'] : wp_die('缓存重置失败')
     242                'callback'      => fn() => opcache_reset() ? ['notice'=>'缓存重置成功'] : wp_die('缓存重置失败')
    243243            ]);
    244244        }
     
    257257                'direct'        => true,
    258258                'confirm'       => true,
    259                 'callback'      => fn() => wp_cache_flush() ? ['errmsg'=>'缓存刷新成功'] : wp_die('缓存刷新失败')
     259                'callback'      => fn() => wp_cache_flush() ? ['notice'=>'缓存刷新成功'] : wp_die('缓存刷新失败')
    260260            ]);
    261261        }
  • wpjam-basic/trunk/extends/baidu-zz.php

    r3344768 r3427357  
    104104
    105105        if(time() - (int)self::get_setting('baidu_zz_last') < DAY_IN_SECONDS){
    106             return $submited == -1 ? ['notice_type'=>'info', 'errmsg'=>'所有页面都已提交'] : wp_die('批量提交的配额已用完,请稍后重试');
     106            return $submited == -1 ? ['notice'=>'所有页面都已提交'] : wp_die('批量提交的配额已用完,请稍后重试');
    107107        }
    108108
     
    143143
    144144            return [
    145                 'notice_type'   => 'success',
    146                 'errmsg'        => '提交成功,本次提交了'.$number.'个页面。',
     145                'notice'    => '提交成功,本次提交了'.$number.'个页面。',
    147146            ];
    148147        }else{
    149148            return [
    150                 'done'          => 0,
    151                 'errmsg'        => '批量提交中,请勿关闭浏览器,本次提交了'.$number.'个页面。',
    152                 'notice_type'   => 'info',
    153                 'args'          => http_build_query(['offset'=>$number])
     149                'notice'    => ['type'=>'info', 'message'=>'批量提交中,请勿关闭浏览器,本次提交了'.$number.'个页面。'],
     150                'args'      => ['offset'=>$number]
    154151            ];
    155152        }
  • wpjam-basic/trunk/extends/bing-webmaster.php

    r3344768 r3427357  
    119119        if(time() - (int)self::get_setting('last') < DAY_IN_SECONDS){
    120120            if($submited == -1){
    121                 return ['notice_type'=>'info', 'errmsg'=>'所有页面都已提交'];
     121                return ['notice'=>'所有页面都已提交'];
    122122            }else{
    123123                wp_die('批量提交的配额已用完,请稍后重试');
     
    163163            self::update_setting('submited', -1);
    164164
    165             return [
    166                 'notice_type'   => 'success',
    167                 'errmsg'        => '提交成功,本次提交了'.$number.'个页面。',
    168             ];
     165            return ['notice'    => '提交成功,本次提交了'.$number.'个页面。'];
    169166        }else{
    170167            return [
    171                 'done'          => 0,
    172                 'errmsg'        => '批量提交中,请勿关闭浏览器,本次提交了'.$number.'个页面。',
    173                 'notice_type'   => 'info',
    174                 'args'          => http_build_query(['offset'=>$number])
     168                'notice'    => ['type'=>'info', 'message'=>'批量提交中,请勿关闭浏览器,本次提交了'.$number.'个页面。'],
     169                'args'      => ['offset'=>$number]
    175170            ];
    176171        }
  • wpjam-basic/trunk/extends/post-type-switcher.php

    r3255446 r3427357  
    2929            }
    3030
    31             return ['errmsg'=>'未修改文章类型'];
     31            return ['notice'=>'未修改文章类型'];
    3232        }
    3333
  • wpjam-basic/trunk/includes/class-wpjam-admin.php

    r3423058 r3427357  
    99    }
    1010
     11    public function error($msg='', $type='success'){
     12        if($msg === ''){
     13            return wpjam_map($this->error ?: [], fn($e)=> wpjam_echo(wpjam_tag('div', ['is-dismissible', 'notice', 'notice-'.$e['type']], ['p', [], $e['msg']]))); 
     14        }
     15
     16        if(is_wp_error($msg)){
     17            $msg    = $msg->get_error_message();
     18            $type   = 'error';
     19        }
     20
     21        $msg && $type && $this->update_arg('error[]', compact('msg', 'type'));
     22    }
     23
     24    public function can($capability, ...$args){
     25        return ($capability = maybe_closure($capability, ...$args)) ? current_user_can($capability, ...$args) : true;
     26    }
     27
     28    public function button($button, $key=null, $render=null){
     29        if(wp_is_numeric_array($button)){
     30            $button = is_array($button[0]) ? $button[0] : [$button[1] => $button[0]];
     31            $button = $key ? ($button[$key] ?? wp_die('无效的提交按钮')) : $button;
     32        }
     33
     34        if($key){
     35            $button = is_array($button) ? $button : ['text'=>$button];
     36
     37            if($render){
     38                return get_submit_button($button['text'], $button['class'] ?? 'primary', $key, false);
     39            }
     40        }else{
     41            $render ??= true;
     42            $button = wpjam_map(array_filter($button), fn($v, $k)=> $this->button($v, $k, $render));
     43
     44            if($render){
     45                return $button ? wpjam_tag('p', ['submit'], implode($button)) : wpjam_tag();
     46            }
     47        }
     48
     49        return $button;
     50    }
     51
     52    public function notice(&$data, $default=''){
     53        if(is_array($data)){
     54            if(!empty($data['errcode']) && !empty($data['errmsg'])){
     55                return wpjam_pull($data, ['errcode', 'errmsg']);
     56            }
     57
     58            $notice = wpjam_pull($data, 'notice');
     59            $errmsg = wpjam_pull($data, 'errmsg');
     60        }
     61
     62        if(empty($notice)){
     63            $notice = !empty($errmsg) && $errmsg != 'ok' ? $errmsg : $default;  // 第三方接口可能返回 ok
     64        }
     65
     66        return ['notice'=>$notice];
     67    }
     68
    1169    public function chart($method, ...$args){
    1270        if(is_object($method)){
     
    2179        $static = wpjam_url(dirname(__DIR__), 'relative').'/static';
    2280
    23         wp_enqueue_media($this->screen->base == 'post' ? ['post'=>wpjam_get_admin_post_id()] : []);
     81        wp_enqueue_media(wpjam_pick($this, ['post_id']));
    2482        wp_enqueue_style('wpjam-style', $static.'/style.css', ['thickbox', 'wp-color-picker', 'editor-buttons'], $ver);
    2583        wp_enqueue_script('wpjam-script', $static.'/script.js', ['jquery', 'thickbox', 'wp-color-picker', 'jquery-ui-sortable', 'jquery-ui-tabs', 'jquery-ui-draggable', 'jquery-ui-autocomplete'], $ver);
     
    3189    }
    3290
    33     public function notices(){
    34         WPJAM_Notice::render();
    35 
    36         wpjam_map($this->get_arg('error[]'), fn($e)=> wpjam_echo(wpjam_tag('div', ['is-dismissible', 'notice', 'notice-'.$e['type']], ['p', [], $e['msg']])));
    37     }
    38 
    3991    public function load($screen=''){
    4092        if($screen){
     93            if($screen->base == 'post'){
     94                $this->post_id  = (int)($_GET['post'] ?? ($_POST['post_ID'] ?? 0));
     95            }
     96
    4197            $this->screen   = $screen;
    4298            $this->vars     = ['screen_id'=>$screen->id]+array_filter(wpjam_pick($screen, ['post_type', 'taxonomy']));
     
    116172        }
    117173
    118         wpjam_trap($this->plugin_page ? [$object, 'load'] : 'WPJAM_Builtin_Page::load', $screen, fn($e)=> wpjam_add_admin_error($e));
     174        wpjam_trap($this->plugin_page ? [$object, 'load'] : 'WPJAM_Builtin_Page::load', $screen, fn($e)=> $this->error($e));
    119175
    120176        add_action('admin_enqueue_scripts', [$this, 'enqueue'], 9);
    121         add_action('all_admin_notices',     [$this, 'notices'], 9);
     177        add_action('all_admin_notices',     [$this, 'error'], 9);
    122178    }
    123179
     
    134190            }
    135191
    136             wpjam_add_admin_ajax('wpjam-page-action', [
     192            wpjam_ajax('wpjam-page-action', [
     193                'admin'         => true,
    137194                'nonce_action'  => fn($data)=> $data['page_action'] ?? '',
    138195                'callback'      => fn($data)=> ($object = WPJAM_Page_Action::get($data['page_action'] ?? '')) ? $object($data['action_type']) : wpjam_page_action_compat($data),
    139196            ]);
    140197
    141             wpjam_add_admin_ajax('wpjam-query', [
     198            wpjam_ajax('wpjam-query', [
     199                'admin'     => true,
    142200                'fields'    => ['data_type'=> ['required'=>true]],
    143201                'callback'  => fn($data)=> ['items'=>($cb = [WPJAM_Data_Type::get_instance($data['data_type'], $data['query_args']), 'query_items'])[0] ? wpjam_try($cb, $data['query_args']) : []]
    144202            ]);
    145203
    146             wpjam_add_admin_ajax('wpjam-upload', [
     204            wpjam_ajax('wpjam-upload', [
     205                'admin'         => true,
    147206                'nonce_action'  => fn($data)=> 'upload-'.$data['name'],
    148207                'callback'      => fn($data)=> wpjam_upload($data['name'], ['mimes'=>$data['mimes']])
     
    220279        $type   = $button['response'] ?? ($this->response ?? $this->name);
    221280        $result = wpjam_try($cb ?: wp_die('无效的回调函数'), ...$args) ?? wp_die('回调函数没有正确返回');
    222         $result = (is_array($result) ? $result : (is_string($result) ? [($type == 'redirect' ? 'url' : 'data') => $result] : []))+['type'=>$type];
    223         $result += ($this->dismiss ? ['dismiss'=>true] : [])+($result['type'] == 'redirect' ? ['target'=>$this->target ?: '_self'] : []);
     281        $result = is_array($result) ? wpjam_admin('notice', $result)+$result : (is_string($result) ? [($type == 'redirect' ? 'url' : 'data') => $result] : []);
     282        $result += ['type'=>$type]+($this->dismiss ? ['dismiss'=>true] : []);
     283        $result += $result['type'] == 'redirect' ? ['target'=>$this->target ?: '_self'] : [];
    224284
    225285        return apply_filters('wpjam_ajax_response', $result);
     
    227287
    228288    public function is_allowed($type=''){
    229         return wpjam_current_user_can(($this->capability ?? ($type ? 'manage_options' : '')), $this->name);
     289        return wpjam_admin('can', ($this->capability ?? ($type ? 'manage_options' : '')), $this->name);
    230290    }
    231291
     
    235295
    236296    public function button($name=null){
    237         return wpjam_button([maybe_callback($this->submit_text, $this->name) ?? wp_strip_all_tags($this->page_title), $this->name], $name);
     297        return wpjam_admin('button', [maybe_callback($this->submit_text, $this->name) ?? wp_strip_all_tags($this->page_title), $this->name], $name);
    238298    }
    239299
  • wpjam-basic/trunk/includes/class-wpjam-api.php

    r3423058 r3427357  
    1010        }
    1111
    12         return wpjam_call(is_closure($cb) ? wpjam_bind($cb, $this) : $cb, ...$args);
     12        return wpjam_call(wpjam_bind($cb, $this), ...$args);
    1313    }
    1414
     
    122122
    123123    protected function prepare_item($item, $key, $action, $field=''){
    124         $field  = $this->get_items_field();
     124        $field  = $field ?: $this->get_items_field();
    125125        $items  = $this->get_items($field);
    126126        $add    = $action == 'add';
     
    760760        return [
    761761            'type'      => (!$this->ajax || $submit == 'reset') ? 'redirect' : $submit,
    762             'errmsg'    => $submit == 'reset' ? '设置已重置。' : '设置已保存。'
     762            'notice'    => $submit == 'reset' ? '设置已重置。' : '设置已保存。'
    763763        ];
    764764    }
     
    947947
    948948    public function page_load(){
    949         wpjam_add_admin_ajax('wpjam-option-action', [
     949        wpjam_ajax('wpjam-option-action',   [
     950            'admin'         => true,
    950951            'callback'      => $this,
    951952            'nonce_action'  => fn()=> $this->option_group,
  • wpjam-basic/trunk/includes/class-wpjam-field.php

    r3423058 r3427357  
    3030        }
    3131
    32         $key    = $args[0];
    33         $args[0]= is_array($key) ? wpjam_array($key, fn($k)=> 'data-'.$k) : 'data-'.$key;
    34 
    35         return $this->attr(...$args) ?? (wpjam_array($this->data)[$key] ?? null);
     32        $args[0]    = is_array($args[0]) ? wpjam_array($args[0], fn($k)=> 'data-'.$k) : 'data-'.$args[0];
     33
     34        return $this->attr(...$args) ?? (wpjam_array($this->data)[$args[0]] ?? null);
    3635    }
    3736
     
    101100    }
    102101
    103     public static function accept_to_mime_types($accept){
    104         if($accept){
    105             $allowed    = get_allowed_mime_types();
    106             $types      = [];
    107 
    108             foreach(wpjam_lines($accept, ',', fn($v)=> strtolower($v)) as $v){
    109                 if(str_ends_with($v, '/*')){
    110                     $prefix = substr($v, 0, -1);
    111                     $types  += array_filter($allowed, fn($m)=> str_starts_with($m, $prefix));
    112                 }elseif(str_contains($v, '/')){
    113                     $ext    = array_search($v, $allowed);
    114                     $types  += $ext ? [$ext => $v] : [];
    115                 }elseif(($v = ltrim($v, '.')) && preg_match('/^[a-z0-9]+$/', $v)){
    116                     $ext    = array_find_key($allowed, fn($m, $ext)=> str_contains($ext, '|') ? in_array($v, explode('|', $ext)) : $v == $ext);
    117                     $types  += $ext ? wpjam_pick($allowed, [$ext]) : [];
    118                 }
    119             }
    120 
    121             return $types;
    122         }
    123     }
    124 
    125102    public static function parse($attr){
    126103        return wpjam_array($attr, function($k, $v){
     
    170147                $this->$key = in_array($key, ['_before', '_prepend']) ? [$value, ...$this->$key] : [...$this->$key, $value];
    171148            }
    172 
    173             return $this;
    174149        }elseif(in_array($method, ['insert_before', 'insert_after', 'append_to', 'prepend_to'])){
    175150            $args[0]->{str_replace(['insert_', '_to'], '', $method)}($this);
    176 
    177             return $this;
    178         }
    179 
    180         trigger_error($method);
     151        }else{
     152            trigger_error($method);
     153        }
     154
     155        return $this;
    181156    }
    182157
     
    305280
    306281    public function schema(...$args){
    307         if($args && in_array($args[0], ['validate', 'sanitize', 'prepare'])){
    308             if($schema  = $this->schema()){
    309                 if($schema['type'] == 'string'){
    310                     if($args[0] == 'validate'){
    311                         $this->pattern && !rest_validate_json_schema_pattern($this->pattern, $args[1]) && wpjam_throw('rest_invalid_pattern', wpjam_join(' ', [$this->_title, $this->custom_validity]));
    312                     }elseif($args[0] == 'sanitize'){
    313                         $args[1]    = (string)$args[1];
    314                     }
    315                 }
    316 
    317                 return wpjam_try('rest_'.$args[0].'_value_from_schema', $args[1], $schema, $this->_title);
    318             }
    319 
    320             return $args[0] == 'validate' ? true : $args[1];
    321         }
    322 
    323282        if($args || isset($this->_schema)){
    324283            return $this->attr('_schema', ...$args);
     
    355314        }
    356315
    357         return $this->_schema = wpjam_parse_json_schema($value);
     316        $parse  = function($value) use(&$parse){
     317            foreach(wpjam_pull($value, ['enum', 'items', 'properties']) as $k => $v){
     318                if($k == 'enum'){
     319                    $value[$k]  = array_map(fn($iv)=> $this->sanitize($iv, $value), $v);
     320                }elseif($value['type'] == ($k == 'items' ? 'array' : 'object')){
     321                    $value[$k]  = $k == 'items' ? $parse($v) : array_map($parse, $v);
     322                }
     323            }
     324
     325            return $value;
     326        };
     327
     328        return $this->_schema = $parse($value);
    358329    }
    359330
     
    470441
    471442            if($type == 'parameter'){
    472                 is_null($value) || ($value = $this->schema('sanitize', $value));
    473             }else{
     443                $value  = is_null($value) ? null : $this->sanitize($value);
     444            }else{  // 空值只需 required 验证
    474445                is_blank($value) && $this->required && wpjam_throw(($type ?: 'value').'_required', [$this->_title]);
    475446
    476                 $value  = $this->schema($this->get_arg_by_parent('fieldset') == 'object' ? 'sanitize' : 'prepare', $value);
    477 
    478                 (is_array($value) || !is_blank($value)) && $this->schema('validate', $value);   // 空值只需 required 验证
     447                $schema = $this->schema() ?: [];
     448                $value  = [$this, $this->get_arg_by_parent('fieldset') == 'object' ? 'sanitize' : 'prepare']($value, $schema);
     449
     450                if((is_array($value) || !is_blank($value)) && $schema){
     451                    $schema['type'] == 'string' && $this->pattern && !rest_validate_json_schema_pattern($this->pattern, $value) && wpjam_throw('rest_invalid_pattern', wpjam_join(' ', [$this->_title, $this->custom_validity]));
     452
     453                    wpjam_try('rest_validate_value_from_schema', $value, $schema, $this->_title);
     454                }
    479455            }
    480456        }
     
    507483    }
    508484
    509     public function prepare($args, $type=''){
     485    public function prepare(...$args){
     486        $type   = $args[1] ??= '';
     487        $value  = $type ? $args[0] : null;
     488
     489        if(is_array($args[1])){
     490            $rule   = ($schema = $args[1]) ? ([
     491                'array'     => ['is_array', fn($val)=> wpjam_map($val, fn($v)=> $this->prepare($v, $schema['items']))],
     492                'object'    => ['is_array', fn($val)=> wpjam_map($val, fn($v, $k)=> $this->prepare($v, ($schema['properties'][$k] ?? [])))],
     493                'null'      => ['is_blank', fn()=> null],
     494                'integer'   => ['is_numeric', 'intval'],
     495                'number'    => ['is_numeric', 'floatval'],
     496                'string'    => ['is_scalar', 'strval'],
     497                'boolean'   => [fn($v)=> is_scalar($v) || is_null($v), 'rest_sanitize_boolean']
     498            ][$schema['type']] ?? '') : '';
     499
     500            return $rule && $rule[0]($value) ? $rule[1]($value) : $value;
     501        }
     502
     503        if($this->is('flat')){
     504            return $this->prepare_by_fields(...$args);
     505        }
     506
     507        if(!$type){
     508            $value  = $this->value_callback($args[0]);
     509        }
     510
    510511        if($this->is('set')){
    511             if($this->is('flat')){
    512                 return $this->prepare_by_fields($args, $type);
    513             }
    514 
    515             $value  = $type ? $args : $this->value_callback($args);
    516             $value  = $this->fields(fn($value)=> $this->prepare($this->unpack($value), 'value'), $value ?: []);
    517 
    518             return array_filter($value, fn($v)=> !is_null($v));
    519         }
    520 
    521         if($type == ''){
    522             return $this->prepare($this->schema('sanitize', $this->value_callback($args)), 'value');
    523         }
     512            return array_filter($this->fields(fn($v)=> $this->prepare($this->unpack($v), 'value'), $value ?: []), fn($v)=> !is_null($v));
     513        }
     514
     515        $value  = $this->sanitize($value);
    524516
    525517        if($this->is('mu')){
    526             return array_map(fn($v)=> $this->prepare_by_item($v, $type), $args);
     518            return array_map(fn($v)=> $this->prepare_by_item($v, 'value'), $value);
    527519        }elseif($this->is('img, image, file')){
    528             return wpjam_get_thumbnail($args, $this->size);
    529         }else{
    530             return $args && $this->parse_required ? $this->parse_value_by_data_type($args) : $args;
    531         }
     520            return wpjam_get_thumbnail($value, $this->size);
     521        }
     522
     523        return $value && $this->parse_required ? $this->parse_value_by_data_type($value) : $value;
     524    }
     525
     526    public function sanitize($value, ...$args){
     527        $schema = $args[0] ?? $this->schema();
     528
     529        return $schema ? wpjam_try('rest_sanitize_value_from_schema', ($schema['type'] == 'string' ? (string)$value : $value), $schema, $this->_title) : $value;
    532530    }
    533531
     
    690688            ]);
    691689        }elseif($this->is('uploader')){
    692             $mimes  = self::accept_to_mime_types($this->accept ?: 'image/*');
     690            $mimes  = wpjam_accept_to_mime_types($this->accept ?: 'image/*');
    693691            $exts   = implode(',', array_map(fn($v)=> str_replace('|', ',', $v), array_keys($mimes)));
    694692            $params = ['_ajax_nonce'=>wp_create_nonce('upload-'.$this->key), 'action'=>'wpjam-upload', 'name'=>$this->key, 'mimes'=>$mimes];
     
    13071305    }
    13081306
    1309     public function formulas($action='', $key='', ...$args){
    1310         if($action == 'parse'){
    1311             if(is_array($args[0])){
    1312                 return array_map(fn($f)=> array_merge($f, ['formula'=>$this->formulas('parse', $key, $f['formula'])]), $args[0]);
    1313             }
    1314 
     1307    public function formulas($key='', $path=[]){
     1308        if($key){
     1309            $fields     = $this->fields;
     1310            $throw      = fn($key, $msg)=> wpjam_throw('invalid_formula', implode([
     1311                is_array($key) ? $msg.':' : '',
     1312                implode(' → ', wpjam_map((array)$key, fn($k)=> '字段'.($fields[$k]['title'] ?? '').'「'.$k.'」'.'公式「'.$fields[$k]['formula'].'」')),
     1313                is_array($key) ? '' : ','.$msg
     1314            ]));
     1315
     1316            $path[]     = in_array($key, $path) ? $throw(array_slice($path, array_search($key, $path)), '公式嵌套') : $key;
    13151317            $depth      = 0;
    13161318            $functions  = ['abs', 'ceil', 'pow', 'sqrt', 'pi', 'max', 'min', 'fmod', 'round'];
    13171319            $signs      = ['+', '-', '*', '/', '(', ')', ',', '%'];
    1318             $formula    = preg_split('/\s*(['.preg_quote(implode($signs), '/').'])\s*/', trim($args[0]), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    1319             $throw      = fn($msg)=> wpjam_throw('invalid_formula', $this->formulas('render', $key, $args[0]).'错误,'.$msg);
     1320            $formula    = preg_split('/\s*(['.preg_quote(implode($signs), '/').'])\s*/', trim($fields[$key]['formula']), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    13201321
    13211322            foreach($formula as $t){
    13221323                if(is_numeric($t)){
    1323                     str_ends_with($t, '.') && $throw('无效数字「'.$t.'」');
     1324                    str_ends_with($t, '.') && $throw($key, '无效数字「'.$t.'」');
    13241325                }elseif(str_starts_with($t, '$')){
    1325                     isset($this->fields[substr($t, 1)]) || $throw('「'.$t.'」未定义');
     1326                    isset($fields[substr($t, 1)]) || $throw($key, '「'.$t.'」未定义');
    13261327                }elseif($t == '('){
    13271328                    $depth  += 1;
    13281329                }elseif($t == ')'){
    1329                     $depth  -= $depth ? 1 : $throw('括号不匹配');
     1330                    $depth  -= $depth ? 1 : $throw($key, '括号不匹配');
    13301331                }else{
    1331                     in_array($t, $signs) || in_array(strtolower($t), $functions) || $throw('无效的「'.$t.'」');
    1332                 }
    1333             }
    1334 
    1335             return $depth ? $throw('括号不匹配') : $formula;
    1336         }elseif($action == 'sort'){
    1337             if($this->get_arg('formulas['.$key.']')){
    1338                 return;
    1339             }
    1340 
    1341             $path   = $args[0] ?? [];
    1342             $path[] = in_array($key, $path) ? wpjam_throw('invalid_formula', '公式嵌套:'.implode(' → ', wpjam_map(array_slice($path, array_search($key, $path)), fn($k)=> $this->formulas('render', $k, $this->fields[$k]['formula'])))) : $key;
    1343 
    1344             $formula    = $this->formulas('parse', $key, $this->fields[$key]['formula']);
    1345 
    1346             wpjam_map(is_array($formula[0]) ? array_merge(...array_column($formula, 'formula')) : $formula, fn($t)=> try_remove_prefix($t, '$') && !empty($this->fields[$t]['formula']) && $this->formulas('sort', $t, $path));
     1332                    in_array($t, $signs) || in_array(strtolower($t), $functions) || $throw($key, '无效的「'.$t.'」');
     1333                }
     1334            }
     1335
     1336            $depth && $throw($key, '括号不匹配');
     1337
     1338            wpjam_map($formula, fn($t)=> try_remove_prefix($t, '$') && !empty($fields[$t]['formula']) && $this->formulas($t, $path));
    13471339
    13481340            $this->update_arg('formulas['.array_pop($path).']', $formula);
    1349         }elseif($action == 'render'){
    1350             return '字段'.wpjam_get($this->fields[$key], 'title').'「'.$key.'」'.'公式「'.$args[0].'」';
    13511341        }else{
    1352             is_null($this->formulas) && wpjam_map($this->fields, fn($v, $k)=> empty($v['formula']) || $this->formulas('sort', $k));
     1342            is_null($this->formulas) && wpjam_map($this->fields, fn($v, $k)=> empty($v['formula']) || $this->get_arg('formulas['.$k.']') || $this->formulas($k, []));
    13531343
    13541344            return $this->formulas;
     
    13571347
    13581348    private function number($v){
    1359         if(is_string($v)){
    1360             $v  = str_replace(',', '', trim($v));
    1361         }
     1349        $v  = is_string($v) ? str_replace(',', '', trim($v)) : $v;
    13621350
    13631351        return is_numeric($v) ? $v : false;
     
    14031391        }
    14041392
    1405         $formulas   = $this->formulas();
    1406         $args       = wp_parse_args($args, ['sum'=>false, 'key'=>'']);
    1407 
    1408         if($args['key']){
    1409             $key        = $args['key'];
    1410             $if_error   = $this->get_arg('if_errors['.$key.']');
    1411             $formula    = $formulas[$key];
    1412             $formula    = is_array($formula[0]) ? (($f = array_find($formula, fn($f)=> wpjam_match($item, $f))) ? $f['formula'] : []) : $formula;
    1413 
    1414             if(!$formula){
    1415                 return '';
    1416             }
    1417 
    1418             foreach($formula as &$t){
     1393        if(!empty($args['formula'])){
     1394            foreach($args['formula'] as &$t){
    14191395                if(str_starts_with($t, '$')){
    14201396                    $k  = substr($t, 1);
     
    14291405
    14301406                        if(!isset($t)){
    1431                             return $if_error ?? (isset($v) ? '!!无法计算' : '!无法计算');
     1407                            return $args['if_error'] ?? (isset($v) ? '!!无法计算' : '!无法计算');
    14321408                        }
    14331409                    }
     
    14361412
    14371413            try{
    1438                 return eval('return '.implode($formula).';');
     1414                return eval('return '.implode($args['formula']).';');
    14391415            }catch(DivisionByZeroError $e){
    1440                 return $if_error ?? '!除零错误';
     1416                return $args['error'] ?? '!除零错误';
    14411417            }catch(throwable $e){
    1442                 return $if_error ?? '!计算错误:'.$e->getMessage();
    1443             }
    1444         }
    1445 
    1446         if($args['sum']){
    1447             $formulas   = wpjam_pick($formulas, $this->sumable[2]);
    1448         }
     1418                return $args['error'] ?? '!计算错误:'.$e->getMessage();
     1419            }
     1420        }
     1421
     1422        $formulas   = $this->formulas();
     1423        $formulas   = empty($args['sum']) ? $formulas : wpjam_pick($formulas, $this->sumable[2]);
    14491424
    14501425        if($formulas){
    14511426            $prev   = set_error_handler(function($no, $str){
    1452                 if(str_contains($str , 'Division by zero')){
    1453                     throw new DivisionByZeroError($str);
    1454                 }
    1455 
    1456                 throw new ErrorException($str, $no);
     1427                throw str_contains($str , 'Division by zero') ? new DivisionByZeroError($str) : new ErrorException($str, $no);
    14571428            });
    14581429
    14591430            $item   = array_diff_key($item, $formulas);
    1460             $item   = array_reduce(array_keys($formulas), fn($c, $k)=> wpjam_set($c, $k, $this->calc($c, ['key'=>$k]+$args)), $item);
     1431            $item   = wpjam_reduce($formulas, fn($c, $v, $k)=> wpjam_set($c, $k, $this->calc($c, ['error'=>$this->get_arg('if_errors['.$k.']'), 'formula'=>$v])), $item);
     1432
    14611433            $prev ? set_error_handler($prev) : restore_error_handler();
    14621434        }
  • wpjam-basic/trunk/includes/class-wpjam-list-table.php

    r3423058 r3427357  
    407407
    408408    public function column_cb($item){
    409         if(($id = $this->parse_id($item)) && wpjam_current_user_can($this->capability, $id)){
     409        if(($id = $this->parse_id($item)) && wpjam_admin('can', $this->capability, $id)){
    410410            return wpjam_tag('input', ['type'=>'checkbox', 'name'=>'ids[]', 'value'=>$id, 'id'=>'cb-select-'.$id, 'title'=>'选择'.strip_tags($item[$this->get_primary_column_name()] ?? $id)]);
    411411        }
     
    478478    public function page_load(){
    479479        if(wp_doing_ajax()){
    480             return wpjam_add_admin_ajax('wpjam-list-table-action',  [
     480            return wpjam_ajax('wpjam-list-table-action',    [
     481                'admin'         => true,
    481482                'callback'      => $this,
    482483                'nonce_action'  => fn($data)=> ($object = $this->get_action($data['list_action'] ?? '')) ? $object->parse_nonce_action($data) : null
     
    488489        }
    489490
    490         wpjam_trap([$this, 'prepare_items'], fn($result)=> wpjam_add_admin_error($result));
     491        wpjam_trap([$this, 'prepare_items'], fn($result)=> wpjam_admin('error', $result));
    491492    }
    492493
     
    711712
    712713        if($response['type'] != 'form'){
    713             $args   = (in_array($type, ['submit', 'export']) ? array_filter(wpjam_pick($button, $cbs)) : [])+$args;
    714             $result = $this->callback(['data'=>$data, 'fields'=>$fields, 'submit_name'=>$submit]+$args);
    715             $errmsg = is_array($result) ? ($result['errmsg'] ?? '') : '';
    716             $errmsg = $errmsg && $errmsg != 'ok' ? $errmsg : ($type == 'submit' ? $button['text'].'成功' : '');
    717 
    718             $response['errmsg'] = $errmsg;  // 第三方接口可能返回 ok
     714            $args       = (in_array($type, ['submit', 'export']) ? array_filter(wpjam_pick($button, $cbs)) : [])+$args;
     715            $result     = $this->callback(['data'=>$data, 'fields'=>$fields, 'submit_name'=>$submit]+$args);
     716            $response   += wpjam_admin('notice', $result, $type == 'submit' ? $button['text'].'成功' : '');
    719717        }
    720718
    721719        if(is_array($result)){
     720            $response   += wpjam_pull($result, ['args']);
     721
    722722            if(array_intersect(array_keys($result), ['type', 'bulk', 'ids', 'id', 'items'])){
    723723                $response   = $result+$response;
     
    755755
    756756                if($response['type'] == 'form'){
    757                     $response['errmsg'] = '';
     757                    $response['notice'] = '';
    758758                }
    759759            }
     
    829829
    830830    public function is_allowed($args=[]){
    831         return $this->capability == 'read' || array_all($args && !$this->overall ? (array)$this->parse_arg($args) : [null], fn($id)=> wpjam_current_user_can($this->capability, $id, $this->name));
     831        return $this->capability == 'read' || array_all($args && !$this->overall ? (array)$this->parse_arg($args) : [null], fn($id)=> wpjam_admin('can', $this->capability, $id, $this->name));
    832832    }
    833833
     
    891891    public function button($args, $name=null){
    892892        if(!$name && $this->next){
    893             return wpjam_button(['next'=>'下一步']);
    894         }
    895 
    896         return wpjam_button([maybe_callback($this->submit_text, $this->parse_arg($args), $this->name) ?? (wp_strip_all_tags($this->title) ?: $this->page_title), $this->name], $name);
     893            return wpjam_admin('button', ['next'=>'下一步']);
     894        }
     895
     896        return wpjam_admin('button', [maybe_callback($this->submit_text, $this->parse_arg($args), $this->name) ?? (wp_strip_all_tags($this->title) ?: $this->page_title), $this->name], $name);
    897897    }
    898898
  • wpjam-basic/trunk/includes/class-wpjam-model.php

    r3423058 r3427357  
    321321class WPJAM_Query{
    322322    public static function query($vars, &$args=[]){
     323        if(!empty($vars['related_query'])){
     324            $post   = get_post(wpjam_pull($vars, 'post') ?? get_the_ID());
     325            $type   = get_post_type($post);
     326            $tt_ids = [];
     327
     328            foreach($post ? get_object_taxonomies($type) : [] as $tax){
     329                if($terms = $tax == 'post_format' ? [] : get_the_terms($post, $tax)){
     330                    $type   = array_merge((array)$type, get_taxonomy($tax)->object_type);
     331                    $tt_ids = array_merge($tt_ids, array_column($terms, 'term_taxonomy_id'));
     332                }
     333            }
     334
     335            if(!$tt_ids){
     336                return false;
     337            }
     338
     339            $vars   += ['post_status'=>'publish', 'post__not_in'=>[$post->ID], 'post_type'=>array_unique($type), 'term_taxonomy_ids'=>wpjam_filter($tt_ids, 'unique')];
     340        }
     341
    323342        $vars   = self::parse_vars($vars);
    324343
     
    348367            $query  = is_object($vars) ? $vars : self::query($vars, $args);
    349368
    350             if(!$parse){
    351                 return $query->posts;
     369            if(!$query || !$parse){
     370                return $query ? $query->posts : [];
    352371            }
    353372
     
    465484        $args   += ['query'=>$query];
    466485
    467         return $cb['wrap_callback'](implode(wpjam_map($query->posts, fn($p, $i)=> $cb['item_callback']($p->ID, $args+['i'=>$i]))), $args);
     486        return $query ? $cb['wrap_callback'](implode(wpjam_map($query->posts, fn($p, $i)=> $cb['item_callback']($p->ID, $args+['i'=>$i]))), $args) : '';
    468487    }
    469488
     
    582601            return isset($total) ? ['items'=>$items, 'total'=>$total] : $items;
    583602        }elseif(str_contains($method, '_meta')){
    584             return ($object = wpjam_get_meta_type_object($this->meta_type)) ? $object->$method(...$args) : null;
     603            return ($object = WPJAM_Meta_Type::get($this->meta_type)) ? $object->$method(...$args) : null;
    585604        }elseif(str_starts_with($method, 'cache_')){
    586605            return [WPJAM_Cache::create($this), $method](...$args);
     
    12671286        $type   = $this->item_type;
    12681287        $key    = $this->primary_key;
    1269         $uk     = $this->unique_key;
    12701288        $title  = $this->primary_title ?: 'ID';
    12711289        $add    = $method == 'insert' || ($method == 'add' && count($args) <= 1);
     
    12751293            $id || wpjam_throw('empty_'.($key ?: 'id'), ($key ? $title : 'ID').'不能为空');
    12761294
    1277             $exist  = isset($items[$id]);
    1278 
    12791295            if($method == 'set'){
    1280                 if(!$exist){
    1281                     $method = 'add';
    1282                 }
    1283             }else{
    1284                 if($exist === ($method == 'add')){
    1285                     wpjam_throw(($exist ? 'duplicate_' : 'invalid_').($key ?: 'id'), ($key ? $title : 'ID').'-「'.$id.'」'.($exist ? '已存在' : '不存在'));
    1286                 }
     1296                $method = isset($items[$id]) ? 'set' : 'add';
     1297            }elseif(($exist = isset($items[$id])) === ($method == 'add')){
     1298                wpjam_throw(($exist ? 'duplicate_' : 'invalid_').($key ?: 'id'), ($key ? $title : 'ID').'-「'.$id.'」'.($exist ? '已存在' : '不存在'));
    12871299            }
    12881300        }
     
    12951307            }
    12961308
    1297             $item   = array_shift($args);
     1309            $item   = $args[0];
    12981310
    12991311            if($type == 'array'){
    1300                 if($uk && ($add || isset($item[$uk]))){
    1301                     $uv     = $item[$uk] ?? '';
    1302                     $blank  = !$uv && !is_numeric($uv);
    1303 
    1304                     if($blank || array_find($items, fn($v, $k)=> ($add || $id != $k) && $v[$uk] == $uv)){
    1305                         wpjam_throw(($blank ? 'empty_' : 'duplicate_').$uk, ($this->unique_title ?: $uk).($blank ? '不能为空' : '不能重复'));
    1306                     }
    1307                 }
    1308 
    13091312                if($add){
    13101313                    if(in_array($key, ['option_key', 'id'])){
     
    13141317                        $id = $item[$key] ?? '';
    13151318
    1316                         (!$id || isset($items[$id])) && wpjam_throw(($id ? 'duplicate_' : 'empty_').$key, $title.($id ? '不能重复' : '不能为空'));
     1319                        (!$id || isset($items[$id])) && wpjam_throw(($id ? 'duplicate_' : 'empty_').$key, $title.($id ? '「'.$id.'」已被使用' : '不能为空'));
     1320                    }
     1321                }
     1322
     1323                if(($uk = $this->unique_key) && ($add || isset($item[$uk]))){
     1324                    $uv     = $item[$uk] ?? '';
     1325                    $blank  = !$uv && !is_numeric($uv);
     1326
     1327                    if($blank || array_find($items, fn($v, $k)=> ($add || $id != $k) && $v[$uk] == $uv)){
     1328                        wpjam_throw(($blank ? 'empty_' : 'duplicate_').$uk, ($this->unique_title ?: $uk).($blank ? '不能为空' : '「'.$uv.'」已被使用'));
    13171329                    }
    13181330                }
     
    13221334                $add && in_array($item, $items) && wpjam_throw('duplicate_item', '不能重复');
    13231335            }
     1336
     1337            $item   = $this->prepare_item ? $this->call('prepare_item_by_prop', $item, $id, $method, $items) : $item;
    13241338        }
    13251339
    13261340        if(in_array($method, ['add', 'insert'])){
    1327             $this->max_items && count($items) >= $this->max_items && wpjam_throw('over_max_items', '最大允许数量:'.$this->max_items);
    1328 
     1341            ($max   = $this->max_items) && count($items) >= $max && wpjam_throw('over_max_items', '最大允许数量:'.$max);
    13291342            $last   = $this->last ?? ($method == 'add');
    13301343
     
    13541367
    13551368    public function query_items($args){
    1356         $items  = $this->parse_items();
    13571369        $s      = trim(wpjam_pull($args, 's') ?: '');
    13581370        $number = wpjam_pull($args, 'number') ?: 50;
    13591371        $offset = wpjam_pull($args, 'offset') ?: 0;
    1360         $items  = $args ? array_filter($items, fn($item)=> wpjam_matches($item, $args)) : $items;
    1361         $items  = $s ? array_filter($items, fn($item)=> array_any($item, fn($v)=> str_contains($v, $s))) : $items;
    1362         $items  = array_values($items);
     1372        $items  = $this->parse_items();
     1373        $items  = array_values(($args || $s) ? array_filter($items, fn($item)=> (!$args || wpjam_matches($item, $args)) && (!$s || array_any($item, fn($v)=> str_contains($v, $s))) ) : $items);
    13631374
    13641375        return ['total'=>count($items), 'items'=>array_slice($items, $offset, $number)];
     
    13671378    public function parse_items($items=null){
    13681379        $items  ??= $this->get_items();
    1369         $items  = $items && is_array($items) ? wpjam_map($items, [$this, 'parse_item']) : [];
    1370         $items && $this->item_type == 'array' && wpjam_lazyload($this->lazyload_key, $items);
     1380
     1381        if($this->item_type == 'array'){
     1382            $items  = $items && is_array($items) ? wpjam_map($items, fn($v, $k)=> [$this->primary_key => $k]+(is_array($v) ? $v : [])) : [];
     1383            $items && wpjam_lazyload($this->lazyload_key, $items);
     1384        }
    13711385
    13721386        return $items;
    1373     }
    1374 
    1375     public function parse_item($item, $id){
    1376         return $this->item_type == 'array' ? [$this->primary_key => $id]+(is_array($item) ? $item : []) : $item;
    13771387    }
    13781388
     
    13931403    }
    13941404
    1395     public function exists($item, $type='unique'){
    1396         $items  = $this->get_items();
    1397         $items  = $this->item_type == 'array' ? ($type == 'unique' && $this->unique_key ? array_column($items, $this->unique_key) : array_keys($items)) : $items;
    1398 
    1399         return in_array($item, $items);
    1400     }
    1401 
    14021405    public function get($id){
    1403         $items  = $this->get_items();
    1404 
    1405         return isset($items[$id]) ? $this->parse_item($items[$id], $id) : null;
     1406        return ($items = wpjam_pick($this->get_items(), [$id])) ? $this->parse_items($items)[$id] : null;
    14061407    }
    14071408}
     
    14831484    }
    14841485}
     1486
  • wpjam-basic/trunk/includes/class-wpjam-user.php

    r3423058 r3427357  
    617617    public function registered(){
    618618        foreach(['login', 'bind'] as $action){
    619             wpjam_register_ajax($this->name.'-'.$action, [
     619            wpjam_ajax($this->name.'-'.$action, [
    620620                'nopriv'    => true,
    621621                'callback'  => [$this, 'ajax_response']
    622622            ]);
    623623
    624             wpjam_register_ajax('get-'.$this->name.'-'.$action, [
     624            wpjam_ajax('get-'.$this->name.'-'.$action, [
    625625                'nopriv'    => true,
    626626                'verify'    => false,
     
    867867
    868868    public static function init(){
     869        add_action('all_admin_notices', [self::class, 'render'], 9);
     870
    869871        wpjam_register_page_action('delete_notice', [
    870872            'button_text'   => '删除',
  • wpjam-basic/trunk/public/wpjam-compat.php

    r3423058 r3427357  
    244244        delete_option($from);
    245245    }
     246}
     247
     248function wpjam_get_verify_txt($name, $key=''){
     249    return wpjam_txt($name, $key);
     250}
     251
     252function wpjam_set_verify_txt($name, $data){
     253    return wpjam_txt($name, $data);
    246254}
    247255
     
    918926}
    919927
     928function wpjam_add_admin_error($msg='', $type='success'){
     929    wpjam_admin('error', $msg, $type);
     930}
     931
     932function wpjam_get_admin_post_id(){
     933    return wpjam_admin('post_id');
     934}
     935
    920936function_alias(fn($user, $blog_id, $capability, ...$args)=> wpjam_call_for_blog($blog_id, 'user_can', $user, $capability, ...$args), 'user_can_for_blog');
    921937function_alias(fn($type, $value, $key='')=> ($data = wpjam_get_by_meta($type, $key, $value)) ? (object)array_first($data) : false, 'get_metadata_by_value');
     
    937953
    938954function_alias('is_login', 'wpjam_is_login');
     955function_alias('wpjam_ajax', 'wpjam_register_ajax');
    939956function_alias('wpjam_route', 'wpjam_register_route');
    940957function_alias('wpjam_route', 'wpjam_register_route_module');
     
    14871504trait WPJAM_Meta_Trait{
    14881505    public static function get_meta_type_object(){
    1489         return wpjam_get_meta_type_object(self::$meta_type);
     1506        return WPJAM_Meta_Type::get(self::$meta_type);
    14901507    }
    14911508
  • wpjam-basic/trunk/public/wpjam-functions.php

    r3423058 r3427357  
    186186}
    187187
    188 // Verify TXT
    189 function wpjam_txt(...$args){
    190     $object = wpjam_setting('wpjam_verify_txts');
    191 
    192     if(!$args){
    193         return $object;
    194     }
    195 
    196     if($data = array_find($object->get_option(), fn($v)=> $v['name'] == $args[0])){
    197         header('Content-Type: text/plain');
    198         echo $data['value']; exit;
    199     }
    200 }
    201 
    202 function wpjam_get_verify_txt($name, $key=''){
    203     $data   = wpjam_txt()->get_setting($name);
    204 
    205     return $key == 'fields' ? [
    206         'name'  => ['title'=>'文件名称',    'type'=>'text', 'required', 'value'=>$data['name'] ?? '',   'class'=>'all-options'],
    207         'value' => ['title'=>'文件内容',    'type'=>'text', 'required', 'value'=>$data['value'] ?? '']
    208     ] : ($key ? ($data[$key] ?? '') : $data);
    209 }
    210 
    211 function wpjam_set_verify_txt($name, $data){
    212     return wpjam_txt()->update_setting($name, $data);
    213 }
    214 
    215188// Meta Type
    216189function wpjam_register_meta_type($name, $args=[]){
     
    266239
    267240function wpjam_add_post_type_field($post_type, $key, ...$args){
    268     ($object = WPJAM_Post_Type::get($post_type)) && wpjam_field($object, $key, ...$args);
     241    wpjam_field(WPJAM_Post_Type::get($post_type), $key, ...$args);
    269242}
    270243
    271244function wpjam_remove_post_type_field($post_type, $key){
    272     ($object = WPJAM_Post_Type::get($post_type)) && wpjam_field($object, $key);
     245    wpjam_field(WPJAM_Post_Type::get($post_type), $key);
    273246}
    274247
     
    487460}
    488461
    489 function wpjam_pagenavi($total=0, $echo=true){
    490     $result = '<div class="pagenavi">'.paginate_links(array_filter(['prev_text'=>'&laquo;', 'next_text'=>'&raquo;', 'total'=>$total])).'</div>';
    491 
    492     return $echo ? wpjam_echo($result) : $result;
    493 }
    494 
    495462// $number
    496463// $post_id, $args
     
    498465    if(is_null($args)){
    499466        $args   = ['number'=>$post];
    500         $post   = get_the_ID();
    501     }
    502 
    503     $post   = get_post($post);
    504     $type   = [get_post_type($post)];
    505     $tt_ids = [];
    506 
    507     foreach($post ? get_object_taxonomies($type[0]) : [] as $tax){
    508         if($terms = $tax == 'post_format' ? [] : get_the_terms($post, $tax)){
    509             $type   = array_merge($type, get_taxonomy($tax)->object_type);
    510             $tt_ids = array_merge($tt_ids, array_column($terms, 'term_taxonomy_id'));
    511         }
    512     }
    513 
    514     return $tt_ids ? wpjam_query(['related_query'=>true, 'post_status'=>'publish', 'post__not_in'=>[$post->ID], 'post_type'=>array_unique($type), 'term_taxonomy_ids'=>array_unique(array_filter($tt_ids))], $args) : false;
     467        $post   = null;
     468    }
     469
     470    return wpjam_query(['post'=>$post, 'related_query'=>true], $args);
    515471}
    516472
    517473function wpjam_get_related_posts($post=null, $args=[], $parse=false){
    518     return wpjam_query(wpjam_get_related_posts_query($post, $args), $args, $parse);
     474    return wpjam_query(['post'=>$post, 'related_query'=>true], $args, $parse);
    519475}
    520476
     
    525481function wpjam_get_top_viewd_posts($args=[], $parse=false){
    526482    return wpjam_query(['posts_per_page'=>5, 'orderby'=>'meta_value_num', 'meta_key'=>'views'], $args, $parse);
     483}
     484
     485function wpjam_pagenavi($total=0, $echo=true){
     486    $result = '<div class="pagenavi">'.paginate_links(array_filter(['prev_text'=>'&laquo;', 'next_text'=>'&raquo;', 'total'=>$total])).'</div>';
     487
     488    return $echo ? wpjam_echo($result) : $result;
    527489}
    528490
     
    537499
    538500function wpjam_add_taxonomy_field($taxonomy, $key, ...$args){
    539     ($object = WPJAM_Taxonomy::get($taxonomy)) && wpjam_field($object, $key, ...$args);
     501    wpjam_field(WPJAM_Taxonomy::get($taxonomy), $key, ...$args);
    540502}
    541503
    542504function wpjam_remove_taxonomy_field($taxonomy, $key){
    543     ($object = WPJAM_Taxonomy::get($taxonomy)) && wpjam_field($object, $key);
     505    wpjam_field(WPJAM_Taxonomy::get($taxonomy), $key);
    544506}
    545507
     
    549511
    550512function wpjam_update_taxonomy_setting($taxonomy, $key, $value){
    551     ($object = WPJAM_Taxonomy::get($taxonomy)) && ($object->$key    = $value);
     513    ($object = WPJAM_Taxonomy::get($taxonomy)) && ($object->$key = $value);
    552514}
    553515
     
    619581}
    620582
    621 // $args, $max_depth
     583// $vars, $max_depth
    622584// $term_ids, $args
    623585function wpjam_get_terms($vars, ...$args){
    624586    if(is_scalar($vars) || wp_is_numeric_array($vars)){
    625587        $terms  = WPJAM_Term::get_by_ids(wp_parse_id_list($vars));
    626         $parse  = $args[0] ?? false;
    627 
    628         return $parse ? array_map('wpjam_get_term', $terms) : $terms;
    629     }
    630 
    631     $arg    = $args[0] ?? null;
     588
     589        return $args && $args[0] ? array_map('wpjam_get_term', $terms) : $terms;
     590    }
     591
     592    $arg    = $args[0] ?? [];
    632593    $args   = (is_numeric($arg) ? ['depth'=>$arg] : (is_bool($arg) ? ['parse'=>$arg] : (is_array($arg) ? $arg : [])))+wpjam_pull($vars, ['format', 'parse']);
    633594
     
    640601
    641602function wpjam_get_term_thumbnail_url($term=null, $size='full', $crop=1){
    642     $term   ??= get_queried_object();
    643     $thumb  = ($term = get_term($term)) ? (get_term_meta($term->term_id, 'thumbnail', true) ?: apply_filters('wpjam_term_thumbnail_url', '', $term)) : '';
     603    $term   = get_term($term ?? get_queried_object());
     604    $thumb  = $term ? (get_term_meta($term->term_id, 'thumbnail', true) ?: apply_filters('wpjam_term_thumbnail_url', '', $term)) : '';
    644605
    645606    return $thumb ? wpjam_get_thumbnail($thumb, ($size ?: (wpjam_get_taxonomy_setting($term->taxonomy, 'thumbnail_size') ?: 'thumbnail')), $crop) : '';
     
    684645if(!function_exists('get_user_field')){
    685646    function get_user_field($field, $user=null, $context='display'){
    686         return (($user  = get_userdata($user)) && isset($user->$field)) ? sanitize_user_field($field, $user->$field, $user->ID, $context) : '';
     647        return (($user = get_userdata($user)) && isset($user->$field)) ? sanitize_user_field($field, $user->$field, $user->ID, $context) : '';
    687648    }
    688649}
     
    1011972
    1012973function wpjam_accept_to_mime_types($accept){
    1013     return WPJAM_Attr::accept_to_mime_types($accept);
     974    $allowed    = get_allowed_mime_types();
     975    $types      = [];
     976
     977    foreach(wpjam_lines($accept ?: '', ',', fn($v)=> strtolower($v)) as $v){
     978        if(str_ends_with($v, '/*')){
     979            $prefix = substr($v, 0, -1);
     980            $types  += array_filter($allowed, fn($m)=> str_starts_with($m, $prefix));
     981        }elseif(str_contains($v, '/')){
     982            $ext    = array_search($v, $allowed);
     983            $types  += $ext ? [$ext => $v] : [];
     984        }elseif(($v = ltrim($v, '.')) && preg_match('/^[a-z0-9]+$/', $v)){
     985            $ext    = array_find_key($allowed, fn($m, $ext)=> str_contains($ext, '|') ? in_array($v, explode('|', $ext)) : $v == $ext);
     986            $types  += $ext ? wpjam_pick($allowed, [$ext]) : [];
     987        }
     988    }
     989
     990    return $types;
    1014991}
    1015992
     
    1020997
    1021998function wpjam_wrap($text, $wrap='', ...$args){
     999    if($wrap === 'expandable'){
     1000        return wpjam_expandable($text, ...$args);
     1001    }
     1002
    10221003    if((is_array($wrap) || is_closure($wrap))){
    10231004        $text   = is_callable($wrap) ? $wrap($text, ...$args) : $text;
     
    10901071
    10911072        return [$object, $args ? 'update_arg' : 'delete_arg']('_fields['.$key.']', ...$args);
    1092     }
    1093 
    1094     $object = WPJAM_Field::create($field);
    1095     $args   = $args[0] ?? [];
    1096 
    1097     return $args ? (isset($args['wrap_tag']) ? $object->wrap(wpjam_pull($args, 'wrap_tag'), $args) : $object->render($args)) : $object;
    1098 }
    1099 
    1100 function wpjam_button($button, $key=null, $render=null){
    1101     if(wp_is_numeric_array($button)){
    1102         $button = is_array($button[0]) ? $button[0] : [$button[1] => $button[0]];
    1103         $button = $key ? ($button[$key] ?? wp_die('无效的提交按钮')) : $button;
    1104     }
    1105 
    1106     if($key){
    1107         $button = is_array($button) ? $button : ['text'=>$button];
    1108 
    1109         if($render){
    1110             return get_submit_button($button['text'], $button['class'] ?? 'primary', $key, false);
    1111         }
    1112     }else{
    1113         $render ??= true;
    1114         $button = wpjam_map(array_filter($button), fn($v, $k)=> wpjam_button($v, $k, $render));
    1115 
    1116         if($render){
    1117             return $button ? wpjam_tag('p', ['submit'], implode($button)) : wpjam_tag();
    1118         }
    1119     }
    1120 
    1121     return $button;
     1073    }elseif(is_array($field)){
     1074        $object = WPJAM_Field::create($field);
     1075        $args   = $args[0] ?? [];
     1076
     1077        return $args ? (isset($args['wrap_tag']) ? $object->wrap(wpjam_pull($args, 'wrap_tag'), $args) : $object->render($args)) : $object;
     1078    }
    11221079}
    11231080
     
    11461103
    11471104// AJAX
    1148 function wpjam_register_ajax($name, $args){
    1149     return WPJAM_AJAX::create($name, $args);
     1105function wpjam_ajax($name, $args){
     1106    if(empty($args['admin']) || wp_doing_ajax()){
     1107        return WPJAM_AJAX::create($name, $args);
     1108    }
    11501109}
    11511110
  • wpjam-basic/trunk/public/wpjam-route.php

    r3423058 r3427357  
    107107
    108108function wpjam_bind($cb, $args){
    109     $object = is_object($args) ? $args : wpjam_args($args);
    110 
    111     return $cb->bindTo($object, $object);
     109    if(is_closure($cb)){
     110        $object = is_object($args) ? $args : wpjam_args($args);
     111
     112        return $cb->bindTo($object, $object);
     113    }
     114
     115    return $cb;
    112116}
    113117
     
    893897}
    894898
     899// txt
     900function wpjam_txt($name, ...$args){
     901    $object = wpjam_setting('wpjam_verify_txts');
     902
     903    if($args && is_array($args[0])){
     904        return $object->update_setting($name, ...$args);
     905    }
     906
     907    if(!str_ends_with($name, '.txt')){
     908        $data   = $object->get_setting($name) ?: [];
     909        $key    = $args[0] ?? '';
     910
     911        return $key == 'fields' ? [
     912            'name'  => ['title'=>'文件名称',    'type'=>'text', 'required', 'value'=>$data['name'] ?? '',   'class'=>'all-options'],
     913            'value' => ['title'=>'文件内容',    'type'=>'text', 'required', 'value'=>$data['value'] ?? '']
     914        ] : ($key ? ($data[$key] ?? '') : $data);
     915    }
     916
     917    if($data = array_find($object->get_option(), fn($v)=> $v['name'] == $name)){
     918        header('Content-Type: text/plain');
     919        echo $data['value']; exit;
     920    }
     921}
     922
    895923function wpjam_activation(...$args){
    896924    $args   = $args ? array_reverse(array_slice($args+['', 'wp_loaded'], 0, 2)) : [];
     
    10531081}
    10541082
    1055 function wpjam_current_user_can($capability, ...$args){
    1056     return ($capability = maybe_closure($capability, ...$args)) ? current_user_can($capability, ...$args) : true;
    1057 }
    1058 
    10591083// Rewrite Rule
    10601084function wpjam_add_rewrite_rule($args){
     
    11711195    }
    11721196
    1173     function wpjam_add_admin_ajax($action, $args=[]){
    1174         wp_doing_ajax() && wpjam_register_ajax($action, ['admin'=>true]+$args);
    1175     }
    1176 
    1177     function wpjam_add_admin_error($msg='', $type='success'){
    1178         if(is_wp_error($msg)){
    1179             $msg    = $msg->get_error_message();
    1180             $type   = 'error';
    1181         }
    1182 
    1183         $msg && $type && wpjam_admin('error[]', compact('msg', 'type'));
    1184     }
    1185 
    11861197    function wpjam_add_admin_load($args){
    11871198        if(wp_is_numeric_array($args)){
     
    11981209    }
    11991210
    1200     function wpjam_get_admin_post_id(){
    1201         return (int)($_GET['post'] ?? ($_POST['post_ID'] ?? 0));
    1202     }
    1203 
    12041211    function wpjam_register_page_action($name, $args){
    12051212        return WPJAM_Page_Action::create($name, $args);
  • wpjam-basic/trunk/public/wpjam-utils.php

    r3423058 r3427357  
    1414// JWT
    1515function wpjam_generate_jwt($payload, $header=[]){
    16     $header += ['alg'=>'HS256', 'typ'=>'JWT'];
    17     $jwt    = is_array($payload) && $header['alg'] == 'HS256' ? implode('.', array_map(fn($v)=> base64_urlencode(wpjam_json_encode($v)), [$header, $payload])) : '';
     16    $header += ['typ'=>'JWT'];  // 'alg'=>'HS256'
     17    $jwt    = is_array($payload) ? implode('.', array_map(fn($v)=> base64_urlencode(wpjam_json_encode($v)), [$header, $payload])) : '';
    1818
    1919    return $jwt ? $jwt.'.'.wpjam_generate_signature('hmac-sha256', $jwt) : false;
     
    2929        //nbf 时间之前不接收处理该Token
    3030        //exp 过期时间不能小于当前时间
    31         if(($header['alg'] ?? '') == 'HS256' &&
    32             !array_any(['iat'=>'>', 'nbf'=>'>', 'exp'=>'<'], fn($v, $k)=> isset($payload[$k]) && wpjam_compare($payload[$k], $v, time()))
    33         ){
     31        if(!array_any(['iat'=>'>', 'nbf'=>'>', 'exp'=>'<'], fn($v, $k)=> isset($payload[$k]) && wpjam_compare($payload[$k], $v, time()))){
    3432            return $payload;
    3533        }
     
    4240    $header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
    4341
    44     return str_starts_with($header, 'Bearer') ? trim(substr($header, 6)) : wpjam_get_parameter($key, ['required'=>$required]);
     42    return try_remove_prefix($header, 'Bearer') ? trim($header) : wpjam_get_parameter($key, ['required'=>$required]);
    4543}
    4644
     
    9189        $length = (unpack("N", substr($text, 0, 4)))[1];
    9290
    93         if($args && trim(substr($text, $length + 4)) != trim($args[0])){
     91        if(trim(substr($text, $length + 4)) != trim($args[0])){
    9492            return new WP_Error('invalid_appid', 'Appid 校验「'.substr($text, $length + 4).'」「'.$args[0].'」错误');
    9593        }
     
    110108
    111109// JSON
    112 function wpjam_parse_json_schema($schema){
    113     if(isset($schema['enum'])){
    114         $schema['enum'] = array_map(fn($v)=> rest_sanitize_value_from_schema($v, wpjam_except($schema, 'enum')), $schema['enum']);
    115     }
    116 
    117     foreach(wpjam_pull($schema, ['items', 'properties']) as $k => $v){
    118         if($schema['type'] == ($k == 'items' ? 'array' : 'object')){
    119             $schema[$k] = $k == 'items' ?  wpjam_parse_json_schema($v) : array_map('wpjam_parse_json_schema', $v);
    120         }
    121     }
    122 
    123     return $schema;
    124 }
    125 
    126 if(!function_exists('rest_prepare_value_from_schema')){
    127     function rest_prepare_value_from_schema($value, $schema){
    128         $rule   = [
    129             'array'     => ['is_array', fn($val)=> wpjam_map($val, fn($v)=> rest_prepare_value_from_schema($v, $schema['items']))],
    130             'object'    => ['is_array', fn($val)=> wpjam_map($val, fn($v, $k)=> rest_prepare_value_from_schema($v, ($schema['properties'][$k] ?? '')))],
    131             'null'      => ['is_blank', fn()=> null],
    132             'integer'   => ['is_numeric', 'intval'],
    133             'number'    => ['is_numeric', 'floatval'],
    134             'string'    => ['is_scalar', 'strval'],
    135             'boolean'   => [fn($v)=> is_scalar($v) || is_null($v), 'rest_sanitize_boolean']
    136         ][$schema['type']] ?? '';
    137 
    138         return $rule && $rule[0]($value) ? $rule[1]($value) : $value;
    139     }
    140 }
    141 
    142110function wpjam_json_encode($data){
    143111    return wp_json_encode($data, JSON_UNESCAPED_UNICODE);
     
    501469   
    502470        if($op){
    503             trigger_error('matches');
     471            trigger_error('matches');   // del 2026-03-31
    504472            return wpjam_matches($item, $args, $op);
    505473        }
     
    530498    $op = strtoupper($op);
    531499
    532     if(in_array($op, ['AND', 'OR', 'NOT'])){
    533         return wpjam_array($args, fn($v, $k)=> wpjam_match($item, ...(wpjam_is_assoc_array($v) ? [$v+['key'=>$k]] : [$k, $v])), $op);
    534     }
    535 
    536     return false;
     500    return in_array($op, ['AND', 'OR', 'NOT']) ? wpjam_array($args, fn($v, $k)=> wpjam_match($item, ...(wpjam_is_assoc_array($v) ? [$v+['key'=>$k]] : [$k, $v])), $op) : false;
    537501}
    538502
     
    13061270
    13071271function wpjam_expandable($str, $num=10, $name=null){
    1308     if(count(explode("\n", $str)) > $num){
     1272    if(is_a($str, 'WPJAM_Tag') || count(explode("\n", $str)) > $num){
    13091273        static $index = 0;
    13101274
  • wpjam-basic/trunk/readme.txt

    r3423058 r3427357  
    33Donate link: https://wpjam.com/
    44Tags: WPJAM, Memcached, 性能优化
    5 Requires at least: 6.5
     5Requires at least: 6.7
    66Requires PHP: 7.4
    7 Tested up to: 6.7
     7Tested up to: 6.9
    88Stable tag: trunk
    99License: GPLv2 or later
     
    5454== Changelog ==
    5555
    56 = 6.8.7 =
     56= 6.9 =
    5757* 新增函数 get_term_level
    5858* 新增函数 get_term_depth
     
    6161* 新增函数 wpjam_is,判断当前 query 是 is_main_query 并且还支持判断在哪些页面
    6262* 新增函数 wpjam_matches,支持多条件匹配检测
    63 * 新增函数 wpjam_parse_json_schema 
    64 * 新增函数 rest_prepare_value_from_schema
     63* 新增函数 current_shortcode 和 doing_shortcode,用于 shortcode 获取和判断
    6564* 新增 PHP 8.5 array_first 和 array_last 兼容
    6665* wpjam_try 和 wpjam_catch 函数新增 :: 和 -> 模式的支持
     
    7069* WP_Query 新增 sticky_posts 参数支持
    7170* WPJAM_Args 新增 pick 方法
    72 * WPJAM_Field 优化 attr 转换 data 的处理
    73 * WPJAM_Post 优化 parse_for_json 的处理
    74 * WPJAM_Taxonomy 和 WPJAM_Meta_Option 新增 show_in_posts_rest 属性。
    75 * 全面优化 WPJAM_AJAX class,整合后台的 AJAX 操作
     71* WPJAM_Taxonomy 和 WPJAM_Meta_Option 新增 show_in_posts_rest 属性
    7672* 后台 JS 新增 list_table_load 事件
    7773* wpjam_set 支持 [] 模式新增元素
     
    134130* 后台 List Table 新增导出操作支持,列表 AJAX 返回更加细化
    135131* 优化自定义文章类型和分类模式获取名称的方式
    136 * 新增 Class WPJAM_Platforms - 多平台处理
    137 * 新增函数 wpjam_url,根据目录获取 url
     132* 新增函数 wpjam_url - 根据目录获取 url
    138133* 新增函数 wpjam_has_bit / wpjam_add_bit / wpjam_remove_bit - 位运算
    139134* 新增函数:wpjam_move / wpjam_get_all_terms / wpjam_html_tag_processor / wpjam_dashboard_widget
     
    145140* 新增函数 wpjam_generate_jwt / wpjam_verify_jwt, 实现 JWT 生成和验证
    146141* WPJAM_Field 增加 before / after 属性,统一使用 button_field 作为各种按钮的自定义文本
    147 * WPJAM_Register 增加 admin_load config
     142* WPJAM_Register 继承 WPJAM_Args 来丰富功能
     143* WPJAM_Register 新增 init 参数,支持在 WordPress init 时回调
     144* WPJAM_Register 增加 add_hooks
    148145* WPJAM_Model 支持 meta_input 方法
    149146* WPJAM_DB 新增 group_cache_key 属性,新增 query 方法
     
    166163* 新增 Trait WPJAM_Call_Trait,WPJAM_Items_Trat / WPJAM_Instance
    167164* 新增 WPJAM_Post / WPJAM_Term 的 update_callback 方法,支持同时更新文章和分类的本身字段和自定义字段
    168 * WPJAM_Register 继承 WPJAM_Args 来丰富功能
    169 * WPJAM_Register 增加 add_hooks 支持,支持 group config。
    170165* WPJAM_JSON 支持 data_type 接口,用于前端自动完成
    171166* WPJAM_Field 支持 data_type 的数据源联动处理,下拉菜单,单选和复选框都支持其他选项
     
    195190* 函数 wpjam_register 新增 priority 参数
    196191* 函数 wpjam_register_option 新增 field_default / menu_page 参数
    197 * Class WPJAM_Register 新增 init 参数,支持在 WordPress init 时回调
    198192* 增强 Class WPJAM_Option_Setting
    199193* 增强「文章浏览」扩展,支持批量增加浏览数
     
    248242* 新增 WPJAM_Field 分组打横显示功能
    249243* 新增 Class WPJAM_Bind - 用户社交账号绑定
    250 * 新增 Class WPJAM_AJAX - 统一 AJAX 处理
     244* 新增 Class WPJAM_AJAX - 统一所有(包括后台) AJAX 处理
    251245* 新增函数 wpjam_register_meta_type
    252246* 新增函数 wpjam_register_bind
     
    265259* 跳过其他版本直接升级到 5.6 / WordPress 保持一致
    266260* CDN 文件扩展设置和媒体库对应
    267 * 调用 save_post 改成调用 wp_after_insert_post
    268261
    269262= 5.2 =
     
    271264* 新增函数 wpjam_register_json 自定义 API 接口
    272265* wpjam_add_menu_page 支持 load_callback 参数
    273 * form 页面支持 summary
    274266* wpjam_register_option 支持自定义 update_callback 和 reset 选项
    275267
     
    380372= 3.0 =
    381373* 基于 PHP 7.2 进行代码重构,效率更高,更加快速
    382 * 全AJAX操作后台
     374* 全 AJAX 操作后台
    383375* 新增「简单SEO」扩展
    384376* 新增「短代码」扩展
  • wpjam-basic/trunk/static/script.js

    r3396132 r3427357  
    148148            }
    149149
    150             if(!args){
     150            if(args){
     151                if(args.action_type == 'submit'){
     152                    $el = $el.is(':submit') ? $el : this.find(':submit').first().focus();
     153                }
     154            }else{
    151155                args    = {
    152156                    action_type:    this.is('form') ? 'submit' : (this.data('direct') ? 'direct' : 'form'),
     
    298302
    299303                    if(type == 'option'){
    300                         data.type == 'save' && wpjam.add_notice(data.errmsg, 'success');
     304                        data.type == 'save' && wpjam.add_notice(data.notice);
    301305
    302306                        $('body').wpjam_form().trigger('option_action_success', data);
    303307                    }else if(type == 'page'){
    304308                        if(!['form', 'append', 'redirect'].includes(data.type)){
    305                             data.done === 0 && setTimeout(()=> this.wpjam_action(type, _.extend({}, args, {data: data.args})), 400);
     309                            data.args && setTimeout(()=> this.wpjam_action(type, _.extend({}, args, {data: data.args})), 400);
    306310
    307311                            args.action_type == 'submit' && $('#wpjam_form').length && data.form && $('#wpjam_form').html(data.form);
    308312
    309                             wpjam.add_notice(data.errmsg || args.page_title+'成功', data.notice_type || 'success');
     313                            wpjam.add_notice(data.notice || args.page_title+'成功');
    310314                        }
    311315
     
    334338                            }
    335339                        }else if(!['form', 'append', 'redirect'].includes(data.type)){
     340                            data.args && setTimeout(()=> ($('#TB_window').length ? $('#list_table_action_form') : this).wpjam_action(type, _.extend({}, args, {data: data.args})), 400);
     341
    336342                            data.type == 'list' && data.list_action == 'delete' && list_table.delete_row(args.id);
    337343
     
    437443
    438444        add_notice: function(notice, type){
     445            if(typeof notice === 'object'){
     446                type    = notice.type;
     447                notice  = notice.message;
     448            }
     449
    439450            if(notice){
    440                 let $notice = $('<div class="notice notice-'+type+' is-replaceable is-dismissible"><p><strong>'+notice+'</strong></p></div>');
     451                let $notice = $('<div class="notice notice-'+(type || 'success')+' is-replaceable is-dismissible"><p><strong>'+notice+'</strong></p></div>');
    441452
    442453                if($('#TB_ajaxContent').length){
     
    10361047
    10371048                (modal && data.form) && wpjam.add_modal(data);
    1038                 (modal || args.action_type != 'submit') && wpjam.add_notice(data.errmsg, 'success');
     1049                (modal || args.action_type != 'submit') && wpjam.add_notice(data.notice);
    10391050
    10401051                if(data.type == 'list'){
     
    11551166    });
    11561167
     1168    $(document).on('heartbeat-send', (e, data)=> wpjam.query_data && $.extend(data, wpjam.query_data));
     1169
    11571170    wpjam.load();
    11581171});
  • wpjam-basic/trunk/static/style.css

    r3396132 r3427357  
    2323.expandable-container{display:flex; flex-direction:column-reverse; align-items:flex-start;}
    2424.expandable-container .inner{max-height:12em; margin-bottom:1em; overflow:hidden; transition:max-height 1s ease;}
     25.expandable-container .inner .row-actions{display:none;}
    2526.expandable-container input:checked + label + .inner{max-height:none; margin-bottom:0;}
     27.expandable-container input:checked + label + .inner .row-actions{display:initial;}
    2628.expandable-container input{display:none;}
    2729.expandable-container label:before{font-family:remixicon !important; font-style:normal; content:"展开\f2e0";}
  • wpjam-basic/trunk/wpjam-basic.php

    r3423059 r3427357  
    44Plugin URI: https://blog.wpjam.com/project/wpjam-basic/
    55Description: WPJAM 常用的函数和接口,屏蔽所有 WordPress 不常用的功能。
    6 Version: 6.8.8
    7 Requires at least: 6.6
    8 Tested up to: 6.8
     6Version: 6.9
     7Requires at least: 6.7
     8Tested up to: 6.9
    99Requires PHP: 7.4
    1010Author: Denis
Note: See TracChangeset for help on using the changeset viewer.