Changeset 3454739
- Timestamp:
- 02/05/2026 03:10:11 PM (8 weeks ago)
- Location:
- wpjam-basic/trunk
- Files:
-
- 28 edited
-
components/server-status.php (modified) (3 diffs)
-
components/wpjam-admin.php (modified) (1 diff)
-
components/wpjam-basic.php (modified) (1 diff)
-
components/wpjam-cdn.php (modified) (8 diffs)
-
components/wpjam-custom.php (modified) (1 diff)
-
components/wpjam-enhance.php (modified) (14 diffs)
-
components/wpjam-thumbnail.php (modified) (1 diff)
-
extends/mobile-theme.php (modified) (5 diffs)
-
extends/quick-excerpt.php (modified) (1 diff)
-
extends/wpjam-roles.php (modified) (1 diff)
-
extends/wpjam-seo.php (modified) (1 diff)
-
extends/wpjam-toc.php (modified) (5 diffs)
-
includes/class-wpjam-admin.php (modified) (10 diffs)
-
includes/class-wpjam-api.php (modified) (17 diffs)
-
includes/class-wpjam-field.php (modified) (22 diffs)
-
includes/class-wpjam-list-table.php (modified) (28 diffs)
-
includes/class-wpjam-model.php (modified) (1 diff)
-
includes/class-wpjam-post.php (modified) (1 diff)
-
includes/class-wpjam-user.php (modified) (1 diff)
-
public/wpjam-compat.php (modified) (4 diffs)
-
public/wpjam-functions.php (modified) (8 diffs)
-
public/wpjam-route.php (modified) (19 diffs)
-
public/wpjam-utils.php (modified) (14 diffs)
-
readme.txt (modified) (2 diffs)
-
static/form.js (modified) (1 diff)
-
static/script.js (modified) (3 diffs)
-
static/style.css (modified) (2 diffs)
-
wpjam-basic.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
wpjam-basic/trunk/components/server-status.php
r3440469 r3454739 11 11 12 12 class WPJAM_Server_Status{ 13 public static function server_widget(){ 14 $items[] = ['title'=>'服务器', 'value'=>gethostname().'('.$_SERVER['HTTP_HOST'].')']; 15 $items[] = ['title'=>'服务器IP', 'value'=>'内网:'.gethostbyname(gethostname())]; 16 $items[] = ['title'=>'系统', 'value'=>php_uname('s')]; 17 18 if(strpos(ini_get('open_basedir'), ':/proc') !== false){ 19 if(@is_readable('/proc/cpuinfo')){ 20 $cpus = wpjam_lines(file_get_contents('/proc/cpuinfo'), "\n\n"); 21 $base[] = count($cpus).'核'; 13 public static function callback(...$args){ 14 $id = $args[1]['id']; 15 $items = [self::class, $GLOBALS['current_tab']]($id); 16 17 if($id == 'usage'){ 18 foreach($items as $item){ 19 echo '<hr />'; 20 21 $unit = wpjam_pull($item[1], 'unit') ?: 1; 22 $data = wpjam_map(wpjam_pull($item[1], 'labels'), fn($v, $k) => ['label'=>$v, 'count'=>round($item[0][$k]/$unit, 2)]); 23 24 echo wpjam_chart('donut', $data, $item[1]+['total'=>true, 'chart_width'=>150, 'table_width'=>320]); 22 25 } 26 }else{ 27 ?> 28 <table class="widefat striped" style="border:none;"> 29 <tbody><?php foreach($items as $item){ ?> 30 <tr><?php foreach($item as $i){ ?> 31 <td><?php echo $i; ?></td> 32 <?php } ?></tr> 33 <?php } ?></tbody> 34 </table> 35 <?php 36 } 37 } 38 39 public static function server($id){ 40 if($id == 'server'){ 41 $items[] = ['服务器', gethostname().'('.$_SERVER['HTTP_HOST'].')']; 42 $items[] = ['服务器IP', '内网:'.gethostbyname(gethostname())]; 43 $items[] = ['系统', php_uname('s')]; 44 45 if(strpos(ini_get('open_basedir'), ':/proc') !== false){ 46 if(@is_readable('/proc/cpuinfo')){ 47 $cpus = wpjam_lines(file_get_contents('/proc/cpuinfo'), "\n\n"); 48 $base[] = count($cpus).'核'; 49 } 50 51 if(@is_readable('/proc/meminfo')){ 52 $mems = wpjam_lines(file_get_contents('/proc/meminfo')); 53 $mem = (int)substr(array_find($mems, fn($m) => str_starts_with($m, 'MemTotal:')), 9); 54 $base[] = round($mem/1024/1024).'G'; 55 } 56 57 if(!empty($base)){ 58 $items[] = ['配置', '<strong>'.implode(' / ', $base).'</strong>']; 59 } 23 60 24 if(@is_readable('/proc/meminfo')){ 25 $mems = wpjam_lines(file_get_contents('/proc/meminfo')); 26 $mem = (int)substr(array_find($mems, fn($m) => str_starts_with($m, 'MemTotal:')), 9); 27 $base[] = round($mem/1024/1024).'G'; 61 if(@is_readable('/proc/meminfo')){ 62 $uptime = wpjam_lines(file_get_contents('/proc/uptime'), ' '); 63 $items[] = ['运行时间', human_time_diff(time()-$uptime[0])]; 64 } 65 66 67 $items[] = ['空闲率', round($uptime[1]*100/($uptime[0]*count($cpus)), 2).'%']; 68 $items[] = ['系统负载', '<strong>'.implode(' ',sys_getloadavg()).'</strong>']; 28 69 } 29 70 30 if(!empty($base)){ 31 $items[] = ['title'=>'配置', 'value'=>'<strong>'.implode(' / ', $base).'</strong>']; 71 $items[] = ['文档根目录', $_SERVER['DOCUMENT_ROOT']]; 72 73 return $items; 74 }elseif($id == 'version'){ 75 return [ 76 [wpjam_lines($_SERVER['SERVER_SOFTWARE'], '/')[0], $_SERVER['SERVER_SOFTWARE']], 77 ['MySQL', $GLOBALS['wpdb']->db_version().'(最低要求:'.$GLOBALS['required_mysql_version'].')'], 78 ['PHP', phpversion().'(最低要求:'.$GLOBALS['required_php_version'].')'], 79 ['Zend', Zend_Version()], 80 ['WordPress', $GLOBALS['wp_version'].'('.$GLOBALS['wp_db_version'].')'], 81 ['TinyMCE', $GLOBALS['tinymce_version']] 82 ]; 83 }elseif($id == 'php'){ 84 return [[implode(' ', get_loaded_extensions())]]; 85 }elseif($id == 'apache'){ 86 return [[implode(' ', apache_get_modules())]]; 87 } 88 } 89 90 public static function opcache($id){ 91 if($id == 'usage'){ 92 echo '<p>'.wpjam_get_page_button('reset_opcache').'</p>'; 93 94 $status = opcache_get_status(); 95 $rest = $status['opcache_statistics']['max_cached_keys']-$status['opcache_statistics']['num_cached_keys']; 96 97 return [ 98 [$status['memory_usage'], [ 99 'title' => '内存使用', 100 'labels' => ['used_memory'=>'已用内存', 'free_memory'=>'剩余内存', 'wasted_memory'=>'浪费内存'], 101 'unit' => 1024*1024 102 ]], 103 [$status['opcache_statistics'], [ 104 'title' => '命中率', 105 'labels' => ['hits'=>'命中', 'misses'=>'未命中'] 106 ]], 107 [$status['opcache_statistics']+['rest_cached_keys'=>$rest], [ 108 'title' => '存储Keys', 109 'labels' => ['num_cached_keys'=>'已用Keys', 'rest_cached_keys'=>'剩余Keys'] 110 ]] 111 ]; 112 }elseif($id == 'status'){ 113 return wpjam_entries(opcache_get_status()['opcache_statistics']); 114 }elseif($id == 'configuration'){ 115 $config = opcache_get_configuration(); 116 117 return array_reduce([$config['version'], wpjam_array($config['directives'], fn($k)=> str_replace('opcache.', '', $k))], fn($c, $v)=> array_merge($c, wpjam_entries($v)), []); 118 } 119 } 120 121 public static function memcached($id){ 122 foreach($GLOBALS['wp_object_cache']->get_stats() as $key => $stats){ 123 if($id == 'usage'){ 124 echo '<p>'.wpjam_get_page_button('flush_mc').'</p>'; 125 126 return [ 127 [$stats, [ 128 'title' => '命中率', 129 'labels' => ['get_hits'=>'命中次数', 'get_misses'=>'未命中次数'], 130 ]], 131 [$stats+['rest'=>$stats['limit_maxbytes']-$stats['bytes']], [ 132 'title' => '内存使用', 133 'labels' => ['bytes'=>'已用内存', 'rest'=>'剩余内存'], 134 'unit' => 1024*1024 135 ]] 136 ]; 137 }elseif($id == 'status'){ 138 return [ 139 ['Memcached地址', $key], 140 ['Memcached版本', $stats['version']], 141 ['进程ID', $stats['pid']], 142 ['启动时间', wpjam_date('Y-m-d H:i:s',($stats['time']-$stats['uptime']))], 143 ['运行时间', human_time_diff(0,$stats['uptime'])], 144 ['已用/分配的内存', size_format($stats['bytes']).' / '.size_format($stats['limit_maxbytes'])], 145 ['当前/启动后总数量', $stats['curr_items'].' / '.$stats['total_items']], 146 ['为获取内存踢除数量', $stats['evictions']], 147 ['当前/总打开连接数', $stats['curr_connections'].' / '.$stats['total_connections']], 148 ['总命中次数', $stats['get_hits']], 149 ['总未命中次数', $stats['get_misses']], 150 ['总获求次数', $stats['cmd_get']], 151 ['总请求次数', $stats['cmd_set']], 152 ['Item平均大小', size_format($stats['bytes']/$stats['curr_items'])], 153 ]; 154 }elseif($id == 'efficiency'){ 155 return wpjam_map(['get_hits'=>'命中', 'get_misses'=>'未命中', 'cmd_get'=>'获取', 'cmd_set'=>'设置'], fn($v, $k)=> ['每秒'.$v.'次数', round($stats[$k]/$stats['uptime'])]); 156 }elseif($id == 'options'){ 157 return wpjam_array(wpjam_get_reflection(['Memcached'], 'Constants'), fn($k, $v)=> str_starts_with($k, 'OPT_') ? [$k, [$k, $GLOBALS['wp_object_cache']->get_mc()->getOption($v)]] : null); 32 158 } 33 34 if(@is_readable('/proc/meminfo')){ 35 $uptime = wpjam_lines(file_get_contents('/proc/uptime'), ' '); 36 $items[] = ['title'=>'运行时间', 'value'=>human_time_diff(time()-$uptime[0])]; 37 } 38 39 40 $items[] = ['title'=>'空闲率', 'value'=>round($uptime[1]*100/($uptime[0]*count($cpus)), 2).'%']; 41 $items[] = ['title'=>'系统负载', 'value'=>'<strong>'.implode(' ',sys_getloadavg()).'</strong>']; 42 } 43 44 $items[] = ['title'=>'文档根目录', 'value'=>$_SERVER['DOCUMENT_ROOT']]; 45 46 self::output($items); 47 } 48 49 public static function php_widget(){ 50 self::output([['value'=>implode(', ', get_loaded_extensions())]]); 51 } 52 53 public static function apache_widget(){ 54 self::output([['value'=>implode(', ', apache_get_modules())]]); 55 } 56 57 public static function version_widget(){ 58 global $wpdb, $required_mysql_version, $required_php_version, $wp_version, $wp_db_version, $tinymce_version; 59 60 $http = $_SERVER['SERVER_SOFTWARE']; 61 62 self::output([ 63 ['title'=>wpjam_lines($http, '/')[0], 'value'=>$http], 64 ['title'=>'MySQL', 'value'=>$wpdb->db_version().'(最低要求:'.$required_mysql_version.')'], 65 ['title'=>'PHP', 'value'=>phpversion().'(最低要求:'.$required_php_version.')'], 66 ['title'=>'Zend', 'value'=>Zend_Version()], 67 ['title'=>'WordPress', 'value'=>$wp_version.'('.$wp_db_version.')'], 68 ['title'=>'TinyMCE', 'value'=>$tinymce_version] 69 ]); 70 } 71 72 public static function opcache_status_widget(){ 73 self::output(wpjam_map(opcache_get_status()['opcache_statistics'], fn($v, $k) => ['title'=>$k, 'value'=>$v])); 74 } 75 76 public static function opcache_usage_widget(){ 77 echo '<p>'.wpjam_get_page_button('reset_opcache').'</p>'; 78 79 echo '<hr />'; 80 81 $status = opcache_get_status(); 82 $args = ['chart_width'=>150, 'table_width'=>320]; 83 84 $labels = ['used_memory'=>'已用内存', 'free_memory'=>'剩余内存', 'wasted_memory'=>'浪费内存']; 85 $counts = wpjam_map($labels, fn($v, $k) => ['label'=>$v, 'count'=>round($status['memory_usage'][$k]/(1024*1024),2)]); 86 $total = round(array_reduce(array_keys($labels), fn($total, $k) => $total+$status['memory_usage'][$k], 0)/(1024*1024),2); 87 88 wpjam_donut_chart($counts, ['title'=>'内存使用', 'total'=>$total]+$args); 89 90 echo '<hr />'; 91 92 $labels = ['hits'=>'命中', 'misses'=>'未命中']; 93 $counts = wpjam_map($labels, fn($v, $k) => ['label'=>$v, 'count'=>$status['opcache_statistics'][$k]]); 94 $total = array_reduce(array_keys($labels), fn($total, $k) => $total+$status['opcache_statistics'][$k], 0); 95 96 wpjam_donut_chart($counts, ['title'=>'命中率', 'total'=>$total]+$args); 97 98 echo '<hr />'; 99 100 $counts = [ 101 ['label'=>'已用Keys', 'count'=>$status['opcache_statistics']['num_cached_keys']], 102 ['label'=>'剩余Keys', 'count'=>$status['opcache_statistics']['max_cached_keys']-$status['opcache_statistics']['num_cached_keys']] 103 ]; 104 105 $total = $status['opcache_statistics']['max_cached_keys']; 106 107 wpjam_donut_chart($counts, ['title'=>'存储Keys','total'=>$total]+$args); 108 109 // echo '<hr />'; 110 111 // $labels = ['used_memory'=>'已用内存', 'free_memory'=>'剩余内存']; 112 // $counts = wpjam_map($labels, fn($v, $k) => ['label'=>$v, 'count'=>round($status['interned_strings_usage'][$k]/(1024*1024),2)]); 113 // $total = round(array_reduce(array_keys($labels), fn($total, $k) => $total+$status['interned_strings_usage'][$k], 0)/(1024*1024),2); 114 115 // wpjam_donut_chart($counts, ['title'=>'临时字符串存储内存','total'=>$total]+$args); 116 } 117 118 public static function opcache_configuration_widget(){ 119 $config = opcache_get_configuration(); 120 $items = wpjam_map($config['version'], fn($v, $k) => ['title'=>$k, 'value'=>$v]); 121 $items = array_merge($items, wpjam_map($config['directives'], fn($v, $k) => ['title'=>str_replace('opcache.', '', $k), 'value'=>$v])); 122 123 self::output($items); 124 } 125 126 public static function memcached_usage_widget(){ 127 global $wp_object_cache; 128 129 echo '<p>'.wpjam_get_page_button('flush_mc').'</p>'; 130 131 foreach($wp_object_cache->get_stats() as $key => $details){ 132 echo '<hr />'; 133 134 $args = ['chart_width'=>150,'table_width'=>320]; 135 $labels = ['get_hits'=>'命中次数', 'get_misses'=>'未命中次数']; 136 $counts = wpjam_map($labels, fn($v, $k) => ['label'=>$v, 'count'=>$details[$k]]); 137 138 wpjam_donut_chart($counts, ['title'=>'命中率','total'=>$details['cmd_get']]+$args); 139 140 echo '<hr />'; 141 142 $counts = [ 143 ['label'=>'已用内存', 'count'=>round($details['bytes']/(1024*1024),2)], 144 ['label'=>'剩余内存', 'count'=>round(($details['limit_maxbytes']-$details['bytes'])/(1024*1024),2)] 145 ]; 146 147 $total = round($details['limit_maxbytes']/(1024*1024),2); 148 149 wpjam_donut_chart($counts, ['title'=>'内存使用','total'=>$total]+$args); 150 } 151 } 152 153 public static function memcached_status_widget(){ 154 global $wp_object_cache; 155 156 foreach($wp_object_cache->get_stats() as $key => $details){ 157 self::output([ 158 // ['title'=>'Memcached进程ID', 'value'=>$details['pid']], 159 ['title'=>'Memcached地址', 'value'=>$key], 160 ['title'=>'Memcached版本', 'value'=>$details['version']], 161 ['title'=>'启动时间', 'value'=>wpjam_date('Y-m-d H:i:s',($details['time']-$details['uptime']))], 162 ['title'=>'运行时间', 'value'=>human_time_diff(0,$details['uptime'])], 163 ['title'=>'已用/分配的内存', 'value'=>size_format($details['bytes']).' / '.size_format($details['limit_maxbytes'])], 164 ['title'=>'启动后总数量', 'value'=>$details['curr_items'].' / '.$details['total_items']], 165 ['title'=>'为获取内存踢除数量', 'value'=>$details['evictions']], 166 ['title'=>'当前/总打开连接数', 'value'=>$details['curr_connections'].' / '.$details['total_connections']], 167 ['title'=>'命中次数', 'value'=>$details['get_hits']], 168 ['title'=>'未命中次数', 'value'=>$details['get_misses']], 169 ['title'=>'总获取请求次数', 'value'=>$details['cmd_get']], 170 ['title'=>'总设置请求次数', 'value'=>$details['cmd_set']], 171 ['title'=>'Item平均大小', 'value'=>size_format($details['bytes']/$details['curr_items'])], 172 ]); 173 } 174 } 175 176 public static function memcached_options_widget(){ 177 global $wp_object_cache; 178 179 $reflector = new ReflectionClass('Memcached'); 180 $constants = wpjam_filter($reflector->getConstants(), fn($v, $k) => str_starts_with($k, 'OPT_')); 181 $mc = $wp_object_cache->get_mc(); 182 183 self::output(wpjam_map($constants, fn($v, $k) => ['title'=>$k, 'value'=>$mc->getOption($v)])); 184 } 185 186 public static function memcached_efficiency_widget(){ 187 global $wp_object_cache; 188 189 foreach($wp_object_cache->get_stats() as $key => $details){ 190 self::output([ 191 ['title'=>'每秒命中次数', 'value'=>round($details['get_hits']/$details['uptime'],2)], 192 ['title'=>'每秒未命中次数', 'value'=>round($details['get_misses']/$details['uptime'],2)], 193 ['title'=>'每秒获取请求次数', 'value'=>round($details['cmd_get']/$details['uptime'],2)], 194 ['title'=>'每秒设置请求次数', 'value'=>round($details['cmd_set']/$details['uptime'],2)], 195 ]); 196 } 197 } 198 199 public static function output($items){ 200 ?> 201 <table class="widefat striped" style="border:none;"> 202 <tbody><?php foreach($items as $item){ ?> 203 <tr><?php if(!empty($item['title'])){ ?> 204 <td><?php echo $item['title'] ?></td> 205 <td><?php echo $item['value'] ?></td> 206 <?php }else{ ?> 207 <td colspan="2"><?php echo $item['value'] ?></td> 208 <?php } ?></tr> 209 <?php } ?></tbody> 210 </table> 211 <?php 159 } 212 160 } 213 161 214 162 public static function get_tabs(){ 215 $tabs['server'] = ['title'=>'服务器', 'function'=>'dashboard', 'widgets'=>[ 216 'server' => ['title'=>'信息', 'callback'=>[self::class, 'server_widget']], 217 'php' => ['title'=>'PHP扩展', 'callback'=>[self::class, 'php_widget']], 218 'version' => ['title'=>'版本', 'callback'=>[self::class, 'version_widget'], 'context'=>'side'], 219 'apache' => ['title'=>'Apache模块', 'callback'=>[self::class, 'apache_widget'], 'context'=>'side'] 220 ]]; 163 $parse = fn($items)=> array_map(fn($v)=> $v+['callback'=>[self::class, 'callback']], $items); 164 $tabs = ['server'=>['title'=>'服务器', 'function'=>'dashboard', 'widgets'=>$parse([ 165 'server' => ['title'=>'信息'], 166 'php' => ['title'=>'PHP扩展'], 167 'version' => ['title'=>'版本', 'context'=>'side'], 168 'apache' => ['title'=>'Apache模块', 'context'=>'side'] 169 ])]]; 221 170 222 171 if(strtoupper(substr(PHP_OS,0,3)) === 'WIN'){ … … 229 178 230 179 if(function_exists('opcache_get_status')){ 231 $tabs['opcache'] = ['title'=>'Opcache', 'function'=>'dashboard', 'widgets'=> [232 'usage' => ['title'=>'使用率' , 'callback'=>[self::class, 'opcache_usage_widget']],233 'status' => ['title'=>'状态' , 'callback'=>[self::class, 'opcache_status_widget']],234 'configuration' => ['title'=>'配置信息', 'c allback'=>[self::class, 'opcache_configuration_widget'], 'context'=>'side']235 ] ];180 $tabs['opcache'] = ['title'=>'Opcache', 'function'=>'dashboard', 'widgets'=>$parse([ 181 'usage' => ['title'=>'使用率'], 182 'status' => ['title'=>'状态'], 183 'configuration' => ['title'=>'配置信息', 'context'=>'side'] 184 ])]; 236 185 237 186 wpjam_register_page_action('reset_opcache', [ … … 245 194 246 195 if(method_exists('WP_Object_Cache', 'get_mc')){ 247 $tabs['memcached'] = ['title'=>'Memcached', 'function'=>'dashboard', 'widgets'=> [248 'usage' => ['title'=>'使用率' , 'callback'=>[self::class, 'memcached_usage_widget']],249 'efficiency' => ['title'=>'效率' , 'callback'=>[self::class, 'memcached_efficiency_widget']],250 'options' => ['title'=>'选项', 'callback'=>[self::class, 'memcached_options_widget'],'context'=>'side'],251 'status' => ['title'=>'状态' , 'callback'=>[self::class, 'memcached_status_widget']]252 ] ];196 $tabs['memcached'] = ['title'=>'Memcached', 'function'=>'dashboard', 'widgets'=>$parse([ 197 'usage' => ['title'=>'使用率'], 198 'efficiency' => ['title'=>'效率'], 199 'options' => ['title'=>'选项', 'context'=>'side'], 200 'status' => ['title'=>'状态'] 201 ])]; 253 202 254 203 wpjam_register_page_action('flush_mc', [ -
wpjam-basic/trunk/components/wpjam-admin.php
r3394812 r3454739 126 126 $args = ['post_type'=>get_post_types(['show_ui'=>true, 'public'=>true, '_builtin'=>false])+['post']]; 127 127 128 wpjam_ map(['posts', 'drafts'], fn($k)=> add_filter('dashboard_recent_'.$k.'_query_args', fn($query_args)=> array_merge($query_args, $args+['cache_results'=>true])));128 wpjam_hooks('dashboard_recent_posts_query_args, dashboard_recent_drafts_query_args', fn($query_args)=> array_merge($query_args, $args+['cache_results'=>true])); 129 129 130 130 add_action('pre_get_comments', fn($query)=> $query->query_vars = array_merge($query->query_vars, $args+['type'=>'comment'])); -
wpjam-basic/trunk/components/wpjam-basic.php
r3436010 r3454739 218 218 219 219 if(self::disabled('privacy', 1)){ 220 add_action('admin_menu', fn()=> array_map(fn($args)=> remove_submenu_page(...$args), [220 add_action('admin_menu', fn()=> wpjam_call_multiple('remove_submenu_page', [ 221 221 ['options-general.php', 'options-privacy.php'], 222 222 ['tools.php', 'export-personal-data.php'], -
wpjam-basic/trunk/components/wpjam-cdn.php
r3356207 r3454739 9 9 public static function get_sections(){ 10 10 $cdn_fields = [ 11 'cdn_name' => ['title'=>'云存储', 'type'=>'select', 'options'=>[''=>'请选择']+ wpjam('cdn')+['disabled'=>['title'=>'切回本站', 'description'=>'当使用 CDN 之后想切换回使用本站图片才勾选该选项,并将原 CDN 域名填到「本地设置」的「额外域名」中。']]],11 'cdn_name' => ['title'=>'云存储', 'type'=>'select', 'options'=>[''=>'请选择']+self::get_items()+['disabled'=>['title'=>'切回本站', 'description'=>'当使用 CDN 之后想切换回使用本站图片才勾选该选项,并将原 CDN 域名填到「本地设置」的「额外域名」中。']]], 12 12 'host' => ['title'=>'CDN 域名', 'type'=>'url', 'description'=>'设置为在CDN云存储绑定的域名。']+self::show_if(), 13 13 'image' => ['title'=>'图片处理', 'class'=>'switch', 'value'=>1, 'label'=>'开启云存储图片处理功能,使用云存储进行裁图、添加水印等操作。<br /><strong>开启之后,文章和媒体库中的所有图片都会镜像到云存储。</strong>']+self::show_if('image'), … … 65 65 ]]+self::show_if('wm'), 66 66 67 'volc_imagex_template' => ['title'=>'火山引擎图片处理模板' ]+self::show_if('volc_imagex')67 'volc_imagex_template' => ['title'=>'火山引擎图片处理模板', 'show_if'=>['cdn_name', 'volc_imagex']] 68 68 ]; 69 69 … … 75 75 76 76 public static function show_if($feature=null){ 77 return ['show_if'=>['cdn_name', isset(wpjam('cdn')[$feature]) ? [$feature] : array_keys(wpjam_filter(wpjam('cdn'), fn($item)=> $feature ? in_array($feature, $item['supports'] ?? []) : true))]];77 return ['show_if'=>['cdn_name', array_keys(array_filter(self::get_items(), fn($v)=> $feature ? in_array($feature, $v['supports'] ?? []) : true))]]; 78 78 } 79 79 … … 86 86 87 87 public static function is_exception($url){ 88 static $exceptions; 89 $exceptions ??= wpjam_lines(self::get_setting('exceptions')); 90 91 return array_any($exceptions, fn($v)=> str_contains($url, $v)); 88 $object = self::get_object(); 89 90 $object->exceptions ??= wpjam_lines(self::get_setting('exceptions')); 91 92 return array_any($object->exceptions, fn($v)=> str_contains($url, $v)); 92 93 } 93 94 … … 201 202 202 203 if(self::get_setting('image')){ 203 $file = wpjam('cdn', CDN_NAME.'.file'); 204 205 if($file && file_exists($file)){ 206 $cb = include $file; 207 $cb !== 1 && is_callable($cb) && add_filter('wpjam_thumbnail', $cb, 10, 2); 208 } 209 210 if(self::get_setting('no_subsizes', 1)){ 211 wpjam_hooks([ 212 ['wp_calculate_image_srcset_meta', fn()=> []], 213 ['embed_thumbnail_image_size', fn()=> '160x120'], 214 ['intermediate_image_sizes_advanced', fn($sizes)=> wpjam_pick($sizes, ['full'])], 215 ['wp_get_attachment_metadata', [self::class, 'filter_metadata'], 10, 2], 216 217 ['wp_img_tag_add_srcset_and_sizes_attr, wp_img_tag_add_width_and_height_attr', fn()=> false] 218 ]); 219 } 220 221 if(self::get_setting('thumbnail', 1)){ 222 wpjam_hooks([ 223 ['render_block_core/image', [self::class, 'filter_image_block'], 5, 2], 224 ['wp_content_img_tag', [self::class, 'filter_img_tag'], 1, 3] 225 ]); 226 } 204 $file = self::get_item(CDN_NAME.'[file]') ?? dirname(__DIR__).'/cdn'.'/'.CDN_NAME.'.php'; 205 206 $file && file_exists($file) && ($cb = include $file) && is_callable($cb) && add_filter('wpjam_thumbnail', $cb, 10, 2); 207 208 self::get_setting('no_subsizes', 1) && wpjam_hooks([ 209 ['wp_calculate_image_srcset_meta', fn()=> []], 210 ['embed_thumbnail_image_size', fn()=> '160x120'], 211 ['intermediate_image_sizes_advanced', fn($sizes)=> wpjam_pick($sizes, ['full'])], 212 ['wp_get_attachment_metadata', [self::class, 'filter_metadata'], 10, 2], 213 214 ['wp_img_tag_add_srcset_and_sizes_attr, wp_img_tag_add_width_and_height_attr', fn()=> false] 215 ]); 216 217 self::get_setting('thumbnail', 1) && wpjam_hooks([ 218 ['render_block_core/image', [self::class, 'filter_image_block'], 5, 2], 219 ['wp_content_img_tag', [self::class, 'filter_img_tag'], 1, 3] 220 ]); 227 221 228 222 wpjam_hooks([ … … 242 236 } 243 237 244 if(!wpjam_basic_get_setting('upload_external_images') && self::get_setting('remote') && !is_multisite()){ 245 include dirname(__DIR__).'/cdn/remote.php'; 246 } 238 self::get_setting('remote') && !wpjam_basic_get_setting('upload_external_images') && !is_multisite() && (include dirname(__DIR__).'/cdn/remote.php'); 247 239 } 248 240 249 241 public static function add_hooks(){ 250 wpjam_map([242 self::add_items([ 251 243 'aliyun_oss' => [ 252 244 'title' => '阿里云OSS', … … 269 261 ], 270 262 'ucloud' => ['title'=>'UCloud'] 271 ], fn($v, $k)=> wpjam('cdn', $k, $v+['file'=>dirname(__DIR__).'/cdn'.'/'.$k.'.php'])); 272 273 if(self::get_setting('disabled')){ 274 self::update_setting('cdn_name', 'disabled'); 275 self::delete_setting('disabled'); 276 } 277 278 if(self::get_setting('image') && !self::get_setting('img_exts')){ 279 self::update_setting('img_exts', 1); 280 } 263 ]); 281 264 282 265 add_action('plugins_loaded', [self::class, 'on_plugins_loaded'], 99); … … 285 268 286 269 function wpjam_register_cdn($name, $args){ 287 return wpjam('cdn',$name, $args);270 return WPJAM_CDN::add_item($name, $args); 288 271 } 289 272 290 273 function wpjam_unregister_cdn($name){ 291 return wpjam('cdn[]', $name, null);274 return WPJAM_CDN::delete_item($name); 292 275 } 293 276 -
wpjam-basic/trunk/components/wpjam-custom.php
r3356207 r3454739 47 47 if($value = get_post_meta(get_the_ID(), 'custom_'.$name, true)){ 48 48 if($name == 'head'){ 49 add_action('wp_'.$name, fn()=> wpjam_echo($value), 99);49 wpjam_hook('echo', 'wp_'.$name, fn()=> $value, 99); 50 50 }else{ 51 51 echo $value; -
wpjam-basic/trunk/components/wpjam-enhance.php
r3423058 r3454739 4 4 Version: 2.0 5 5 */ 6 class WPJAM_Enhance {6 class WPJAM_Enhance extends WPJAM_Option_Model{ 7 7 public static function get_section(){ 8 8 $options = array_column(get_taxonomies(['public'=>true, 'hierarchical'=>true], 'objects'), 'label', 'name'); … … 23 23 add_filter('wp_update_attachment_metadata', fn($data)=> (isset($data['thumb']) ? ['thumb'=>basename($data['thumb'])] : [])+$data); 24 24 25 $options = wpjam_basic_get_setting('x-frame-options');25 $options = self::get_setting('x-frame-options'); 26 26 $options && add_action('send_headers', fn()=> header('X-Frame-Options: '.$options)); 27 27 28 28 // 防止重名造成大量的 SQL 29 if( wpjam_basic_get_setting('timestamp_file_name')){29 if(self::get_setting('timestamp_file_name')){ 30 30 wpjam_hooks('wp_handle_sideload_prefilter, wp_handle_upload_prefilter', fn($file)=> array_merge($file, empty($file['md5_filename']) ? ['name'=> time().'-'.$file['name']] : [])); 31 31 } 32 32 33 if( wpjam_basic_get_setting('no_category_base')){34 $tax = wpjam_basic_get_setting('no_category_base_for', 'category');33 if(self::get_setting('no_category_base')){ 34 $tax = self::get_setting('no_category_base_for', 'category'); 35 35 36 36 $tax == 'category' && str_starts_with($_SERVER['REQUEST_URI'], '/category/') && add_action('template_redirect', fn()=> wp_redirect(site_url(substr($_SERVER['REQUEST_URI'], 10)), 301)); … … 41 41 } 42 42 43 class WPJAM_Gravatar {43 class WPJAM_Gravatar extends WPJAM_Option_Model{ 44 44 public static function get_fields(){ 45 45 return ['gravatar'=>['title'=>'Gravatar加速', 'label'=>true, 'type'=>'fieldset', 'fields'=>[ 46 'gravatar'=>['after'=>'加速服务', 'options'=>wpjam_options( 'gravatar')+['custom'=>[46 'gravatar'=>['after'=>'加速服务', 'options'=>wpjam_options(self::get_items(), ['type'=>'select'])+['custom'=>[ 47 47 'title' => '自定义', 48 48 'fields' => ['gravatar_custom'=>['placeholder'=>'请输入 Gravatar 加速服务地址']] … … 77 77 } 78 78 79 $name = wpjam_basic_get_setting('gravatar');80 $value = $name == 'custom' ? wpjam_basic_get_setting('gravatar_custom') : ($name ? wpjam('gravatar', $name.'.url') : '');79 $name = self::get_setting('gravatar'); 80 $value = $name == 'custom' ? self::get_setting('gravatar_custom') : ($name ? self::get_item($name.'[url]') : ''); 81 81 82 82 $value && add_filter('get_avatar_url', fn($url)=> str_replace(array_map(fn($v)=>$v.'gravatar.com/avatar/', ['https://secure.', 'http://0.', 'http://1.', 'http://2.']), $value, $url)); … … 86 86 87 87 public static function add_hooks(){ 88 wpjam_map([88 self::add_items([ 89 89 'geekzu' => ['title'=>'极客族', 'url'=>'https://sdn.geekzu.org/avatar/'], 90 90 'loli' => ['title'=>'loli', 'url'=>'https://gravatar.loli.net/avatar/'], … … 92 92 '7ed' => ['title'=>'7ED', 'url'=>'https://use.sevencdn.com/avatar/'], 93 93 'cravatar' => ['title'=>'Cravatar', 'url'=>'https://cravatar.cn/avatar/'], 94 ] , fn($v, $k)=> wpjam('gravatar', $k, $v));94 ]); 95 95 96 96 add_filter('pre_get_avatar_data', [self::class, 'filter_pre_data'], 10, 2); … … 98 98 } 99 99 100 class WPJAM_Google_Font {100 class WPJAM_Google_Font extends WPJAM_Option_Model{ 101 101 public static function get_search(){ 102 102 return [ … … 110 110 public static function get_fields(){ 111 111 return ['google_fonts'=>['title'=>'Google字体加速', 'type'=>'fieldset', 'label'=>true, 'fields'=>[ 112 'google_fonts'=>['type'=>'select', 'after'=>'加速服务', 'options'=>wpjam_options( 'google_font')+['custom'=>[112 'google_fonts'=>['type'=>'select', 'after'=>'加速服务', 'options'=>wpjam_options(self::get_items(), ['type'=>'select'])+['custom'=>[ 113 113 'title' => '自定义', 114 114 'fields' => wpjam_map(self::get_search(), fn($v)=> ['placeholder'=>'请输入'.str_replace('//', '', $v).'加速服务地址']) … … 118 118 119 119 public static function add_hooks(){ 120 wpjam_map([120 self::add_items([ 121 121 'geekzu' => [ 122 122 'title' => '极客族', … … 131 131 'replace' => ['//fonts.lug.ustc.edu.cn', '//ajax.lug.ustc.edu.cn', '//google-themes.lug.ustc.edu.cn', '//fonts-gstatic.lug.ustc.edu.cn'] 132 132 ] 133 ] , fn($v, $k)=> wpjam('google_font', $k, $v));133 ]); 134 134 135 135 $search = self::get_search(); 136 $name = wpjam_basic_get_setting('google_fonts');137 $value = $name == 'custom' ? wpjam_map($search, fn($v, $k)=> str_replace(['http://','https://'], '//', wpjam_basic_get_setting($k) ?: $v)) : ($name ? wpjam('google_font', $name.'.replace') : '');136 $name = self::get_setting('google_fonts'); 137 $value = $name == 'custom' ? wpjam_map($search, fn($v, $k)=> str_replace(['http://','https://'], '//', self::get_setting($k) ?: $v)) : ($name ? self::get_item($name.'[replace]') : ''); 138 138 139 139 $value && add_filter('wpjam_html', fn($html)=> str_replace($search, $value, $html)); … … 141 141 } 142 142 143 class WPJAM_Static_CDN {144 public static function get_ setting(){145 $hosts = wpjam('static_cdn');146 $host = wpjam_basic_get_setting('static_cdn');143 class WPJAM_Static_CDN extends WPJAM_Option_Model{ 144 public static function get_value(){ 145 $hosts = self::get_items(); 146 $host = self::get_setting('static_cdn'); 147 147 148 148 return $host && in_array($host, $hosts) ? $host : $hosts[0]; … … 150 150 151 151 public static function get_fields(){ 152 return ['static_cdn'=>['title'=>'前端公共库', 'options'=>wpjam_fill( wpjam('static_cdn'), fn($v)=> parse_url($v, PHP_URL_HOST))]];152 return ['static_cdn'=>['title'=>'前端公共库', 'options'=>wpjam_fill(self::get_items(), fn($v)=> parse_url($v, PHP_URL_HOST))]]; 153 153 } 154 154 155 155 public static function add_hooks(){ 156 wpjam_map([156 self::add_items([ 157 157 'https://cdnjs.cloudflare.com/ajax/libs', 158 158 'https://s4.zstatic.net/ajax/libs', … … 161 161 'https://cdnjs.loli.net/ajax/libs', 162 162 'https://use.sevencdn.com/ajax/libs', 163 ] , fn($v)=> wpjam('static_cdn[]', $v));163 ]); 164 164 165 $host = self::get_ setting();166 $hosts = array_diff( wpjam('static_cdn'), [$host]);165 $host = self::get_value(); 166 $hosts = array_diff(self::get_items(), [$host]); 167 167 168 168 foreach(['style', 'script'] as $type){ … … 182 182 183 183 function wpjam_register_gravatar($name, $args){ 184 return wpjam('gravatar',$name, $args);184 return WPJAM_Gravatar::add_item($name, $args); 185 185 } 186 186 187 187 function wpjam_register_google_font($name, $args){ 188 return wpjam('google_font',$name, $args);188 return WPJAM_Google_Font::add_item($name, $args); 189 189 } 190 190 191 191 function wpjam_add_static_cdn($host){ 192 return wpjam('static_cdn[]',$host);192 return WPJAM_Static_CDN::add_item($host); 193 193 } 194 194 195 195 function wpjam_get_static_cdn(){ 196 return WPJAM_Static_CDN::get_ setting();196 return WPJAM_Static_CDN::get_value(); 197 197 } -
wpjam-basic/trunk/components/wpjam-thumbnail.php
r3423058 r3454739 47 47 public static function get_default(){ 48 48 $default = self::get_setting('default', []); 49 $default = ($default && is_array($default)) ? $default[array_rand($default)] : '';49 $default = $default && is_array($default) ? $default[array_rand($default)] : ''; 50 50 51 51 return apply_filters('wpjam_default_thumbnail_url', $default); -
wpjam-basic/trunk/extends/mobile-theme.php
r3356207 r3454739 6 6 Version: 2.0 7 7 */ 8 class WPJAM_Mobile_Stylesheet {8 class WPJAM_Mobile_Stylesheet extends WPJAM_Option_Model{ 9 9 public static function get_fields(){ 10 10 $themes = array_map(fn($v)=> $v->get('Name'), wp_get_themes(['allowed'=>true])); … … 14 14 } 15 15 16 public static function builtin_page_load(){17 $mobile = wpjam_basic_get_setting('mobile_stylesheet');16 public static function load(){ 17 $mobile = self::get_setting('mobile_stylesheet'); 18 18 $button = wpjam_register_page_action('set_mobile_stylesheet', [ 19 19 'button_text' => '移动主题', … … 22 22 'confirm' => true, 23 23 'response' => 'redirect', 24 'callback' => fn()=> WPJAM_Basic::update_setting('mobile_stylesheet', wpjam_get_data_parameter('stylesheet'))24 'callback' => fn()=> self::update_setting('mobile_stylesheet', wpjam_get_data_parameter('stylesheet')) 25 25 ])->get_button(['data'=>['stylesheet'=>'slug']]); 26 26 … … 41 41 42 42 public static function add_hooks(){ 43 $name = wp_is_mobile() ? wpjam_basic_get_setting('mobile_stylesheet') : null;43 $name = wp_is_mobile() ? self::get_setting('mobile_stylesheet') : null; 44 44 $name = $name ?: ($_GET['wpjam_theme'] ?? null); 45 45 $theme = $name ? wp_get_theme($name) : null; … … 50 50 51 51 wpjam_add_option_section('wpjam-basic', 'enhance', ['model'=>'WPJAM_Mobile_Stylesheet', 'admin_load'=>['base'=>'themes']]); 52 -
wpjam-basic/trunk/extends/quick-excerpt.php
r3356207 r3454739 27 27 } 28 28 29 add_filter('wp_insert_post_data', fn($data)=> isset($_POST['the_excerpt']) ? wpjam_set($data, 'post_excerpt', $_POST['the_excerpt']) : $data);29 isset($_POST['the_excerpt']) && add_filter('wp_insert_post_data', fn($data)=> wpjam_set($data, 'post_excerpt', $_POST['the_excerpt'])); 30 30 31 add_action('add_inline_data', fn($post)=> wpjam_echo('<div class="post_excerpt">'.esc_textarea(trim($post->post_excerpt)).'</div>'));31 wpjam_hook('echo', 'add_inline_data', fn($post)=> '<div class="post_excerpt">'.esc_textarea(trim($post->post_excerpt)).'</div>'); 32 32 } 33 33 } -
wpjam-basic/trunk/extends/wpjam-roles.php
r3423058 r3454739 126 126 add_filter('additional_capabilities_display', '__return_false' ); 127 127 128 wpjam_map(['show', 'edit'], fn($v)=> add_action($v.'_user_profile', fn($user)=> wpjam_echo('<h3>额外权限</h3>'.self::get_additional($user, 'fields'))));128 wpjam_map(['show', 'edit'], fn($v)=> wpjam_hook('echo', $v.'_user_profile', fn($user)=> '<h3>额外权限</h3>'.self::get_additional($user, 'fields'))); 129 129 130 130 wpjam_map(['personal_options_update', 'edit_user_profile_update'], fn($v)=> add_action($v, fn($id)=> self::set_additional($id, wpjam_get_post_parameter('capabilities') ?: []))); -
wpjam-basic/trunk/extends/wpjam-seo.php
r3356207 r3454739 171 171 public static function add_hooks(){ 172 172 if(self::get_setting('unique')){ 173 add_filter('wpjam_html', [self::class, 'filter_html']);174 }else{ 175 add_action('wp_head', fn()=> wpjam_echo(implode(self::get_value('meta'))));173 add_filter('wpjam_html', [self::class, 'filter_html']); 174 }else{ 175 wpjam_hook('echo', 'wp_head', fn()=> implode(self::get_value('meta'))); 176 176 } 177 177 -
wpjam-basic/trunk/extends/wpjam-toc.php
r3436010 r3454739 7 7 */ 8 8 class WPJAM_Toc extends WPJAM_Option_Model{ 9 private static $toc = [];10 11 9 public static function get_fields(){ 12 10 $fields = array_filter([ … … 28 26 $path = []; 29 27 30 foreach(self:: $tocas $item){28 foreach(self::get_items() as $item){ 31 29 $depth = $item['depth']; 32 30 … … 48 46 } 49 47 50 public static function add_item($m, $index=false){48 public static function callback($m, $index=false, $added=false){ 51 49 $attr = $m[2] ? shortcode_parse_atts($m[2]) : []; 52 50 $attr = wp_parse_args($attr, ['class'=>'', 'id'=>'']); … … 54 52 if(!$attr['class'] || !str_contains($attr['class'], 'toc-noindex')){ 55 53 $attr['class'] = wpjam_join(' ', $attr['class'], ($index ? 'toc-index' : '')); 56 $attr['id'] = $attr['id'] ?: 'toc_'.(count(self::$toc)+1); 57 self::$toc[] = ['text'=>trim(strip_tags($m[3])), 'depth'=>$m[1], 'id'=>$attr['id']]; 54 $attr['id'] = $attr['id'] ?: 'toc_'.(count(self::get_items())+1); 55 56 $added || self::add_item(['text'=>trim(strip_tags($m[3])), 'depth'=>$m[1], 'id'=>$attr['id']]); 58 57 } 59 58 … … 75 74 76 75 if($depth){ 77 self::$toc = [];76 $added = (bool)self::get_items(); 78 77 $index = str_contains($content, '[toc]'); 79 $position = self::get_setting('position', 'content'); 80 $content = wpjam_preg_replace('#<h([1-'.$depth.'])\b([^>]*)>(.*?)</h\1>#', fn($m)=> self::add_item($m, $index), $content); 78 $content = wpjam_preg_replace('#<h([1-'.$depth.'])\b([^>]*)>(.*?)</h\1>#', fn($m)=> self::callback($m, $index, $added), $content); 81 79 82 80 if($index){ 83 81 return str_replace('[toc]', self::render(), $content); 84 }elseif( $position== 'content'){82 }elseif(self::get_setting('position', 'content') == 'content'){ 85 83 return self::render().$content; 86 84 } -
wpjam-basic/trunk/includes/class-wpjam-admin.php
r3440469 r3454739 20 20 21 21 $msg && $type && $this->update_arg('error[]', compact('msg', 'type')); 22 }23 24 public function chart($method, ...$args){25 if(is_object($method)){26 return $this->chart = $method;27 }28 29 return $this->chart ? $this->chart->$method(...$args) : null;30 22 } 31 23 … … 44 36 } 45 37 46 public function load($screen=''){ 47 if($screen){ 48 if($screen->base == 'post'){ 49 $this->post_id = (int)($_GET['post'] ?? ($_POST['post_ID'] ?? 0)); 50 } 51 38 public function load(...$args){ 39 if(count($args) >= 2){ 40 $map = ['builtin_page'=>'base', 'plugin_page'=>'plugin_page']; 41 $type = $args[0] ?? array_find_key($map, fn($v)=> isset($args[1][$v])); 42 43 return isset($map[$type]) && $this->update_arg($type.'_load[]', $args[1]); 44 } 45 46 if($screen = array_shift($args)){ 52 47 $this->screen = $screen; 53 48 $this->vars = ['screen_id'=>$screen->id]+array_filter(wpjam_pick($screen, ['post_type', 'taxonomy'])); 49 50 $screen->base == 'post' && ($this->post_id = (int)($_GET['post'] ?? ($_POST['post_ID'] ?? 0))); 54 51 } 55 52 … … 466 463 } 467 464 468 $this->chart && wpjam_ admin('chart', WPJAM_Chart::get_instance($this->chart));465 $this->chart && wpjam_chart(is_array($this->chart) ? $this->chart : []); 469 466 $this->editor && add_action('admin_footer', 'wp_enqueue_editor'); 470 467 … … 505 502 }else{ 506 503 $function = $this->function ?: wpjam_get_filter_name($this->name, 'page'); 507 $this->render = is_callable($function) ? fn()=> wpjam_ admin('chart','render').wpjam_ob($function) : $this->throw('页面函数'.'「'.$function.'」未定义。');504 $this->render = is_callable($function) ? fn()=> wpjam_chart('render').wpjam_ob($function) : $this->throw('页面函数'.'「'.$function.'」未定义。'); 508 505 } 509 506 } … … 754 751 755 752 class WPJAM_Chart extends WPJAM_Args{ 756 public function get_parameter($key, $args=[]){ 757 if(str_contains($key, 'timestamp')){ 758 return wpjam_strtotime($this->get_parameter(str_replace('timestamp', 'date', $key), $args).' '.(str_starts_with($key, 'end_') ? '23:59:59' : '00:00:00')); 759 } 760 761 $data = $args['data'] ?? null; 762 $method = $args['method'] ?? $this->method; 763 $value = (is_array($data) && !empty($data[$key])) ? $data[$key] : wpjam_get_parameter($key, ['method'=>$method]); 764 765 if($value){ 766 wpjam_set_cookie($key, $value, HOUR_IN_SECONDS); 767 768 return $value; 769 } 770 771 if(!empty($_COOKIE[$key])){ 772 return $_COOKIE[$key]; 773 } 774 775 if($key == 'date_format' || $key == 'date_type'){ 776 return '%Y-%m-%d'; 777 }elseif($key == 'compare'){ 778 return 0; 779 }elseif(str_contains($key, 'date')){ 780 if($key == 'start_date'){ 781 $ts = time() - DAY_IN_SECONDS*30; 782 }elseif($key == 'end_date'){ 783 $ts = time(); 784 }elseif($key == 'date'){ 785 $ts = time() - DAY_IN_SECONDS; 786 }elseif($key == 'start_date_2'){ 787 $ts = $this->get_parameter('end_timestamp_2') - ($this->get_parameter('end_timestamp') - $this->get_parameter('start_timestamp')); 788 }elseif($key == 'end_date_2'){ 789 $ts = $this->get_parameter('start_timestamp') - DAY_IN_SECONDS; 790 } 791 792 return wpjam_date('Y-m-d', $ts); 793 } 794 } 795 796 public function get_fields($args=[]){ 797 if($this->show_start_date){ 798 $fields['date'] = ['sep'=>' ', 'fields'=>[ 799 'start_date' => ['type'=>'date', 'value'=>$this->get_parameter('start_date', $args)], 800 'date_view' => ['type'=>'view', 'value'=>'-'], 801 'end_date' => ['type'=>'date', 'value'=>$this->get_parameter('end_date', $args)] 802 ]]; 803 }elseif($this->show_date){ 804 $fields['date'] = ['sep'=>' ', 'fields'=>[ 805 'prev_day' => ['type'=>'button', 'value'=>'‹', 'class'=>'button prev-day'], 806 'date' => ['type'=>'date', 'value'=>$this->get_parameter('date', $args)], 807 'next_day' => ['type'=>'button', 'value'=>'›', 'class'=>'button next-day'] 808 ]]; 809 } 810 811 if(isset($fields['date']) && !empty($args['show_title'])){ 812 $fields['date']['title'] = '日期'; 813 } 814 815 if($this->show_date_type){ 816 $fields['date_format'] = ['type'=>'select','value'=>$this->get_parameter('date_format', $args), 'options'=>[ 817 '%Y-%m' => '按月', 818 '%Y-%m-%d' => '按天', 819 // '%Y%U' => '按周', 820 '%Y-%m-%d %H:00' => '按小时', 821 '%Y-%m-%d %H:%i' => '按分钟', 822 ]]; 823 } 824 825 return $fields; 826 } 827 828 public function get_data($args=[]){ 829 $keys = $this->show_start_date ? ['start_date', 'end_date'] : ($this->show_date ? ['date'] : []); 830 831 return wpjam_fill($keys, fn($k)=> $this->get_parameter($k, $args)); 753 public function validate($data){ 754 $fields = wpjam_fields($this->get_fields(['data'=>$data])); 755 756 return $fields->validate($data+$fields->get_defaults()); 832 757 } 833 758 … … 869 794 } 870 795 871 public static function line($args=[], $type='Line'){ 872 $args += [ 873 'data' => [], 874 'labels' => [], 875 'day_labels' => [], 876 'day_label' => '时间', 877 'day_key' => 'day', 878 'chart_id' => 'daily-chart', 879 'show_table' => true, 880 'show_chart' => true, 881 'show_sum' => true, 882 'show_avg' => true, 883 ]; 884 885 foreach($args['labels'] as $k => $v){ 796 public function get_parameter($key, $args=[]){ 797 if(is_array($key)){ 798 return wpjam_fill($key, fn($k)=> $this->get_parameter($k, $args)); 799 } 800 801 if(str_contains($key, 'timestamp')){ 802 return wpjam_strtotime($this->get_parameter(str_replace('timestamp', 'date', $key), $args).' '.(str_starts_with($key, 'end_') ? '23:59:59' : '00:00:00')); 803 } 804 805 $value = ($args['data'][$key] ?? '') ?: wpjam_get_parameter($key, ['method'=>($args['method'] ?? $this->method)]); 806 $value && wpjam_set_cookie($key, $value, HOUR_IN_SECONDS); 807 808 if(!empty($_COOKIE[$key])){ 809 return $_COOKIE[$key]; 810 } 811 812 if($key == 'date_format' || $key == 'date_type'){ 813 return '%Y-%m-%d'; 814 }elseif($key == 'compare'){ 815 return 0; 816 } 817 818 if($key == 'date'){ 819 $ts = time() - DAY_IN_SECONDS; 820 }elseif($key == 'start_date'){ 821 $ts = time() - DAY_IN_SECONDS*30; 822 }elseif($key == 'end_date'){ 823 $ts = time(); 824 }elseif($key == 'start_date_2'){ 825 $ts = $this->get_parameter('end_timestamp_2') - ($this->get_parameter('end_timestamp') - $this->get_parameter('start_timestamp')); 826 }elseif($key == 'end_date_2'){ 827 $ts = $this->get_parameter('start_timestamp') - DAY_IN_SECONDS; 828 } 829 830 return isset($ts) ? wpjam_date('Y-m-d', $ts) : null; 831 } 832 833 public function get_fields($args=[]){ 834 $fields = $this->show_start_date ? [ 835 'start_date'=> ['type'=>'date'], 836 'date_view' => ['type'=>'view', 'value'=>'-'], 837 'end_date' => ['type'=>'date'] 838 ] : ($this->show_date ? [ 839 'prev_day' => ['type'=>'button', 'value'=>'‹', 'class'=>'button prev-day'], 840 'date' => ['type'=>'date'], 841 'next_day' => ['type'=>'button', 'value'=>'›', 'class'=>'button next-day'] 842 ] : []); 843 844 $fields = $fields ? ['date'=>['sep'=>' ', 'fields'=>wpjam_map($fields, fn($v, $k)=> ['value'=>($v['value'] ?? $this->get_parameter($k, $args))]+$v)]+(empty($args['show_title']) ? ['title'=>'日期'] : [])] : []; 845 846 return $fields+($this->show_date_type ? ['date_format'=>['type'=>'select','value'=>$this->get_parameter('date_format', $args), 'options'=>[ 847 '%Y-%m' => '按月', 848 '%Y-%m-%d' => '按天', 849 // '%Y%U' => '按周', 850 '%Y-%m-%d %H:00' => '按小时', 851 '%Y-%m-%d %H:%i' => '按分钟', 852 ]]] : []); 853 } 854 855 public static function line($data, $args=[], $type='Line'){ 856 foreach(($args['labels'] ?? []) as $k => $v){ 886 857 if(is_array($v)){ 887 $ args['columns'][$k] = $v['label'];888 889 if( !isset($v['show_in_chart']) || $v['show_in_chart']){858 $columns[$k] = $v['label']; 859 860 if($v['show_in_chart'] ?? true){ 890 861 $labels[$k] = $v['label']; 891 862 } … … 895 866 } 896 867 }else{ 897 $args['columns'][$k] = $labels[$k] = $v; 898 } 899 } 900 901 $parser = fn($item)=> empty($cbs) ? $item : array_merge($item, array_map(fn($cb)=> $cb($item), $cbs)); 902 $data = $total = []; 903 904 if($args['show_table']){ 905 $args['day_labels'] += ['sum'=>'累加', 'avg'=>'平均']; 906 907 $row = self::row('head', [], $args); 908 $thead = wpjam_tag('thead')->append($row); 909 $tfoot = wpjam_tag('tfoot')->append($row); 910 $tbody = wpjam_tag('tbody'); 911 } 912 913 foreach($args['data'] as $day => $item){ 914 $item = $parser((array)$item); 915 $day = $item[$args['day_key']] ?? $day; 916 $total = wpjam_map($args['columns'], fn($v, $k)=> ($total[$k] ?? 0)+((isset($item[$k]) && is_numeric($item[$k])) ? $item[$k] : 0)); 917 $data[] = array_merge([$args['day_key']=> $day], array_intersect_key($item, $labels)); 918 919 $args['show_table'] && $tbody->append(self::row($day, $item, $args)); 920 } 921 868 $columns[$k] = $labels[$k] = $v; 869 } 870 } 871 872 $xkey = $args['day_key'] ?? 'day'; 873 $ykeys = array_keys($labels); 874 $data += ($args['show_table'] ?? true) && $data ? ['total' => array_fill_keys($ykeys, 0)] : []; 875 876 foreach($data as $day => &$item){ 877 $item = isset($cbs) ? array_merge((array)$item, array_map(fn($cb)=> $cb($item), $cbs)) : $item; 878 879 if($day !== 'total'){ 880 $item[$xkey] ??= $day; 881 882 if(isset($data['total'])){ 883 $data['total'] = wpjam_map($data['total'], fn($v, $k)=> $v+(is_numeric($item[$k] ?? null) ? $item[$k] : 0)); 884 $rows[$item[$xkey]] = $item; 885 } 886 887 $item = wpjam_pull($item, [...$ykeys, $xkey]); 888 } 889 } 890 891 $total = wpjam_pull($data, 'total'); 922 892 $tag = wpjam_tag(); 923 893 924 $args['show_chart'] && $data && wpjam_tag('div', ['id'=>$args['chart_id']])->data(['chart'=>true, 'type'=>$type, 'options'=>['data'=>$data, 'xkey'=>$args['day_key'], 'ykeys'=>array_keys($labels), 'labels'=>array_values($labels)]])->append_to($tag); 925 926 if($args['show_table'] && $args['data']){ 927 $total = $parser($total); 928 929 $args['show_sum'] && $tbody->append(self::row('sum', $total, $args)); 930 $args['show_avg'] && $tbody->append(self::row('avg', array_map(fn($v)=> is_numeric($v) ? round($v/count($args['data'])) : '', $total), $args)); 931 932 $thead->after([$tbody, $tfoot])->wrap('table', ['class'=>'wp-list-table widefat striped'])->append_to($tag); 894 if($args['show_chart'] ?? true){ 895 $tag->append(wpjam_tag('div', [ 896 'id' => $args['chart_id'] ?? 'daily-chart', 897 'data' => ['type'=>$type, 'chart'=>true, 'options'=>['data'=>$data, 'xkey'=>$xkey, 'ykeys'=>$ykeys, 'labels'=>array_values($labels)]] 898 ])); 899 } 900 901 if($total && $data){ 902 $labels = ($args['day_labels'] ?? [])+['sum'=>'累加', 'avg'=>'平均']; 903 $columns = [$xkey => $args['day_label'] ?? '时间']+$columns; 904 $th = wpjam_tag('tr')->append(wpjam_map($columns, fn($col, $id)=> wpjam_tag('th', ['scope'=>'col', 'id'=>$id], $col))); 905 $rows += ($args['show_sum'] ?? true) ? ['sum'=>$total] : []; 906 $rows += ($args['show_avg'] ?? true) ? ['avg'=>array_map(fn($v)=> is_numeric($v) ? round($v/count($data)) : '', $total)] : []; 907 $rows = wpjam_map($rows, fn($row, $k)=> wpjam_tag('tr')->append(wpjam_map($columns, fn($col, $id)=> wpjam_tag('td', [ 908 'data' => ['colname'=>$col], 909 'class' => ['column-'.$id, ($id == $xkey ? 'column-primary' : '')] 910 ])->append($id == $xkey ? [($labels[$k] ?? $k), wpjam_tag('button', ['class'=>'toggle-row'])] : ($row[$id] ?? ''))))); 911 912 $tag->append(wpjam_tag('table', ['class'=>'wp-list-table widefat striped'])->append([ 913 wpjam_tag('thead')->append($th), 914 wpjam_tag('tbody')->append($rows), 915 wpjam_tag('tfoot')->append($th) 916 ])); 933 917 } 934 918 … … 936 920 } 937 921 938 public static function donut($args=[]){ 939 $args += [ 940 'data' => [], 941 'total' => 0, 942 'title' => '名称', 943 'key' => 'type', 944 'chart_id' => 'chart_'.wp_generate_password(6, false, false), 945 'show_table' => true, 946 'show_chart' => true, 947 'show_line_num' => false, 948 'labels' => [] 949 ]; 950 951 if($args['show_table']){ 952 $thead = wpjam_tag('thead')->append(self::row('head', '', $args)); 953 $tbody = wpjam_tag('tbody'); 954 } 955 956 foreach(array_values($args['data']) as $i => $item){ 957 $label = $item['label'] ?? '/'; 958 $label = $args['labels'][$label] ?? $label; 959 $value = $item['count']; 960 $data[] = ['label'=>$label, 'value'=>$value]; 961 962 $args['show_table'] && $tbody->append(self::row($i+1, $value, ['label'=>$label]+$args)); 963 } 964 965 $tag = wpjam_tag(); 966 967 $args['show_chart'] && $tag->append('div', ['id'=>$args['chart_id'], 'data'=>['chart'=>true, 'type'=>'Donut', 'options'=>['data'=>$data ?? []]]]); 968 969 if($args['show_table']){ 970 $args['total'] && $tbody->append(self::row('total', $args['total'], $args+['label'=>'所有'])); 971 972 $tag->append('table', ['wp-list-table', 'widefat', 'striped'], implode('', [$thead, $tbody])); 973 } 974 975 return $tag->wrap('div', ['class'=>'donut-chart-wrap']); 976 } 977 978 protected static function row($key, $data=[], $args=[]){ 979 $row = wpjam_tag('tr'); 980 981 if(is_array($data)){ 982 $day_key = $args['day_key']; 983 $columns = [$day_key=>$args['day_label']]+$args['columns']; 984 $data = [$day_key=>$args['day_labels'][$key] ?? $key]+$data; 985 986 foreach($columns as $col => $column){ 987 $cell = wpjam_tag(...($key == 'head' ? ['th', ['scope'=>'col', 'id'=>$col], $column] : ['td', ['data'=>['colname'=>$column]], $data[$col] ?? ''])); 988 989 $col == $day_key && $cell->add_class('column-primary')->append('button', ['class'=>'toggle-row']); 990 $cell->add_class('column-'.$col)->append_to($row); 991 } 992 }else{ 993 $row->append($key == 'head' ? [ 994 $args['show_line_num'] ? ['th', ['style'=>'width:40px;'], '排名'] : '', 995 ['th', [], $args['title']], 996 ['th', [], '数量'], 997 $args['total'] ? ['th', [], '比例'] : '' 998 ] : [ 999 $args['show_line_num'] ? ['td', [], $key == 'total' ? '' : $key] : '', 1000 ['td', [], $args['label']], 1001 ['td', [], $data], 1002 $args['total'] ? ['td', [], round($data / $args['total'] * 100, 2).'%'] : '' 922 public static function bar($data, $args=[]){ 923 return self::line($data, $args, 'Bar'); 924 } 925 926 public static function donut($data, $args=[]){ 927 $tag = wpjam_tag('div', ['class'=>'donut-chart-wrap']); 928 $data = wpjam_array($data, fn($k, $v)=> [null, [ 929 'label' => !empty($v['label']) ? ($args['labels'][$v['label']] ?? $v['label']) : '/', 930 'value' => $v['count'] 931 ]]); 932 933 if($args['show_chart'] ?? true){ 934 $tag->append('div', [ 935 'id' => $args['chart_id'] ?? 'chart_'.wp_generate_password(6, false, false), 936 'data' => ['type'=>'Donut', 'chart'=>true, 'options'=>['data'=>$data]] 1003 937 ]); 1004 938 } 1005 939 1006 return $row; 1007 } 1008 1009 public static function create_instance(){ 940 if(($args['show_table'] ?? true) && $data){ 941 $columns = (!empty($args['show_line_num']) ? ['no'=>'排名'] : [])+['label'=>$args['title'] ?? '名称', 'value'=>'数量']; 942 943 if($total = $args['total'] ?? false){ 944 $total = $total === true ? array_sum(array_column($data, 'value')) : $total; 945 $data += ['total'=>['label'=>'所有', 'value'=>$total]]; 946 $columns += ['rate'=>'比例']; 947 } 948 949 $tag->append(wpjam_tag('table', ['wp-list-table', 'widefat', 'striped'])->append([ 950 wpjam_tag('thead')->append(wpjam_tag('tr')->append(wpjam_map($columns, fn($col, $id)=> wpjam_tag('th', ['scope'=>'col', 'id'=>$id], $col)))), 951 wpjam_tag('tbody')->append(wpjam_map($data, fn($item, $k)=> wpjam_tag('tr')->append(wpjam_map($columns, fn($col, $id)=> wpjam_tag('td', ['data'=>['colname'=>$col]], $item[$id] ?? ($id == 'no' ? ($k === 'total' ? '' : $k+1) : round($item['value']/$total*100, 2).'%')))))) 952 ])); 953 } 954 955 return $tag; 956 } 957 958 public static function create($args=[]){ 1010 959 $offset = (int)get_option('gmt_offset'); 1011 960 $offset = $offset >= 0 ? '+'.$offset.':00' : $offset.':00'; … … 1017 966 wpjam_script('morris', wpjam_get_static_cdn().'/morris.js/0.5.1/morris.min.js'); 1018 967 1019 return new self( [968 return new self($args+[ 1020 969 'method' => 'POST', 1021 970 'show_form' => true, … … 1026 975 ]); 1027 976 } 1028 1029 public static function get_instance($args=[]){1030 static $object;1031 return ($object ??= self::create_instance())->update_args(is_array($args) ? $args : []);1032 }1033 977 } -
wpjam-basic/trunk/includes/class-wpjam-api.php
r3440469 r3454739 3 3 public function call($name, ...$args){ 4 4 if(is_closure($name)){ 5 $cb = $name;5 $cb = $name; 6 6 }else{ 7 $by = array_find(['model', 'prop'], fn($k)=> str_ends_with($name, '_by_'.$k)); 8 $name = $by ? explode_last('_by_', $name)[0] : $name; 9 $cb = $by == 'prop' ? $this->$name : [$by == 'model' ? $this->model : $this, $name]; 7 $cb = [$this, $name]; 8 9 if($by = array_find(['model', 'prop'], fn($k)=> str_ends_with($name, '_by_'.$k))){ 10 $name = explode_last('_by_', $name)[0]; 11 $cb = $by == 'prop' ? $this->$name : [$this->model, $name]; 12 } 10 13 } 11 14 … … 85 88 } 86 89 90 public function add_items($items){ 91 return wpjam_map($items, [$this, 'add_item'], wp_is_numeric_array($items) ? 'v' : 'kv'); 92 } 93 87 94 public function remove_item($item, $field=''){ 88 95 return $this->process_items(fn($items)=> array_diff($items, [$item]), $field); … … 104 111 $res = $this->process_items(fn($items)=> wpjam_except($items, $this->prepare_item(null, $key, 'delete', $field) ?? $key), $field); 105 112 106 is_wp_error($res) || (($cb = wpjam_callback([$this, 'after_delete_item'])) && $cb($key, $field));113 is_wp_error($res) || wpjam_call([$this, 'after_delete_item'], $key, $field); 107 114 108 115 return $res; … … 171 178 add_action('plugins_loaded', [$this, 'loaded'], 0); 172 179 173 add_filter('gettext', [$this, 'filter_gettext'], 10, 3); 174 add_filter('gettext_with_context', [$this, 'filter_gettext'], 10, 4); 175 176 if(get_locale() == 'zh_CN'){ 177 load_textdomain('wpjam', dirname(__DIR__).'/template/wpjam-zh_CN.l10n.php'); 178 } 179 180 if(wpjam_is_json_request()){ 181 ini_set('display_errors', 0); 182 183 remove_filter('the_title', 'convert_chars'); 184 185 remove_action('init', 'wp_widgets_init', 1); 186 remove_action('init', 'maybe_add_existing_user_to_blog'); 187 // remove_action('init', 'check_theme_switched', 99); 188 189 remove_action('plugins_loaded', 'wp_maybe_load_widgets', 0); 190 remove_action('plugins_loaded', 'wp_maybe_load_embeds', 0); 191 remove_action('plugins_loaded', '_wp_customize_include'); 192 remove_action('plugins_loaded', '_wp_theme_json_webfonts_handler'); 193 194 remove_action('wp_loaded', '_custom_header_background_just_in_time'); 195 remove_action('wp_loaded', '_add_template_loader_filters'); 196 } 180 wpjam_hooks(['gettext', 'gettext_with_context'], fn($get, ...$args)=> $get === $args[0] ? wpjam_translate(...$args) : $get, 10, 4); 181 182 get_locale() == 'zh_CN' && load_textdomain('wpjam', dirname(__DIR__).'/template/wpjam-zh_CN.l10n.php'); 183 184 wpjam_is_json_request() && wpjam_hooks('remove', [ 185 ['the_title', 'convert_chars'], 186 ['init', ['wp_widgets_init', 'maybe_add_existing_user_to_blog']], 187 ['plugins_loaded', ['wp_maybe_load_widgets', 'wp_maybe_load_embeds', '_wp_customize_include', '_wp_theme_json_webfonts_handler']], 188 ['wp_loaded', ['_custom_header_background_just_in_time', '_add_template_loader_filters']] 189 ]); 197 190 } 198 191 … … 216 209 'src' => wpjam_get_static_cdn().'/remixicon/4.2.0/remixicon.min.css', 217 210 'method' => is_admin() ? 'enqueue' : 'register', 218 'data' => is_admin() ? "\n".'.wp-menu-image[class*=" ri-"]:before{display:inline-block; line-height:1; font-size:20px;}' : '',219 211 'priority' => 1 220 212 ]); 221 213 222 add_filter('pre_do_shortcode_tag', fn($pre, $tag)=> [$this->push('shortcode', $tag), $pre][1], 1, 2);223 add_filter('do_shortcode_tag', fn($res, $tag)=> [$this->pop('shortcode'), $res][1], 999, 2);214 wpjam_hook('tap', 'pre_do_shortcode_tag', fn($pre, $tag)=> $this->push('shortcode', $tag), 1, 2); 215 wpjam_hook('tap', 'do_shortcode_tag', fn($res, $tag)=> $this->pop('shortcode'), 999, 2); 224 216 225 217 add_action('loop_start', fn($query)=> $this->push('query', $query), 1); … … 232 224 } 233 225 234 public function filter_gettext($get, $text, ...$args){235 if($get === $text && ($domain = wpjam_at($args, -1)) != 'default'){236 $cb = 'translate'.(count($args) >= 2 ? '_with_gettext_context' : '');237 238 if($domain === 'wpjam' && ($low = strtolower($text)) !== $text && count(explode(' ', $text)) <= 2 && ($trans = $cb($low, ...$args)) != $low){239 return $trans;240 }241 242 return $cb($text, ...array_slice($args, 0, -1));243 }244 245 return $get;246 }247 248 226 public function add($field, $key, ...$args){ 249 227 [$key, $item] = $args ? [$key, $args[0]] : [null, $key]; … … 253 231 } 254 232 255 return $this->set($field, $key ?? '[]', $item);233 return $this->set($field, $key, $item); 256 234 } 257 235 258 236 public function set($field, $key, ...$args){ 259 $this->data[$field] = is_array($key) ? array_merge(($args && $args[0]) ? $this->get($field) : [], $key) : wpjam_set($this->get($field), $key , ...$args);237 $this->data[$field] = is_array($key) ? array_merge(($args && $args[0]) ? $this->get($field) : [], $key) : wpjam_set($this->get($field), $key ?? '[]', ...$args); 260 238 261 239 return is_array($key) ? $key : $args[0]; … … 395 373 396 374 if($action){ 397 $value = is_closure($value) ? wpjam_bind($value, $this) : $value; 398 $value ??= is_string($key) ? wpjam_callback([$this->model, 'get_'.$key]) : null; 375 $value = is_closure($value) ? wpjam_bind($value, $this) : ($value ?? (is_string($key) ? wpjam_callback([$this->model, 'get_'.$key]) : null)); 399 376 $value = $action === 'callback' ? maybe_callback($value, $this->name) : $value; 400 377 } … … 444 421 445 422 protected function parse_method($name){ 446 if($cb = wpjam_callback([$this->model, $name])){ 447 return $cb; 448 } 449 450 if($cb = wpjam_callback($this->$name)){ 451 return is_closure($cb) ? wpjam_bind($cb, $this) : $cb; 452 } 423 $cb = array_find([[$this->model, $name], $this->$name], fn($v)=> wpjam_callback($v)); 424 425 return is_closure($cb) ? wpjam_bind($cb, $this) : $cb; 453 426 } 454 427 … … 603 576 class WPJAM_Register_Group extends WPJAM_Args{ 604 577 public function get_objects($args=[], $operator='AND'){ 605 $this->defaults && array_map([$this, 'by_default'], array_keys($this->defaults));578 $this->defaults && wpjam_map($this->defaults, [$this, 'by_default'], 'k'); 606 579 607 580 $objects = wpjam_filter($this->get_arg('objects[]'), $args, $operator); … … 771 744 $cb ? $cb($this->name, $values) : [$this, 'update_'.$fix]($values); 772 745 }else{ 773 wpjam_map($values, fn($v, $k)=> $submit == 'reset' ? ('delete_'.$fix)($k) : ('update_'.$fix)($k, $v));746 wpjam_map($values, ...($submit == 'reset' ? ['delete_'.$fix, 'k'] : ['update_'.$fix, 'kv'])); 774 747 } 775 748 … … 888 861 }elseif($key == 'admin_load'){ 889 862 $value = wp_is_numeric_array($value) ? $value : ($value ? [$value] : []); 890 $value = array_map(fn($v) => ($this->model && !isset($v['callback']) && !isset($v['model'])) ? $v+['model'=>$this->model] : $v, $value);863 $value = array_map(fn($v)=> ($this->model && !isset($v['callback']) && !isset($v['model'])) ? $v+['model'=>$this->model] : $v, $value); 891 864 }elseif($key == 'sections'){ 892 865 if(!$value || !is_array($value)){ … … 895 868 } 896 869 897 $value = wpjam_array($value, fn($k, $v)=> is_array($v) && isset($v['fields']) ? [$k, wpjam_set($v, 'fields', maybe_callback($v['fields'] ?? [], $k, $this->name))] : null);870 $value = wpjam_array($value, fn($k, $v)=> is_array($v) && isset($v['fields']) ? [$k, ['fields'=>maybe_callback($v['fields'] ?? [], $k, $this->name)]+$v] : null); 898 871 } 899 872 … … 1028 1001 } 1029 1002 1030 protected static function call_setting($action, ...$args){ 1031 return ($object = self::get_object()) ? [$object, $action.'_setting'](...$args) : null; 1032 } 1033 1034 public static function get_setting($name='', ...$args){ 1035 return self::call_setting('get', $name, ...$args); 1036 } 1037 1038 public static function update_setting(...$args){ 1039 return self::call_setting('update', ...$args); 1040 } 1041 1042 public static function delete_setting($name){ 1043 return self::call_setting('delete', $name); 1003 public static function __callStatic($method, $args){ 1004 return ($object = self::get_object()) ? [$object, $method](...$args) : null; 1044 1005 } 1045 1006 } … … 1185 1146 $data = $wpdb->get_results("SELECT * FROM {$table} WHERE {$where}", ARRAY_A) ?: []; 1186 1147 1187 return $data && $column ? array_first($data)[$this->get_column($column)] : array_map(fn($v)=> wpjam_set($v, 'meta_value', maybe_unserialize($v['meta_value'])), $data);1148 return $data && $column ? array_first($data)[$this->get_column($column)] : array_map(fn($v)=> ['meta_value'=>maybe_unserialize($v['meta_value'])]+$v, $data); 1188 1149 } 1189 1150 … … 1364 1325 if($this->modules){ 1365 1326 $modules = maybe_callback($this->modules, $this->name, $this->args); 1366 $results = array_map( fn($module)=> WPJAM_JSON_Module::parse($module), wp_is_numeric_array($modules) ? $modules : [$modules]);1327 $results = array_map(['WPJAM_JSON_Module', 'parse'], wp_is_numeric_array($modules) ? $modules : [$modules]); 1367 1328 }elseif($this->callback){ 1368 1329 $fields = wpjam_try('maybe_callback', $this->fields ?: [], $this->name); … … 1408 1369 exit; 1409 1370 } 1371 1372 ini_set('display_errors', 0); 1410 1373 1411 1374 add_filter('wp_die_'.(array_find(['jsonp_', 'json_'], fn($v)=> call_user_func('wp_is_'.$v.'request')) ?: '').'handler', fn()=> [self::class, 'die_handler']); -
wpjam-basic/trunk/includes/class-wpjam-field.php
r3436010 r3454739 42 42 43 43 public function class($action='', ...$args){ 44 $args = array_map( fn($v)=> wp_parse_list($v ?: []), [$this->class, ...$args]);44 $args = array_map('wp_parse_list', [$this->class ?: [], ...$args]); 45 45 $cb = $action ? ['add'=>'array_merge', 'remove'=>'array_diff', 'toggle'=>'wpjam_toggle'][$action] : ''; 46 46 … … 108 108 109 109 return self::is_bool($v) ? [$v, $v] : null; 110 } else{111 return self::is_bool($k) ? ($v ? [$k, $k] : null) : [$k, $v]; 112 }110 } 111 112 return self::is_bool($k) ? ($v ? [$k, $k] : null) : [$k, $v]; 113 113 }); 114 114 } … … 217 217 218 218 if($type == '_data_type'){ 219 if( str_ends_with($action, '_value')){219 if(in_array($action, ['parse', 'validate'])){ 220 220 if(!$this->$type){ 221 221 return $args[0]; … … 223 223 224 224 if($this->multiple && is_array($args[0])){ 225 return array_map(fn($v)=> wpjam_try([$this, $method], $v), $args[0]); 226 } 227 } 228 229 array_push($args, $this); 225 return array_map([$this, $method], $args[0]); 226 } 227 228 $args = [$action, ...$args]; 229 $action = 'with_field'; 230 } 231 232 if($action != 'get_arg'){ 233 $args[] = $this; 234 } 230 235 }elseif($type == '_fields'){ 231 236 $this->$type ??= WPJAM_Fields::create($this->fields, $this->_fields_args ?: [], $this); … … 284 289 } 285 290 286 $value = array_filter(['type'=>$this->get_arg('show_in_rest.type')])+($this->get_ schema_by_data_type() ?: []);291 $value = array_filter(['type'=>$this->get_arg('show_in_rest.type')])+($this->get_arg_by_data_type('schema') ?: []); 287 292 288 293 if($this->is('mu')){ … … 308 313 309 314 $value += ['type'=>'string']; 310 $value += array_filter(wpjam_map(((array_fill_keys(['integer', 'number'], ['minimum'=>'min', 'maximum'=>'max'])+[315 $value += wpjam_array((array_fill_keys(['integer', 'number'], ['minimum'=>'min', 'maximum'=>'max'])+[ 311 316 'array' => ['maxItems'=>'max_items', 'minItems'=>'min_items', 'uniqueItems'=>'unique_items'], 312 317 'string' => ['minLength'=>'minlength', 'maxLength'=>'maxlength'], 313 ])[$value['type']] ?? []), fn($v)=> $this->$v), fn($v)=> !is_blank($v)); 318 ])[$value['type']] ?? [], fn($k, $v)=> is_blank($this->$v) ? null : [$k, $this->$v]); 319 314 320 } 315 321 … … 317 323 foreach(wpjam_pull($value, ['enum', 'items', 'properties']) as $k => $v){ 318 324 if($k == 'enum'){ 319 $value[$k] = array_map(fn($i v)=> $this->sanitize($iv, $value), $v);325 $value[$k] = array_map(fn($i)=> $this->sanitize($i, $value), $v); 320 326 }elseif($value['type'] == ($k == 'items' ? 'array' : 'object')){ 321 327 $value[$k] = $k == 'items' ? $parse($v) : array_map($parse, $v); … … 437 443 } 438 444 439 $value && ($value = $this->validate_ value_by_data_type($value));445 $value && ($value = $this->validate_by_data_type($value)); 440 446 } 441 447 … … 480 486 $args = $this->$k ? [[$k=>$this->$k]+wpjam_pick($args, ['id']), array_last($this->_names)] : [$args, $this->_names]; 481 487 482 return wpjam_value _callback(...$args) ?? $this->value;488 return wpjam_value(...$args) ?? $this->value; 483 489 } 484 490 … … 521 527 } 522 528 523 return $value && $this->parse_required ? $this->parse_ value_by_data_type($value) : $value;529 return $value && $this->parse_required ? $this->parse_by_data_type($value) : $value; 524 530 } 525 531 … … 623 629 }elseif($this->is('mu-text')){ 624 630 if(($this->item_type ??= 'text') == 'text'){ 625 $this->direction == 'row' && ($this->class ??= 'medium-text');626 627 array_walk($value, fn(&$v)=> ($l = $this->query_label_by_data_type($v)) && ($v = ['value'=>$v, 'label'=>$l]));631 $this->direction == 'row' && ($this->class ??= 'medium-text'); 632 633 $value = $this->query_label_by_data_type($value) ?: $value; 628 634 } 629 635 … … 689 695 }elseif($this->is('uploader')){ 690 696 $mimes = wpjam_accept_to_mime_types($this->accept ?: 'image/*'); 691 $exts = implode(',', array_map(fn($v)=> str_replace('|', ',', $v), array_keys($mimes)));697 $exts = implode(',', wpjam_map($mimes, fn($v)=> str_replace('|', ',', $v), 'k')); 692 698 $params = ['_ajax_nonce'=>wp_create_nonce('upload-'.$this->key), 'action'=>'wpjam-upload', 'name'=>$this->key, 'mimes'=>$mimes]; 693 699 … … 719 725 } 720 726 721 public static function parse($field){ 727 public static function parse($field, ...$args){ 728 if(is_object($field)){ 729 $object = $field; 730 $key = array_shift($args); 731 732 if(is_array($key)){ 733 return wpjam_reduce($key, fn($c, $v, $k)=> wpjam_field($object, $k, $v), $object); 734 } 735 736 if(!$args && is_callable($key)){ 737 [$args, $key] = [[$key], '']; 738 } 739 740 return [$object, $args ? 'update_arg' : 'delete_arg']('_fields['.$key.']', ...$args); 741 } 742 722 743 $field = is_string($field) ? ['type'=>'view', 'value'=>$field, 'wrap_tag'=>''] : parent::parse($field); 723 744 $field = ['options'=>(($field['options'] ?? []) ?: [])]+$field; … … 808 829 809 830 if($method == 'validate'){ 810 $can = !$field->disabled && !$field->readonly && !$field->is('view ');831 $can = !$field->disabled && !$field->readonly && !$field->is('view, button'); 811 832 $args[0] = $flat ? $values : $field->unpack($values); 812 833 … … 875 896 } 876 897 877 public static function create($fields, $args=[], $parent=null){ 898 public function process($items, $args=[]){ 899 $sumable = $this->sumable; 900 901 if(!$sumable){ 902 $sumable = [1=>[], 2=>[]]; 903 904 foreach($this->fields as $k => $v){ 905 if($s = $v['sumable'] ?? ''){ 906 $sumable[$s][$k] = 0; 907 } 908 909 if(array_filter($f = [$v['format'] ?? '', $v['precision'] ?? null])){ 910 $formats[$k] = $f; 911 } 912 913 if(($e = $v['if_error'] ?? '') || is_numeric($e)){ 914 $if_errors[$k] = $e; 915 } 916 } 917 918 $formulas = wpjam_formula($this->fields); 919 $sumable[2] = array_intersect_key($formulas, $sumable[2]); 920 921 $this->update_args([ 922 'formulas' => $formulas, 923 'sumable' => $sumable, 924 'formats' => $formats ?? [], 925 'if_errors' => $if_errors ?? [], 926 ]); 927 } 928 929 $sum = $args['sum'] ?? true; 930 $calc = $args['calc'] ?? null; 931 932 if($sum === 'accumulate'){ 933 $calc ??= false; 934 $field = $args['field'] ?? ''; 935 $to = $args['to'] ?? []; 936 $to = $field ? $to : ($to ?: $sumable[1]); 937 }else{ 938 $calc ??= true; 939 $sums = $sum ? $sumable[1] : null; 940 } 941 942 foreach($items as $i => &$item){ 943 if($calc && $item && is_array($item)){ 944 $item = wpjam_calc($item, ($calc === 'sum' ? $sumable[2] : $this->formulas), $this->if_errors); 945 } 946 947 if(!empty($args['filter']) && !wpjam_matches($item, $args['filter'])){ 948 unset($items[$i]); continue; 949 } 950 951 if($sum === 'accumulate'){ 952 if($field){ 953 $g = $item[$field] ?? ''; 954 $to[$g] ??= $sumable[1]+$item; 955 $target = &$to[$g]; 956 }else{ 957 $target = &$to; 958 } 959 }elseif($sum){ 960 $target = &$sums; 961 } 962 963 if($sum){ 964 foreach($sumable[1] as $k => $null){ 965 $target[$k] += wpjam_format($item[$k] ?? 0, '-,', 0); 966 } 967 } 968 969 if(!empty($args['format'])){ 970 $item = wpjam_format($item, $this->formats); 971 } 972 } 973 974 if($sum === 'accumulate'){ 975 return $to; 976 } 977 978 if(!empty($args['orderby'])){ 979 $items = wpjam_sort($items, $args['orderby'], $args['order']); 980 } 981 982 if($sums){ 983 $sums = wpjam_calc($sums, $sumable[2], $this->if_errors)+(is_array($sum) ? $sum : []); 984 $items = wpjam_add_at($items, 0, '__sum__', (!empty($args['format']) ? wpjam_format($sums, $this->formats) : $sums)); 985 } 986 987 return $items; 988 } 989 990 public static function create($fields, $type='', ...$args){ 991 if($type === 'processor'){ 992 return new self(['fields'=>$fields]); 993 } 994 995 $parent = $args[0] ?? null; 996 $args = $type ?: []; 878 997 $prop = $parent && !$parent->is('flat'); 879 998 $attr = ['_parent'=>$parent, '_fields_args'=>$args]+wpjam_pick($parent ?: [], ['readonly', 'disabled']); … … 892 1011 } 893 1012 894 public static function parse($fields, $flat=false, $prefix=''){ 1013 public static function parse($fields, ...$args){ 1014 if(is_object($fields)){ 1015 $object = $fields; 1016 $fields = []; 1017 1018 foreach($object->get_arg('_fields[]') as $key => $field){ 1019 if(is_callable($field)){ 1020 $result = wpjam_try($field, ...$args); 1021 1022 if(is_numeric($key)){ 1023 $fields = array_merge($fields, $result); 1024 }else{ 1025 $fields[$key] = $result; 1026 } 1027 }elseif(wpjam_is_assoc_array($field)){ 1028 $fields[$key] = $field; 1029 } 1030 } 1031 1032 return $fields; 1033 } 1034 1035 [$flat, $prefix] = $args+[false, '']; 1036 895 1037 foreach($fields as $key => $field){ 896 1038 $field = WPJAM_Field::parse($field); … … 1088 1230 1089 1231 foreach($pks as $pk => [$op, $fix]){ 1090 if(wpjam_ array($platforms, fn($pf)=> $pf->has_path($name, $strict && $op == 'OR'), $op)){1232 if(wpjam_matches($platforms, fn($pf)=> $pf->has_path($name, $strict && $op == 'OR'), $op)){ 1091 1233 $i++; 1092 1234 … … 1174 1316 #[config(model:false)] 1175 1317 class WPJAM_Data_Type extends WPJAM_Register{ 1176 public function __call($method, $args){ 1177 if(in_array($method, ['parse_value', 'validate_value'])){ 1178 [$value, $field] = $args; 1179 1180 $action = wpjam_at($method, '_', 0); 1181 $result = $this->$method ? $this->call($method.'_by_prop', $value, $field) : (($cb = $this->model.'::with_field') && wpjam_callback($cb) ? wpjam_try($cb, $action, $field, $value) : $value); 1182 1183 return $action == 'validate' && is_null($result) ? wpjam_throw('invalid_field_value', $field->_title.'的值无效') : $result; 1184 }elseif($method == 'get_path'){ 1185 return ($cb = $this->model.'::get_path') && wpjam_callback($cb) ? wpjam_try($cb, ...$args) : null; 1186 }elseif($method == 'get_schema'){ 1187 return $this->get_arg('schema'); 1188 } 1189 1190 trigger_error($method); 1318 public function get_path($args, $item){ 1319 return wpjam_if_error(wpjam_call($this->model.'::get_path', $args, $item), 'throw'); 1320 } 1321 1322 public function with_field($action, $value, $field){ 1323 $method = $action.'_value'; 1324 $result = $this->$method ? $this->call($method.'_by_prop', $value, $field) : (($cb = $this->model.'::with_field') && wpjam_callback($cb) ? wpjam_try($cb, $action, $field, $value) : $value); 1325 1326 return $action == 'validate' && is_null($result) ? wpjam_throw('invalid_field_value', $field->_title.'「'.$value.'」的值无效') : $result; 1327 } 1328 1329 public function query_label($value){ 1330 if($value && $this->model && $this->label_field){ 1331 if(is_array($value)){ 1332 wpjam_call($this->model.'::update_caches', $value); 1333 1334 return array_map(fn($v)=> ($l = $this->query_label($v)) ? ['label'=>$l, 'value'=>$v] : $v, $value); 1335 } 1336 1337 return ($this->model::get($value) ?: [])[$this->label_field] ?? null; 1338 } 1191 1339 } 1192 1340 … … 1203 1351 $items = wp_is_numeric_array($result) ? $result : ($result['items'] ?? []); 1204 1352 1205 return $this->label_field ? array_map(fn($v)=> [ 1206 'label' => wpjam_get($v, $this->label_field), 1207 'value' => wpjam_get($v, $this->id_field) 1208 ], $items) : $items; 1353 return $this->label_field ? wpjam_column($items, ['label'=>$this->label_field, 'value'=>$this->id_field]) : $items; 1209 1354 } 1210 1355 1211 1356 return []; 1212 }1213 1214 public function query_label($id, $field=null){1215 if($this->query_label){1216 return $id ? $this->call('query_label_by_prop', $id, $field) : null;1217 }elseif($this->model && $this->label_field){1218 return ($id ? ($this->model::get($id) ?: []) : [])[$this->label_field] ?? null;1219 }1220 1357 } 1221 1358 … … 1255 1392 1256 1393 $args['label_field'] ??= wpjam_pull($args, 'label_key') ?: 'title'; 1257 $args['id_field'] ??= wpjam_pull($args, 'id_key') ?: wpjam_ call($model.'::get_primary_key');1394 $args['id_field'] ??= wpjam_pull($args, 'id_key') ?: wpjam_value($model, 'primary_key'); 1258 1395 1259 1396 $object = $object->get_sub($model) ?: $object->register_sub($model, $args+[ 1260 'meta_type' => wpjam_ call($model.'::get_meta_type') ?: '',1397 'meta_type' => wpjam_value($model, 'meta_type') ?: '', 1261 1398 'validate_value' => fn($v)=> wpjam_try([$model, 'get'], $v) ? $v : null 1262 1399 ]); … … 1276 1413 $args = $type ? (['data_type'=>$type]+(in_array($type, ['post_type', 'taxonomy']) ? [$type => wpjam_get($args, $type, '')] : [])) : []; 1277 1414 1278 return $output == 'key' ? ($args ? '__'.md5( serialize(array_map(fn($v)=> is_closure($v) ? spl_object_hash($v) : $v, $args))) : '') : $args;1415 return $output == 'key' ? ($args ? '__'.md5(wpjam_serialize($args)) : '') : $args; 1279 1416 } 1280 1417 … … 1283 1420 } 1284 1421 } 1285 1286 class WPJAM_Data_Processor extends WPJAM_Args{1287 public function __construct($fields){1288 $this->args = ['fields'=>$fields, 'sumable'=>[1=>[], 2=>[]]];1289 1290 foreach($fields as $k => $v){1291 if(!empty($v['sumable'])){1292 $this->update_arg('sumable['.$v['sumable'].'][]', $k);1293 }1294 1295 if(($if = $v['if_error'] ?? '') || is_numeric($if)){1296 $this->update_arg('if_errors['.$k.']', $if);1297 }1298 1299 $format = [$v['format'] ?? '', $v['precision'] ?? null];1300 1301 if(array_filter($format)){1302 $this->update_arg('formats['.$k.']', $format);1303 }1304 }1305 }1306 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) ? '' : ','.$msg1314 ]));1315 1316 $path[] = in_array($key, $path) ? $throw(array_slice($path, array_search($key, $path)), '公式嵌套') : $key;1317 $depth = 0;1318 $functions = ['abs', 'ceil', 'pow', 'sqrt', 'pi', 'max', 'min', 'fmod', 'round'];1319 $signs = ['+', '-', '*', '/', '(', ')', ',', '%'];1320 $formula = preg_split('/\s*(['.preg_quote(implode($signs), '/').'])\s*/', trim($fields[$key]['formula']), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);1321 1322 foreach($formula as $t){1323 if(is_numeric($t)){1324 str_ends_with($t, '.') && $throw($key, '无效数字「'.$t.'」');1325 }elseif(str_starts_with($t, '$')){1326 isset($fields[substr($t, 1)]) || $throw($key, '「'.$t.'」未定义');1327 }elseif($t == '('){1328 $depth += 1;1329 }elseif($t == ')'){1330 $depth -= $depth ? 1 : $throw($key, '括号不匹配');1331 }else{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));1339 1340 $this->update_arg('formulas['.array_pop($path).']', $formula);1341 }else{1342 is_null($this->formulas) && wpjam_map($this->fields, fn($v, $k)=> empty($v['formula']) || $this->get_arg('formulas['.$k.']') || $this->formulas($k, []));1343 1344 return $this->formulas;1345 }1346 }1347 1348 private function number($v){1349 $v = is_string($v) ? str_replace(',', '', trim($v)) : $v;1350 1351 return is_numeric($v) ? $v : false;1352 }1353 1354 public function process($items, $args=[]){1355 $args = wp_parse_args($args, ['calc'=>true, 'sum'=>true, 'format'=>false, 'orderby'=>'', 'order'=>'', 'filter'=>'']);1356 $sums = $args['sum'] ? array_fill_keys($this->sumable[1], 0) : [];1357 1358 foreach($items as $i => &$item){1359 if($args['calc']){1360 $item = $this->calc($item);1361 }1362 1363 if($args['filter'] && !wpjam_matches($item, $args['filter'])){1364 unset($items[$i]); continue;1365 }1366 1367 if($args['sum']){1368 $sums = wpjam_map($sums, fn($v, $k)=> $v+$this->number($item[$k] ?? 0));1369 }1370 1371 if($args['format']){1372 $item = $this->format($item);1373 }1374 }1375 1376 if($args['orderby']){1377 $items = wpjam_sort($items, $args['orderby'], $args['order']);1378 }1379 1380 if($args['sum']){1381 $sums = $this->calc($sums, ['sum'=>true])+(is_array($args['sum']) ? $args['sum'] : []);1382 $items = wpjam_add_at($items, 0, '__sum__', ($args['format'] ? $this->format($sums) : $sums));1383 }1384 1385 return $items;1386 }1387 1388 public function calc($item, $args=[]){1389 if(!$item || !is_array($item)){1390 return $item;1391 }1392 1393 if(!empty($args['formula'])){1394 foreach($args['formula'] as &$t){1395 if(str_starts_with($t, '$')){1396 $k = substr($t, 1);1397 $v = $item[$k] ?? null;1398 $r = isset($v) ? $this->number($v) : false;1399 1400 if($r !== false){1401 $t = (float)$r;1402 $t = $t < 0 ? '('.$t.')' : $t;1403 }else{1404 $t = $this->get_arg('if_errors['.$k.']');1405 1406 if(!isset($t)){1407 return $args['if_error'] ?? (isset($v) ? '!!无法计算' : '!无法计算');1408 }1409 }1410 }1411 }1412 1413 try{1414 return eval('return '.implode($args['formula']).';');1415 }catch(DivisionByZeroError $e){1416 return $args['error'] ?? '!除零错误';1417 }catch(throwable $e){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]);1424 1425 if($formulas){1426 $prev = set_error_handler(function($no, $str){1427 throw str_contains($str , 'Division by zero') ? new DivisionByZeroError($str) : new ErrorException($str, $no);1428 });1429 1430 $item = array_diff_key($item, $formulas);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 1433 $prev ? set_error_handler($prev) : restore_error_handler();1434 }1435 1436 return $item;1437 }1438 1439 public function sum($items, $args=[]){1440 return ($this->sumable && $items) ? $this->calc(wpjam_at($this->process($items, $args+['sum'=>true]), 0), ['sum'=>true]) : [];1441 }1442 1443 public function accumulate($to, $items, $args=[]){1444 $args = wp_parse_args($args, ['calc'=>true, 'field'=>'', 'filter'=>'']);1445 $keys = $this->sumable[1];1446 1447 if(!$args['field']){1448 $group = '____';1449 $to = [$group=>($to ?: array_fill_keys($keys, 0))];1450 }1451 1452 foreach($items as $item){1453 if($args['calc']){1454 $item = $this->calc($item);1455 }1456 1457 if($args['filter'] && !wpjam_matches($item, $args['filter'])){1458 continue;1459 }1460 1461 if($args['field']){1462 $group = $item[$args['field']] ?? '';1463 }1464 1465 $exists = isset($to[$group]);1466 1467 if(!$exists){1468 $to[$group] = $item;1469 }1470 1471 foreach($keys as $k){1472 $to[$group][$k] = ($exists ? $to[$group][$k] : 0)+($this->number($item[$k] ?? 0) ?: 0);1473 }1474 }1475 1476 return $args['field'] ? $to : $to[$group];1477 }1478 1479 public function format($item){1480 return wpjam_reduce($this->formats ?: [], fn($c, $v, $k)=> isset($c[$k]) && is_numeric($c[$k]) ? wpjam_set($c, $k, wpjam_format($c[$k], ...$v)) : $c, $item);1481 }1482 } -
wpjam-basic/trunk/includes/class-wpjam-list-table.php
r3440469 r3454739 8 8 9 9 public function __construct($args=[]){ 10 add_screen_option('list_table', ($GLOBALS['wpjam_list_table'] = wpjam_admin('list_table', $this)));11 12 wp_doing_ajax() && wpjam_get_post_parameter('action_type') == 'query_items' && ($_REQUEST = $this->get_data()+$_REQUEST); // 兼容10 add_screen_option('list_table', ($GLOBALS['wpjam_list_table'] = wpjam_admin('list_table', $this))); 11 12 wp_doing_ajax() && wpjam_get_post_parameter('action_type') == 'query_items' && ($_REQUEST = $this->get_data()+$_REQUEST); 13 13 14 14 $this->screen = $screen = get_current_screen(); … … 16 16 17 17 array_map([$this, 'component'], ['action', 'view', 'column']); 18 19 wpjam_admin('style', $this->style); 20 wpjam_admin('vars[list_table]', fn()=> $this->get_setting()); 21 wpjam_admin('vars[page_title_action]', fn()=> $this->get_action('add', ['class'=>'page-title-action']) ?: ''); 22 23 add_filter('views_'.$screen->id, [$this, 'filter_views']); 24 add_filter('bulk_actions-'.$screen->id, [$this, 'filter_bulk_actions']); 25 add_filter('manage_'.$screen->id.'_sortable_columns', [$this, 'filter_sortable_columns']); 26 27 $this->builtin ? $this->page_load() : parent::__construct($this->_args); 18 array_map(fn($k)=> add_filter('manage_'.$screen->id.'_'.$k, [$this, 'filter_'.$k]), ['columns', 'sortable_columns']); 19 array_map(fn($k, $s)=> add_filter($k.$s.$screen->id, [$this, 'filter_'.$k]), ['views', 'bulk_actions'], ['_', '-']); 20 21 wpjam_admin([ 22 'style' => $this->style, 23 'vars[list_table]' => fn()=> $this->get_setting(), 24 'vars[page_title_action]' => fn()=> $this->get_action('add', ['class'=>'page-title-action']) ?: '' 25 ]); 26 27 if($this->builtin){ 28 $this->page_load(); 29 }else{ 30 add_filter('list_table_primary_column', fn()=> $this->primary_column ??= array_key_first(wpjam_except($this->columns, ['no', 'cb']))); 31 32 parent::__construct($this->_args); 33 } 28 34 } 29 35 … … 37 43 } 38 44 39 if(in_array($name, ['primary_key', 'actions', 'views', 'fields', 'filterable_fields', 'searchable_fields'])){ 40 $value = wpjam_trap(in_array($name, ['actions', 'views', 'fields']) ? [$this, 'get_'.$name.'_by_model'] : $this->model.'::get_'.$name, []) ?: []; 45 if(in_array($name, ['actions', 'views', 'fields'])){ 46 $value = [$this, 'get_'.$name.'_by_model'](); 47 48 if($name == 'fields'){ 49 return $this->$name = wpjam_fields($value ?: [], true); 50 } 51 52 return $value ?? ($name == 'actions' ? ($this->builtin ? [] : WPJAM_Model::get_actions()) : ($this->views_by_model() ?: [])); 53 }elseif(in_array($name, ['primary_key', 'filterable_fields', 'searchable_fields'])){ 54 $value = wpjam_trap($this->model.'::get_'.$name, []) ?: []; 41 55 42 56 if($name == 'primary_key'){ 43 57 return $this->$name = $value ?: 'id'; 44 }elseif($name == 'fields'){45 return $this->$name = wpjam_fields($value, true);46 58 }elseif($name == 'filterable_fields'){ 47 59 $fields = wpjam_filter($this->fields, ['filterable'=>true]); 48 60 $views = array_keys(wpjam_filter($fields, ['type'=>'view'])); 49 $fields = wpjam_map(wpjam_except($fields, $views), fn($v)=> wpjam_except($v, ['title', 'before', 'after', 'required', 'show_admin_column'])+[($v['type'] === 'select' ? 'show_option_all' : 'placeholder') => $v['title'] ?? '']);61 $fields = array_map(fn($v)=> wpjam_except($v, ['title', 'before', 'after', 'required', 'show_admin_column'])+[($v['type'] === 'select' ? 'show_option_all' : 'placeholder') => $v['title'] ?? ''], wpjam_except($fields, $views)); 50 62 51 63 return $this->$name = $fields+($fields && !$this->builtin && $this->sortable_columns ? [ 52 'orderby' => ['options'=>[''=>'排序']+ wpjam_map(array_intersect_key($this->columns, $this->sortable_columns), 'wp_strip_all_tags')],64 'orderby' => ['options'=>[''=>'排序']+array_map('wp_strip_all_tags', array_intersect_key($this->columns, $this->sortable_columns))], 53 65 'order' => ['options'=>['desc'=>'降序','asc'=>'升序']] 54 66 ] : [])+array_fill_keys(array_merge($value, $views), []); … … 59 71 $left = $name == 'left_data'; 60 72 $fields = $left ? $this->left_fields : array_filter($this->filterable_fields); 61 $data = ($name == 'form_data' || wp_doing_ajax()) ? wpjam_get_post_parameter($left ? 'params' : $name) : wpjam_get_parameter(); 62 $value = $data && $fields ? wpjam_trap([wpjam_fields($fields), 'validate'], wp_parse_args($data), []) : []; 63 64 return $this->$name = array_filter($value, fn($v)=> isset($v) && $v !== [])+($left ? [] : (wpjam_admin('chart', 'get_data', ['data'=>$data]) ?: [])); 73 $data = $name == 'form_data' || wp_doing_ajax() ? wpjam_get_post_parameter($left ? 'params' : $name) : wpjam_get_parameter(); 74 75 return array_filter(array_merge(...array_map(fn($v)=> $v ? wpjam_trap([$v, 'validate'], wp_parse_args($data), []) : [], [ 76 $data && $fields ? wpjam_fields($fields) : '', 77 $left ? '' : wpjam_chart() 78 ])), fn($v)=> isset($v) && $v !== []); 65 79 }elseif($name == 'offset'){ 66 80 return ((int)$this->per_page ?: 50)*($this->get_pagenum()-1); … … 69 83 70 84 public function __set($name, $value){ 71 return in_array($name, $this->compat_fields, true) ? ($this->$name = $value) : ($this->_args[$name]= $value);85 return in_array($name, $this->compat_fields, true) ? ($this->$name = $value) : ($this->_args[$name] = $value); 72 86 } 73 87 … … 82 96 return wpjam_get_data_parameter(...$args); 83 97 }elseif($method == 'get_date'){ 84 $type = array_find(['prev', 'next', 'current'], fn($v)=> in_array($v, $args, true)); 85 86 if($type == 'current'){ 87 [$year, $month] = array_map('wpjam_date', ['Y', 'm']); 88 }else{ 89 $year = clamp((int)$this->get_data('year') ?: wpjam_date('Y'), 1970, 2200); 90 $month = clamp((int)$this->get_data('month') ?: wpjam_date('m'), 1, 12); 91 $month += $type ? ($offset = $type == 'prev' ? -1 : 1) : 0; 92 93 if(in_array($month, [0, 13])){ 94 $year += $offset; 95 $month = abs($month-12); 96 } 98 $type = $args[0] ?? ''; 99 100 [$year, $month] = array_map(fn($k, $f, $r)=> clamp(($type == 'current' ? 0 : (int)$this->get_data($k)) ?: wpjam_date($f), ...$r), ['year', 'month'], ['Y', 'm'], [[1970, 2200], [1, 12]]); 101 102 $offset = $type == 'prev' ? -1 : ($type == 'next' ? 1 : 0); 103 $month += $offset; 104 105 if(in_array($month, [0, 13])){ 106 $year += $offset; 107 $month = abs($month-12); 97 108 } 98 109 … … 103 114 return $args[0]; 104 115 }elseif(try_remove_suffix($method, '_by_model')){ 105 return ($cb = wpjam_callback([$this->model, $method])) ? wpjam_catch($cb, ...$args) : ($method == 'get_actions' ? ($this->builtin ? [] : WPJAM_Model::get_actions()) : ($method == 'get_views' ? $this->views_by_model() : null)); 116 return ($cb = wpjam_callback([$this->model, $method])) ? wpjam_catch($cb, ...$args) : null; 117 }elseif(try_remove_suffix($method, '_row_actions')){ 118 [$value, $id] = $method == 'get' ? [[], $args[0]] : [$args[0], $this->parse_id($args[1])]; 119 120 $names = array_diff($this->row_actions ?: [], $this->next_actions ?: []); 121 $value += $this->get_action($names, ['id'=>$id]+($this->layout == 'calendar' ? ['wrap'=>'<span class="%s"></span>'] : [])); 122 $value += $this->builtin ? wpjam_pull($value, ['view', 'delete', 'trash', 'spam', 'remove']) : []; 123 124 return wpjam_except($value+($this->builtin || $this->primary_key == 'id' ? ['id'=>'ID: '.$id] : []), wpjam_admin('removed_actions[]')); 106 125 }elseif(try_remove_prefix($method, 'ob_get_')){ 107 return wpjam_ob([$this, $method], ...$args); 126 $result = wpjam_ob([$this, ($this->builtin && $method != 'single_row' ? 'builtin_' : '').$method], ...$args); 127 128 return $this->builtin && in_array($method, ['single_row', 'display']) ? $this->filter_table($result) : $result; 108 129 }elseif(try_remove_prefix($method, 'builtin_')){ 109 130 return [$GLOBALS['wp_list_table'] ??= _get_list_table($this->builtin, ['screen'=>$this->screen]), $method](...$args); 110 131 }elseif(try_remove_prefix($method, 'filter_')){ 111 132 if($method == 'table'){ 112 return wpjam_preg_replace('#<tr id=" '.$this->singular.'-(\d+)"[^>]*>(.+?)</tr>#is', fn($m)=> $this->filter_single_row($m[0], $m[1]), $args[0]);133 return wpjam_preg_replace('#<tr id=".+?-(\d+)"[^>]*>.+?</tr>#is', fn($m)=> $this->filter_single_row(...$m), $args[0]); 113 134 }elseif($method == 'single_row'){ 114 135 return wpjam_do_shortcode(apply_filters('wpjam_single_row', ...$args), [ … … 116 137 'row_action' => fn($attr, $title)=> $this->get_row_action($args[1], (is_blank($title) ? [] : compact('title'))+$attr)."\n" 117 138 ]); 118 }elseif($method == 'custom_column'){ 119 return count($args) == 2 ? wpjam_echo($this->column_default([], ...$args)) : $this->column_default(...$args); 120 } 121 122 $value = $this->$method ?: []; 123 124 if($method == 'columns'){ 125 return wpjam_except(($args ? wpjam_add_at($args[0], -1, $value) : $value), wpjam_admin('removed_columns[]')); 126 }elseif($method == 'row_actions'){ 127 $args[1]= $this->layout == 'calendar' ? $args[1] : ['id'=>$this->parse_id($args[1])]; 128 $value = $args[0]+$this->get_actions(array_diff($value, $this->next_actions ?: []), $args[1]); 129 $value += $this->builtin ? wpjam_pull($value, ['delete', 'trash', 'spam', 'remove', 'view']) : []; 130 131 return wpjam_except($value+($this->primary_key == 'id' || $this->builtin ? ['id'=>'ID: '.$args[1]['id']] : []), wpjam_admin('removed_actions[]')); 132 } 133 134 return array_merge($args[0], $value); 139 }elseif($method == 'columns'){ 140 return $this->columns = wpjam_except(wpjam_add_at($args[0], $args[0] ? -1 : 0, $this->columns ?: []), wpjam_admin('removed_columns[]')); 141 } 142 143 return array_merge($args[0], $this->$method ?: []); 135 144 } 136 145 … … 160 169 $this->prepare_items(); 161 170 162 $result = $this->response($result)+['params'=>$this->params, 'setting'=>$this->get_setting(), 'views'=>$this->ob_get_views(), 'search_box'=>$this->get_search_box()]; 163 164 $result += $result['type'] == 'list' ? ['table'=>$this->get_table()] : ['tablenav'=>wpjam_fill(['top', 'bottom'], fn($which)=>$this->ob_get_display_tablenav($which))]; 171 $result = $this->response($result)+['params'=>$this->params, 'setting'=>$this->get_setting(), 'views'=>$this->ob_get_views()]; 172 $result += $result['type'] == 'list' ? ['table'=>$this->ob_get_display()] : ['tablenav'=>wpjam_fill(['top', 'bottom'], [$this, 'ob_get_display_tablenav'])]; 165 173 } 166 174 … … 180 188 if($this->layout == 'calendar'){ 181 189 if(!empty($data['data'])){ 182 $data['data'] = wpjam_map( ($data['data']['dates'] ?? $data['data']), fn($v, $k)=> $this->ob_get_single_date($v, $k));190 $data['data'] = wpjam_map($data['data'], [$this, 'ob_get_single_date']); 183 191 } 184 192 }elseif(!empty($data['bulk'])){ … … 226 234 }elseif($type == 'column'){ 227 235 if($this->layout == 'calendar'){ 228 $start = (int)get_option('start_of_week'); 229 $locale = $GLOBALS['wp_locale']; 230 231 for($i=$start; $i<$start+7; $i++){ 232 $this->add('columns', 'day'.($i%7), $locale->get_weekday_abbrev($locale->get_weekday($i%7))); 233 } 234 235 return wpjam_map(['year', 'month'], fn($v)=> $this->add('query_args', $v)); 236 array_map(fn($i)=> $this->add('columns', 'day'.($i%7), $GLOBALS['wp_locale']->get_weekday_abbrev($GLOBALS['wp_locale']->get_weekday($i%7))), array_slice(range(0, get_option('start_of_week')+6), -7)); 237 238 return array_map(fn($v)=> $this->add('query_args', $v), ['year', 'month']); 236 239 } 237 240 238 241 $this->bulk_actions && !$this->builtin && $this->add('columns', 'cb', true); 239 242 240 $no = $this->numberable; 241 $no && $this->add('columns', 'no', $no === true ? 'No.' : $no) && wpjam_admin('style', '.column-no{width:42px;}'); 243 ($no = $this->numberable) && $this->add('columns', 'no', $no === true ? 'No.' : $no); 242 244 } 243 245 … … 276 278 277 279 protected function get_setting(){ 278 $s = $this->get_data('s'); 280 $s = $this->get_data('s'); 281 $fields = $this->searchable_fields; 279 282 280 283 return wpjam_pick($this, ['sortable', 'layout', 'left_key'])+[ 284 'search' => $this->builtin || ($this->search ?? $fields) ? [ 285 'columns' => wpjam_is_assoc_array($fields) ? wpjam_field(['key'=>'search_columns', 'value'=>$this->get_data('search_columns'), 'show_option_all'=>'默认', 'options'=>$fields]) : '' 286 ]+($this->builtin ? ['term'=>$s] : ['box'=>$this->ob_get_search_box('搜索', 'wpjam')]) : false, 287 281 288 'subtitle' => $this->get_subtitle_by_model().($s ? sprintf(__('Search results for: %s', 'wpjam'), '<strong>'.esc_html($s).'</strong>') : ''), 282 289 'summary' => $this->get_summary_by_model(), 283 290 284 'column_count' => $this->get_column_count(),285 'bulk_actions' => wpjam_map($this->bulk_actions ?: [], fn($object)=> array_filter($object->get_data_attr(['bulk'=>true]))),286 'overall_actions' => array_values($this->get_action s(array_diff($this->overall_actions ?: [], $this->next_actions ?: []), ['class'=>'button overall-action']))291 'column_count' => [$this, ($this->builtin ? 'builtin_' : '').'get_column_count'](), 292 'bulk_actions' => array_map(fn($v)=> array_filter($v->get_data_attr(['bulk'=>true])), $this->bulk_actions ?: []), 293 'overall_actions' => array_values($this->get_action(array_diff($this->overall_actions ?: [], $this->next_actions ?: []), ['class'=>'button overall-action'])) 287 294 ]; 288 295 } 289 296 290 protected function get_actions($names, $args=[]){291 return wpjam_fill($names ?: [], fn($k)=> $this->get_action($k, $args));292 }293 294 297 public function get_action($name, ...$args){ 298 if(is_array($name)){ 299 return wpjam_fill($name ?: [], fn($n)=> $this->get_action($n, ...$args)); 300 } 301 295 302 return ($object = $this->component('action', $name)) && $args ? $object->render($args[0]) : $object; 296 303 } 297 304 298 public function get_row_action($id, $args =[]){299 return $this->get_action( ...(isset($args['name']) ? [wpjam_pull($args, 'name'), $args+['id'=>$id]] : [$id, $args]));305 public function get_row_action($id, $args){ 306 return $this->get_action(wpjam_pull($args, 'name'), $args+['id'=>$id]); 300 307 } 301 308 … … 321 328 $attr = $id ? ['id'=>$this->singular.'-'.str_replace('.', '-', $id), 'data'=>['id'=>$id]] : []; 322 329 323 $item['row_actions'] = $id ? $this-> filter_row_actions([], $item) : ($this->row_actions ? ['error'=>'Primary Key「'.$this->primary_key.'」不存在'] : []);330 $item['row_actions'] = $id ? $this->get_row_actions($id) : ($this->row_actions ? ['error'=>'Primary Key「'.$this->primary_key.'」不存在'] : []); 324 331 325 332 $this->before_single_row_by_model($raw); … … 338 345 public function single_date($item, $date){ 339 346 $parts = explode('-', $date); 340 $append = ($item || $parts[1] == $this->get_date()['month']) ? wpjam_tag('div', ['row-actions', 'alignright'])->append($this-> filter_row_actions([], ['id'=>$date, 'wrap'=>'<span class="%s"></span>'])) : '';347 $append = ($item || $parts[1] == $this->get_date()['month']) ? wpjam_tag('div', ['row-actions', 'alignright'])->append($this->get_row_actions($date)) : ''; 341 348 342 349 echo wpjam_tag('div', ['date-meta'])->append('span', ['day', $date == wpjam_date('Y-m-d') ? 'today' : ''], (int)$parts[2])->append($append)->after('div', ['date-content'], $this->render_date_by_model($item, $date) ?? (is_string($item) ? $item : '')); … … 348 355 349 356 protected function parse_cell($cell, $id){ 350 if(!is_array($cell)){351 return $cell;352 }353 354 357 $wrap = wpjam_pull($cell, 'wrap'); 355 358 … … 376 379 if($type == 'image'){ 377 380 $ar = wpjam_pick($data, ['width', 'height']); 378 $v = wpjam_tag('img', ['src'=>wpjam_get_thumbnail($v, wpjam_map($ar, fn($s)=> $s*2))]+$ar)->after('span', ['item-title'], $item['title'] ?? '');381 $v = wpjam_tag('img', ['src'=>wpjam_get_thumbnail($v, array_map(fn($s)=> $s*2), $ar)]+$ar)->after('span', ['item-title'], $item['title'] ?? ''); 379 382 } 380 383 … … 383 386 $cell->append(wpjam_tag('div', ['id'=>'item_'.$i, 'data'=>['i'=>$i], 'class'=>'item'])->append([ 384 387 $this->get_action('move_item', $args+['title'=>$v, 'fallback'=>true])->style(wpjam_pick($item, ['color'])), 385 wpjam_tag('span', ['row-actions'])->append($this->get_action s(array_diff($names, ['add_item']), $args+['wrap'=>'<span class="%s"></span>', 'item'=>$item]))388 wpjam_tag('span', ['row-actions'])->append($this->get_action(array_diff($names, ['add_item']), $args+['wrap'=>'<span class="%s"></span>', 'item'=>$item])) 386 389 ])); 387 390 } … … 403 406 $value = $object && $id ? $object($args+['data'=>$item, 'id'=>$id]) : (is_array($item) ? ($item[$name] ?? null) : $item); 404 407 405 return wp_is_numeric_array($value) ? implode(',', array_map(fn($v)=> $this->parse_cell($v, $id), $value)) : $this->parse_cell($value, $id);408 return implode(',', array_map(fn($v)=> is_array($v) ? $this->parse_cell($v, $id) : $v, wp_is_numeric_array($value) ? $value : [$value])); 406 409 } 407 410 408 411 public function column_cb($item){ 409 412 if(($id = $this->parse_id($item)) && wpjam_can($this->capability, $id)){ 410 return wpjam_tag('input', ['type'=>'checkbox', 'name'=>'ids[]', 'value'=>$id, 'id'=>'cb-select-'.$id, 'title'=>'选择'.strip_tags($item[$this-> get_primary_column_name()] ?? $id)]);413 return wpjam_tag('input', ['type'=>'checkbox', 'name'=>'ids[]', 'value'=>$id, 'id'=>'cb-select-'.$id, 'title'=>'选择'.strip_tags($item[$this->primary_column] ?? $id)]); 411 414 } 412 415 } 413 416 414 417 public function render(){ 415 $form = wpjam_tag('form', ['id'=>'list_table_form'])->append([$this->get_search_box(), $this->get_table()])->before($this->ob_get_views()); 416 417 return $this->layout == 'left' ? wpjam_tag('div', ['id'=>'col-container', 'class'=>'wp-clearfix'])->append(wpjam_map([ 418 'left' => wpjam_wrap($this->ob_get_col_left(), 'form'), 419 'right' => $form 420 ], fn($v, $k)=> $v->add_class('col-wrap')->wrap('div', ['id'=>'col-'.$k]))) : $form; 421 } 422 423 public function get_search_box(){ 424 $fields = $this->searchable_fields; 425 426 if($this->search ?? $fields){ 427 $box = $this->ob_get_search_box('搜索', 'wpjam') ?: wpjam_tag('p', ['search-box']); 428 $field = wpjam_is_assoc_array($fields) ? wpjam_field(['key'=>'search_columns', 'value'=>$this->get_data('search_columns'), 'type'=>'select', 'show_option_all'=>'默认', 'options'=>$fields]) : ''; 429 430 return $field ? wpjam_preg_replace('/(<p class="search-box">)/is', '$1'.$field, $box) : $box; 431 } 432 } 433 434 public function get_table(){ 435 return $this->ob_get_display(); 418 $form = wpjam_tag('form', ['id'=>'list_table_form'], $this->ob_get_display())->before($this->ob_get_views()); 419 420 return $this->layout == 'left' ? wpjam_tag('div', ['id'=>'col-container', 'class'=>'wp-clearfix'])->append(array_map(fn($v, $k)=> $v->add_class('col-wrap')->wrap('div', ['id'=>'col-'.$k]), [wpjam_wrap($this->ob_get_col_left(), 'form'), $form], ['left', 'right'])) : $form; 436 421 } 437 422 … … 439 424 $paged = (int)$this->get_data('left_paged') ?: 1; 440 425 441 if( $cb = wpjam_callback($this->model.'::query_left')){426 if(($cb = $this->model.'::query_left') && wpjam_callback($cb)){ 442 427 static $pages, $items; 443 428 … … 458 443 ['p', ['row-title'], $item['title']], 459 444 ['span', ['time'], $item['time']], 460 ...(isset($item['count']) ? wpjam_map((array)$item['count'], fn($v)=> ['span', ['count', 'wp-ui-highlight'], $v]) : [])445 ...(isset($item['count']) ? array_map(fn($v)=> ['span', ['count', 'wp-ui-highlight'], $v], (array)$item['count']) : []) 461 446 ] : $item)->wrap('tr', is_array($item) ? ['class'=>'left-item', 'id'=>$item['id'], 'data-id'=>$item['id']] : ['no-items']))); 462 447 … … 478 463 public function page_load(){ 479 464 if(wp_doing_ajax()){ 480 return wpjam_ajax('wpjam-list-table-action', [465 return wpjam_ajax('wpjam-list-table-action', [ 481 466 'admin' => true, 482 467 'callback' => $this, … … 485 470 } 486 471 487 if($action = wpjam_get_parameter('export_action')){472 if($action = wpjam_get_parameter('export_action')){ 488 473 return ($object = $this->get_action($action)) ? wpjam_trap($object, 'export', 'die') : wp_die('无效的导出操作'); 489 474 } 490 475 491 wpjam_trap([$this, 'prepare_items'], fn($result)=> wpjam_admin('error', $result));476 $this->builtin || wpjam_trap([$this, 'prepare_items'], fn($result)=> wpjam_admin('error', $result)); 492 477 } 493 478 … … 531 516 } 532 517 533 protected function get_default_primary_column_name(){534 return $this->primary_column ?: array_find_key($this->get_columns(), fn($v, $k)=> !in_array($k, ['no', 'cb']));535 }536 537 518 protected function handle_row_actions($item, $column, $primary){ 538 519 return ($primary === $column && !empty($item['row_actions'])) ? $this->row_actions($item['row_actions']) : ''; … … 540 521 541 522 public function get_columns(){ 542 return $this->filter_columns();523 return []; 543 524 } 544 525 … … 546 527 if($this->layout == 'calendar'){ 547 528 echo wpjam_tag('h2', [], $this->get_date('locale')); 548 echo wpjam_tag('span', ['pagination-links'])->append( wpjam_map(['prev'=>'‹', 'current'=>'今日', 'next'=>'›'], fn($v, $k)=> "\n".$this->get_filter_link($this->get_date($k), $v, ['class'=>$k.'-month button', 'title'=>$this->get_date($k, 'locale')])))->wrap('div', ['tablenav-pages']);549 } 550 551 if($which == 'top' && ($fields = (wpjam_ admin('chart','get_fields') ?: [])+array_filter($this->filterable_fields))){529 echo wpjam_tag('span', ['pagination-links'])->append(array_map(fn($v, $k)=> "\n".$this->get_filter_link($this->get_date($k), $v, ['class'=>$k.'-month button', 'title'=>$this->get_date($k, 'locale')]), ['‹', '今日', '›'], ['prev', 'current', 'next']))->wrap('div', ['tablenav-pages']); 530 } 531 532 if($which == 'top' && ($fields = (wpjam_chart('get_fields') ?: [])+array_filter($this->filterable_fields))){ 552 533 echo wpjam_fields($fields, ['fields_type'=>'', 'data'=>$this->params])->wrap('div', ['actions'])->append(get_submit_button('筛选', '', 'filter_action', false)); 553 534 } … … 854 835 $fields = wpjam_try('maybe_callback', $this->fields, $arg, $this->name) ?: wpjam_try($this->model.'::get_fields', $this->name, $arg); 855 836 $fields = array_merge(is_array($fields) ? $fields : [], ($prev ? $this->get_prev_fields($arg, true, '') : [])); 856 $fields = ($cb = wpjam_callback($this->model.'::filter_fields')) ? wpjam_try($cb, $fields, $arg, $this->name) : $fields;837 $fields = ($cb = $this->model.'::filter_fields') && wpjam_callback($cb) ? wpjam_try($cb, $fields, $arg, $this->name) : $fields; 857 838 858 839 if(!in_array($this->name, ['add', 'duplicate']) && isset($fields[$this->primary_key])){ … … 957 938 public function __invoke($args){ 958 939 $id = $args['id']; 959 $value = $this->_field->val(null)->value_callback($args) ?? wpjam_value _callback($args, $this->name) ?? $this->default;940 $value = $this->_field->val(null)->value_callback($args) ?? wpjam_value($args, $this->name) ?? $this->default; 960 941 961 942 if(wpjam_is_assoc_array($value)){ … … 1048 1029 class WPJAM_Builtin_List_Table extends WPJAM_List_Table{ 1049 1030 public function __construct($args){ 1050 $screen = get_current_screen(); 1051 $data_type = wpjam_admin('data_type', $args['data_type']); 1031 $data_type = wpjam_admin(wpjam_pick($args, ['data_type', 'meta_type']))['data_type']; 1052 1032 1053 1033 if($data_type == 'post_type'){ 1054 $parts = $screen->id == 'upload' ? ['media', 'media'] : ($args['hierarchical'] ? ['pages', 'page', 'posts'] : ['posts', 'post', 'posts']); 1055 $args += ['builtin'=> $parts[0] == 'media' ? 'WP_Media_List_Table' : 'WP_Posts_List_Table']; 1034 $echo = 'echo'; 1035 $builtin = $args['post_type'] == 'attachment' ? 'Media' : 'Posts'; 1036 $callback = 'get_post'; 1037 $parts = $builtin == 'Media' ? ['media', 'media'] : ($args['hierarchical'] ? ['pages', 'page', 'posts'] : ['posts', 'post', 'posts']); 1056 1038 }elseif($data_type == 'taxonomy'){ 1057 $args += ['builtin'=>'WP_Terms_List_Table']; 1058 $parts = [$args['taxonomy'], $args['taxonomy']]; 1039 $builtin = 'Terms'; 1040 $callback = ['get_term', 'get_term_level']; 1041 $parts = [$args['taxonomy'], $args['taxonomy']]; 1059 1042 }elseif($data_type == 'user'){ 1060 $args += ['builtin'=>'WP_Users_List_Table']; 1061 $parts = ['users', 'user', 'users']; 1043 $builtin = 'Users'; 1044 $callback = 'get_userdata'; 1045 $parts = ['users', 'user', 'users']; 1062 1046 }elseif($data_type == 'comment'){ 1063 $args += ['builtin'=>'WP_Comments_List_Table']; 1064 $parts = ['comments', 'comment']; 1065 } 1066 1067 wpjam_admin('meta_type', $args['meta_type'] ?? ''); 1068 1069 add_filter('manage_'.$screen->id.'_columns', [$this, 'filter_columns']); 1070 add_filter('manage_'.$parts[0].'_custom_column',[$this, 'filter_custom_column'], 10, in_array($data_type, ['post_type', 'comment']) ? 2 : 3); 1071 1072 add_filter($parts[1].'_row_actions', [$this, 'filter_row_actions'], 1, 2); 1047 $echo = 'echo'; 1048 $builtin = 'Comments'; 1049 $callback = 'get_comment'; 1050 $parts = ['comments', 'comment']; 1051 } 1052 1053 wpjam_hook(($echo ?? ''), 'manage_'.$parts[0].'_custom_column', fn(...$args)=> $this->column_default(...array_pad($args, -3, [])), 10, 3); 1054 1055 add_filter($parts[1].'_row_actions', [$this, 'filter_row_actions'], 1, 2); 1073 1056 1074 1057 isset($parts[2]) && add_action('manage_'.$parts[2].'_extra_tablenav', [$this, 'extra_tablenav']); 1075 in_array($data_type, ['post_type', 'taxonomy']) && add_action('parse_term_query', [$this, 'on_parse_query'], 0); 1058 1076 1059 wp_is_json_request() || add_filter('wpjam_html', [$this, 'filter_table']); 1077 1060 1078 parent::__construct($args); 1079 } 1080 1081 public function views(){ 1082 $this->screen->id != 'upload' && $this->builtin_views(); 1083 } 1084 1085 public function display_tablenav($which){ 1086 $this->builtin_display_tablenav($which); 1087 } 1088 1089 public function get_table(){ 1090 return $this->filter_table($this->ob_get_builtin_display()); 1061 in_array($data_type, ['post_type', 'taxonomy']) && add_action('parse_term_query', function($query){ 1062 if(array_any(debug_backtrace(), fn($v)=> wpjam_get($v, 'class') == $this->builtin)){ 1063 $vars = &$query->query_vars; 1064 $by = $vars['orderby'] ?? ''; 1065 $object = ($by && is_string($by)) ? $this->component('column', $by) : null; 1066 $type = $object ? ($object->sortable === true ? 'meta_value' : $object->sortable) : ''; 1067 $vars = array_merge($vars, ['list_table_query'=>true], in_array($type, ['meta_value_num', 'meta_value']) ? ['orderby'=>$type, 'meta_key'=>$by] : []); 1068 } 1069 }, 0); 1070 1071 parent::__construct($args+['builtin'=>'WP_'.$builtin.'_List_Table', 'item_callback'=>$callback]); 1091 1072 } 1092 1073 1093 1074 public function prepare_items(){ 1094 if(wp_doing_ajax()){ 1095 if($this->screen->base == 'edit'){ 1096 $_GET['post_type'] = $this->post_type; 1097 } 1098 1099 $_GET = array_merge($_GET, $this->get_data()); 1100 $_POST = array_merge($_POST, $this->get_data()); 1101 1102 $this->builtin_prepare_items(); 1103 } 1075 if($this->screen->base == 'edit'){ 1076 $_GET['post_type'] = $this->post_type; 1077 } 1078 1079 $_GET = array_merge($_GET, $this->get_data()); 1080 $_POST = array_merge($_POST, $this->get_data()); 1081 1082 $this->builtin_prepare_items(); 1104 1083 } 1105 1084 1106 1085 public function single_row($item){ 1107 if($this->data_type == 'post_type'){ 1108 global $post, $authordata; 1109 1110 $post = is_numeric($item) ? get_post($item) : $item; 1111 1112 if($post){ 1113 $authordata = get_userdata($post->post_author); 1114 1115 if($post->post_type == 'attachment'){ 1116 echo wpjam_tag('tr', ['id'=>'post-'.$post->ID], $this->ob_get_builtin_single_row_columns($post))->add_class(['author-'.((get_current_user_id() == $post->post_author) ? 'self' : 'other'), 'status-'.$post->post_status]); 1117 }else{ 1118 $args = [$post]; 1119 } 1120 } 1121 }elseif($this->data_type == 'taxonomy'){ 1122 $term = is_numeric($item) ? get_term($item) : $item; 1123 $args = $term ? [$term, get_term_level($term)] : []; 1124 }elseif($this->data_type == 'user'){ 1125 $user = is_numeric($item) ? get_userdata($item) : $item; 1126 $args = $user ? [$user] : []; 1127 }elseif($this->data_type == 'comment'){ 1128 $comment = is_numeric($item) ? get_comment($item) : $item; 1129 $args = $comment ? [$comment] : []; 1130 } 1131 1132 echo empty($args) ? '' : $this->filter_table($this->ob_get_builtin_single_row(...$args)); 1133 } 1134 1135 public function on_parse_query($query){ 1136 if(array_any(debug_backtrace(), fn($v)=> wpjam_get($v, 'class') == $this->builtin)){ 1137 $vars = &$query->query_vars; 1138 $by = $vars['orderby'] ?? ''; 1139 $object = ($by && is_string($by)) ? $this->component('column', $by) : null; 1140 $type = $object ? ($object->sortable === true ? 'meta_value' : $object->sortable) : ''; 1141 $vars = array_merge($vars, ['list_table_query'=>true], in_array($type, ['meta_value_num', 'meta_value']) ? ['orderby'=>$type, 'meta_key'=>$by] : []); 1086 $cb = (array)$this->item_callback; 1087 1088 if($item = is_numeric($item) ? (array_shift($cb))($item) : $item){ 1089 if($this->data_type == 'post_type' && $item->post_type == 'attachment'){ 1090 $GLOBALS['authordata'] = get_userdata($item->post_author); 1091 1092 echo wpjam_tag('tr', ['id'=>'post-'.$item->ID], $this->ob_get_single_row_columns($item))->add_class(['author-'.(get_current_user_id() == $item->post_author ? 'self' : 'other'), 'status-'.$item->post_status]); 1093 }else{ 1094 $this->builtin_single_row($item, ...array_map(fn($v)=> $v($item), $cb)); 1095 } 1142 1096 } 1143 1097 } -
wpjam-basic/trunk/includes/class-wpjam-model.php
r3427374 r3454739 337 337 } 338 338 339 $vars += ['post_status'=>'publish', 'post__not_in'=>[$post->ID], 'post_type'=>array_unique($type), ' term_taxonomy_ids'=>wpjam_filter($tt_ids, 'unique')];339 $vars += ['post_status'=>'publish', 'post__not_in'=>[$post->ID], 'post_type'=>array_unique($type), 'orderby'=>'related', 'term_taxonomy_ids'=>wpjam_filter($tt_ids, 'unique')]; 340 340 } 341 341 -
wpjam-basic/trunk/includes/class-wpjam-post.php
r3423058 r3454739 586 586 add_filter('posts_clauses', function($clauses, $query){ 587 587 $wpdb = $GLOBALS['wpdb']; 588 $orderby = $query->get(' related_query') ? 'related' : $query->get('orderby');588 $orderby = $query->get('orderby'); 589 589 $order = $query->get('order') ?: 'DESC'; 590 590 591 591 if($orderby == 'related'){ 592 if($tt_ids = $query->get('term_taxonomy_ids')){592 if($tt_ids = $query->get('term_taxonomy_ids')){ 593 593 $clauses['join'] .= "INNER JOIN {$wpdb->term_relationships} AS tr ON {$wpdb->posts}.ID = tr.object_id"; 594 594 $clauses['where'] .= " AND tr.term_taxonomy_id IN (".implode(",", $tt_ids).")"; -
wpjam-basic/trunk/includes/class-wpjam-user.php
r3440469 r3454739 665 665 wp_enqueue_script('wpjam-login', wpjam_url(dirname(__DIR__).'/static/login.js'), ['wpjam-ajax']); 666 666 667 add_action('login_form', fn()=> wpjam_echo(wpjam_tag('p')->add_class('types')->data('action', $action)->append($append)));667 wpjam_hook('echo', 'login_form', fn()=> wpjam_tag('p')->add_class('types')->data('action', $action)->append($append)); 668 668 } 669 669 -
wpjam-basic/trunk/public/wpjam-compat.php
r3440469 r3454739 289 289 } 290 290 291 function wpjam_sum($items, $keys){ 292 return array_reduce($items, fn($sum, $item)=> array_map(fn($k)=> $sum[$k]+(is_numeric($v = str_replace(',', '', ($item[$k] ?? 0))) ? $v : 0), $keys), array_fill_keys($keys, 0)); 293 } 294 291 295 function wpjam_migrate_option($from, $to, $default=null){ 292 296 if(get_option($to, $default) === $default){ … … 577 581 578 582 function wpjam_get_list_table_row_action($name, $args=[]){ 579 return $GLOBALS['wpjam_list_table']->get_ row_action($name, $args);583 return $GLOBALS['wpjam_list_table']->get_action($name, $args); 580 584 } 581 585 … … 898 902 } 899 903 904 function wpjam_line_chart($data, $labels, $args=[]){ 905 echo wpjam_chart('line', $data, ['labels'=>$labels]+$args); 906 } 907 908 function wpjam_bar_chart($data, $labels, $args=[]){ 909 echo wpjam_chart('bar', $data, ['labels'=>$labels]+$args); 910 } 911 912 function wpjam_donut_chart($data, ...$args){ 913 echo wpjam_chart('donut', $data, (count($args) >= 2 ? ['labels'=>array_shift($args)] : [])+($args[0] ?? [])); 914 } 915 916 function wpjam_get_chart_parameter(...$args){ 917 return wpjam_chart('get_parameter', ...$args); 918 } 919 900 920 function wpjam_stats_header($args=[]){ 901 921 global $wpjam_stats_labels; … … 1008 1028 } 1009 1029 1010 function_alias('wpjam_add_once_filter', 'wpjam_add_once_action'); 1011 1012 function_alias('wpjam_hook', 'wpjam_add_filter'); 1013 function_alias('wpjam_hook', 'wpjam_add_action'); 1014 1015 function_alias('wpjam_option', 'wpjam_setting'); 1030 function_alias('wpjam_every', 'array_all'); 1031 function_alias('wpjam_some', 'array_any'); 1032 function_alias('wpjam_array', 'array_wrap'); 1033 function_alias('wpjam_get', 'array_get'); 1034 function_alias('wpjam_set', 'array_set'); 1035 function_alias('wpjam_merge', 'merge_deep'); 1036 1037 function_alias('wpjam_hook', 'wpjam_add_filter'); 1038 1039 function_alias('wpjam_option', 'wpjam_setting'); 1016 1040 1017 1041 function_alias('wpjam_ob', 'wpjam_ob_get_contents'); -
wpjam-basic/trunk/public/wpjam-functions.php
r3440469 r3454739 174 174 175 175 function wpjam_is_json_request(){ 176 return get_option('permalink_structure') ? (bool)preg_match("/\/api\/.*\.json/", $_SERVER['REQUEST_URI']) : wpjam_get_parameter('module') == 'json';176 return get_option('permalink_structure') ? (bool)preg_match("/\/api\/.*\.json/", $_SERVER['REQUEST_URI']) : (($_GET['module'] ?? '') == 'json'); 177 177 } 178 178 … … 478 478 } 479 479 480 function wpjam_pagenavi($total=0, $ echo=true){480 function wpjam_pagenavi($total=0, $display=true){ 481 481 $result = '<div class="pagenavi">'.paginate_links(array_filter(['prev_text'=>'«', 'next_text'=>'»', 'total'=>$total])).'</div>'; 482 482 483 return $ echo? wpjam_echo($result) : $result;483 return $display ? wpjam_echo($result) : $result; 484 484 } 485 485 … … 675 675 return ($comment = get_comment($comment_id)) ? $comment->comment_parent : null; 676 676 } 677 } 678 679 // Shortcode 680 function wpjam_do_shortcode($content, $tags, $ignore_html=false){ 681 if(wpjam_is_assoc_array($tags)){ 682 $tags = array_keys(wpjam_map($tags, fn($cb, $tag)=> shortcode_exists($tag) || add_shortcode($tag, $cb))); 683 } 684 685 if($tags && array_any($tags, fn($tag)=> str_contains($content, '['.$tag))){ 686 $content = do_shortcodes_in_html_tags($content, $ignore_html, $tags); 687 $content = preg_replace_callback('/'.get_shortcode_regex($tags).'/', 'do_shortcode_tag', $content); 688 $content = unescape_invalid_shortcodes($content); 689 } 690 691 return $content; 692 } 693 694 function wpjam_parse_shortcode_attr($str, $tag){ 695 return preg_match('/'.get_shortcode_regex((array)$tag).'/', $str, $m) ? shortcode_parse_atts($m[3]) : []; 677 696 } 678 697 … … 795 814 $upload = wp_upload_bits($name, null, $bits); 796 815 }else{ 797 $args += ['test_form'=>false]; 816 wpjam_validate_mime_types($args['mimes'] ?? []) && ($args += ['test_form'=>false]); 817 798 818 $upload = is_array($name) ? wp_handle_sideload($name, $args) : wp_handle_upload($_FILES[$name], $args); 799 819 } … … 966 986 } 967 987 988 function wpjam_validate_mime_types($mimes){ 989 $allowed = get_allowed_mime_types(); 990 991 foreach($mimes as $k => $v){ 992 $ext = array_search($v, $allowed); 993 994 if(!$ext || array_diff(explode('|', $k), explode('|', $ext))){ 995 wpjam_throw('upload_error', '无效的文件类型'); 996 } 997 } 998 999 return true; 1000 } 1001 968 1002 function wpjam_accept_to_mime_types($accept){ 969 1003 $allowed = get_allowed_mime_types(); … … 1016 1050 // Field 1017 1051 function wpjam_fields($fields, ...$args){ 1018 if(is_object($fields)){ 1019 $object = $fields; 1020 $fields = []; 1021 1022 foreach($object->get_arg('_fields[]') as $key => $field){ 1023 if(is_callable($field)){ 1024 $result = wpjam_try($field, ...$args); 1025 1026 if(is_numeric($key)){ 1027 $fields = array_merge($fields, $result); 1028 }else{ 1029 $fields[$key] = $result; 1030 } 1031 }elseif(wpjam_is_assoc_array($field)){ 1032 $fields[$key] = $field; 1033 } 1034 } 1035 1036 return $fields; 1037 } 1038 1039 if($args && is_bool($args[0])){ 1040 return WPJAM_Fields::parse($fields, $args[0]); 1052 if(is_object($fields) || ($args && is_bool($args[0]))){ 1053 return WPJAM_Fields::parse($fields, ...$args); 1041 1054 } 1042 1055 … … 1045 1058 $object = WPJAM_Fields::create($fields, $args); 1046 1059 1047 if($echo){ 1048 echo $object; // del 2026-06-30 1049 } 1050 1051 return $object; 1060 return $echo ? wpjam_echo($object) : $object; 1052 1061 } 1053 1062 1054 1063 function wpjam_field($field, ...$args){ 1055 1064 if(is_object($field)){ 1056 $object = $field; 1057 $key = array_shift($args); 1058 1059 if(is_array($key)){ 1060 return wpjam_reduce($key, fn($c, $v, $k)=> wpjam_field($object, $k, $v), $object); 1061 } 1062 1063 if(!$args && is_callable($key)){ 1064 [$args, $key] = [[$key], '']; 1065 } 1066 1067 return [$object, $args ? 'update_arg' : 'delete_arg']('_fields['.$key.']', ...$args); 1068 }elseif(is_array($field)){ 1065 return WPJAM_Field::parse($field, ...$args); 1066 } 1067 1068 if(is_array($field)){ 1069 $args = $args[0] ?? []; 1070 $echo = wpjam_pull($field, 'echo') ?? wpjam_pull($args, 'echo'); 1069 1071 $object = WPJAM_Field::create($field); 1070 $args = $args[0] ?? []; 1071 1072 return $args ? (isset($args['wrap_tag']) ? $object->wrap(wpjam_pull($args, 'wrap_tag'), $args) : $object->render($args)) : $object; 1072 $wrap = wpjam_pull($args, 'wrap_tag'); 1073 $result = isset($wrap) ? $object->wrap($wrap, $args) : ($args ? $object->render($args) : $object); 1074 1075 return $echo ? wpjam_echo($result) : $result; 1076 } 1077 } 1078 1079 function wpjam_parse_show_if($if){ 1080 if(wp_is_numeric_array($if) && count($if) >= 2){ 1081 $keys = count($if) == 2 ? ['key', 'value'] : ['key', 'compare', 'value']; 1082 1083 if(count($if) > 3){ 1084 if(is_array($if[3])){ 1085 $args = $if[3]; 1086 1087 trigger_error(var_export($args, true)); // del 2025-12-30 1088 } 1089 1090 $if = array_slice($if, 0, 3); 1091 } 1092 1093 return array_combine($keys, $if)+($args ?? []); 1094 }elseif(is_array($if) && !empty($if['key'])){ 1095 return $if; 1073 1096 } 1074 1097 } … … 1143 1166 } 1144 1167 1145 $notice = wpjam_pull($data, 'notice'); 1146 $errmsg = wpjam_pull($data, 'errmsg'); 1147 $notice = !$notice && $errmsg && $errmsg != 'ok' ? $errmsg : ''; // 第三方接口可能返回 ok 1148 1149 return ['notice'=>$notice]; 1150 } 1168 return ['notice'=>wpjam_pull($data, 'notice') ?: (($errmsg = wpjam_pull($data, 'errmsg')) && $errmsg != 'ok' ? $errmsg : '')]; // 第三方接口可能返回 ok 1169 } 1170 } 1171 1172 // translate 1173 function wpjam_translate($text, ...$args){ 1174 if(($domain = wpjam_at($args, -1)) != 'default'){ 1175 $cb = 'translate'.(count($args) >= 2 ? '_with_gettext_context' : ''); 1176 1177 if($domain === 'wpjam' && ($low = strtolower($text)) !== $text && count(explode(' ', $text)) <= 2 && ($trans = $cb($low, ...$args)) != $low){ 1178 return $trans; 1179 } 1180 1181 return $cb($text, ...array_slice($args, 0, -1)); 1182 } 1183 1184 return $text; 1151 1185 } 1152 1186 -
wpjam-basic/trunk/public/wpjam-route.php
r3440469 r3454739 63 63 } 64 64 65 if($name && $args){ 66 if(wp_is_numeric_array($args[0]) && !is_callable($args[0])){ 67 return wpjam_map(array_shift($args), fn($cb)=> wpjam_hook($type, $name, $cb, ...$args)); 68 } 69 70 return wpjam_hook($type, $name, ...$args); 65 if($name && $args && ($cb = array_shift($args))){ 66 return wpjam_map(wp_is_numeric_array($cb) && !is_callable($cb) ? $cb : [$cb], fn($cb)=> wpjam_hook($type, $name, $cb, ...$args)); 71 67 } 72 68 } … … 77 73 } 78 74 79 $ once = $name === 'once';80 $name = ($ once|| !$name) ? array_shift($args) : $name;75 $attr = in_array($name, ['once', 'echo', 'tap'], true) ? [$name => true] : []; 76 $name = ($attr || !$name) ? array_shift($args) : $name; 81 77 $cb = array_shift($args); 82 $assoc = wpjam_is_assoc_array($cb); 83 84 if($once || $assoc){ 85 $object = wpjam_args(($once ? ['once'=>$once] : [])+($assoc ? $cb : ['callback'=>$cb])); 78 79 if($attr += wpjam_is_assoc_array($cb) ? $cb : ($attr ? ['callback'=>$cb] : [])){ 80 $object = wpjam_args($attr); 86 81 $cb = wpjam_bind(function(...$args){ 87 82 if($this->check && !($this->check)(...$args)){ … … 89 84 } 90 85 91 if($this->once === true){86 if($this->once){ 92 87 $hook = $GLOBALS['wp_filter'][current_filter()]; 93 88 … … 95 90 } 96 91 97 return ($this->callback)(...$args); 92 $result = ($this->callback)(...$args); 93 94 if($this->echo){ 95 echo $result; 96 } 97 98 return $this->tap ? $args[0] : $result; 98 99 }, $object); 99 100 … … 106 107 } 107 108 108 function wpjam_bind($cb, $args){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;116 }117 118 109 function wpjam_callback($cb, $parse=false, &$args=[]){ 119 if(is_string($cb) && ($sep = array_find(['::', '->'], fn($v)=> str_contains($cb, $v)))){110 if(is_string($cb) && ($sep = array_find(['::', '->'], fn($v)=> str_contains($cb, $v)))){ 120 111 $static = $sep == '::'; 121 112 $cb = explode($sep, $cb, 2); … … 164 155 return $cb(...$args); 165 156 } 157 } 158 159 function wpjam_call_multiple($cb, $args){ 160 return array_map(fn($v)=> wpjam_call($cb, ...(array)$v), $args); 161 } 162 163 function wpjam_bind($cb, $args){ 164 return is_closure($cb) ? $cb->bindTo(...array_fill(0, 2, is_object($args) ? $args : wpjam_args($args))) : $cb; 166 165 } 167 166 … … 201 200 } 202 201 203 function wpjam_value_callback($args, $name){ 202 function wpjam_value($model, $name, ...$args){ 203 if(is_string($model)){ 204 return wpjam_call($model.'::get_'.$name, ...$args); 205 } 206 207 $args = $model; 204 208 $names = (array)$name; 205 209 $key = 'value_callback'; … … 214 218 $model = $args['model'] ?? ''; 215 219 216 if($id && count($names) >= 2 && $names[0] == 'meta_input' && ($meta_type = ($args['meta_type'] ?? '') ?: wpjam_ call($model.'::get_meta_type'))){220 if($id && count($names) >= 2 && $names[0] == 'meta_input' && ($meta_type = ($args['meta_type'] ?? '') ?: wpjam_value($model, 'meta_type'))){ 217 221 $args['meta_type'] = $meta_type; 218 222 … … 249 253 return $cb(); 250 254 }finally{ 251 array_map(fn($args)=> add_filter(...$args), $suppressed);255 wpjam_call_multiple('add_filter', $suppressed); 252 256 } 253 257 } … … 278 282 $ref = class_exists($cb[0]) ? wpjam_var('reflection:class['.strtolower($cb[0]).']', fn()=> new ReflectionClass($cb[0])) : null; 279 283 }else{ 280 $ref = ($cb = wpjam_callback($cb)) ? wpjam_var('reflection:cb['.wpjam_build_callback_unique_id($cb).']', is_array($cb) ? new ReflectionMethod(...$cb) : new ReflectionFunction($cb)) : null;284 $ref = ($cb = wpjam_callback($cb)) ? wpjam_var('reflection:cb['.wpjam_build_callback_unique_id($cb).']', fn()=> is_array($cb) ? new ReflectionMethod(...$cb) : new ReflectionFunction($cb)) : null; 281 285 } 282 286 … … 617 621 618 622 if(is_array($name)){ 619 return $name ? wpjam_map( (wp_is_numeric_array($name) ? array_fill_keys($name, $args) : $name), fn($v, $n)=> wpjam_get_parameter($n, $v)) : [];623 return $name ? wpjam_map(wp_is_numeric_array($name) ? array_fill_keys($name, $args) : $name, 'wpjam_get_parameter', 'kv') : []; 620 624 } 621 625 … … 783 787 function wpjam_route($module, $args, $query_var=false){ 784 788 if(is_string($args) && class_exists($args)){ 785 foreach(['rewrite_rule', 'menu_page', 'admin_load'] as $k){ 786 if($k == 'rewrite_rule' || is_admin()){ 787 $v = wpjam_callback([$args, 'get_'.$k]); 788 $v && ('wpjam_add_'.$k)($k == 'rewrite_rule' ? $v : maybe_callback($v)); 789 } 790 } 791 792 $args = ['callback'=>$args.'::redirect']; 789 $model = $args; 790 $args = ['callback'=>$model.'::redirect']; 791 792 wpjam_init(fn()=> ($rules = wpjam_value($model, 'rewrite_rule')) && is_array($rules) && wpjam_call_multiple('wpjam_add_rewrite_rule', is_array($rules[0]) ? $rules : [$rules])); 793 794 is_admin() && array_map(fn($k)=> wpjam_call('wpjam_add_'.$k, wpjam_value($model, $k)), ['menu_page', 'admin_load']); 793 795 }else{ 794 796 $args = wpjam_is_assoc_array($args) ? array_filter($args) : ['callback'=>$args]; … … 802 804 if(!wpjam('route')){ 803 805 add_filter('query_vars', fn($vars)=> array_merge($vars, ['module', 'action', 'term_id']), 11); 804 add_filter('request', fn($vars)=> wpjam_parse_query_vars($vars), 11);806 add_filter('request', 'wpjam_parse_query_vars', 11); 805 807 add_action('parse_request', 'wpjam_dispatch', 1); 806 808 } 807 809 808 810 wpjam('route[]', $module, $args+['query_var'=>$query_var]); 811 } 812 813 function wpjam_add_rewrite_rule(...$args){ 814 return add_rewrite_rule($GLOBALS['wp_rewrite']->root.array_shift($args), ...$args); 809 815 } 810 816 811 817 function wpjam_dispatch($module, $action=''){ 812 818 if(is_object($module)){ 813 $ wp = $module;814 $module = $ wp->query_vars['module'] ?? '';815 $action = $ wp->query_vars['action'] ?? '';819 $vars = $module->query_vars; 820 $module = $vars['module'] ?? ''; 821 $action = $vars['action'] ?? ''; 816 822 817 823 if(!$module){ … … 864 870 $result = [wpjam_get_handler(['items_type'=>'transient', 'transient'=>'wpjam-actives']), ($args ? 'add' : 'empty')](...$args); 865 871 866 return $args ? $result : wpjam_ map($result, fn($active)=> $active && count($active) >= 2 && add_action(...$active));872 return $args ? $result : wpjam_call_multiple('add_action', $result); 867 873 } 868 874 … … 1020 1026 } 1021 1027 1022 // Rewrite Rule1023 function wpjam_add_rewrite_rule($args){1024 if(did_action('init')){1025 $args = maybe_callback($args);1026 1027 if($args && is_array($args)){1028 if(is_array($args[0])){1029 array_walk($args, 'wpjam_add_rewrite_rule');1030 }else{1031 add_rewrite_rule(...[$GLOBALS['wp_rewrite']->root.array_shift($args), ...$args]);1032 }1033 }1034 }else{1035 wpjam_init(fn()=> wpjam_add_rewrite_rule($args));1036 }1037 }1038 1039 1028 // Menu Page 1040 1029 function wpjam_add_menu_page(...$args){ 1030 if(!$args[0]){ 1031 return; 1032 } 1033 1034 if(wp_is_numeric_array($args[0])){ 1035 return array_walk($args[0], 'wpjam_add_menu_page'); 1036 } 1037 1041 1038 if(is_array($args[0])){ 1042 1039 $args = $args[0]; 1043 1044 if(wp_is_numeric_array($args)){1045 return array_walk($args, 'wpjam_add_menu_page');1046 }1047 1040 }else{ 1048 1041 $key = empty($args[1]['plugin_page']) ? 'menu_slug' : 'tab_slug'; … … 1104 1097 } 1105 1098 1099 if(is_array($key)){ 1100 return wpjam_map($key, 'wpjam_admin', 'kv'); 1101 } 1102 1106 1103 if(method_exists($object, $key)){ 1107 1104 return $object->$key(...$args); … … 1114 1111 } 1115 1112 1116 if(is_object($value) ){1113 if(is_object($value) && !is_object($args[0])){ 1117 1114 return count($args) >= 2 ? ($value->{$args[0]} = $args[1]) : $value->{$args[0]}; 1118 1115 } … … 1134 1131 } 1135 1132 1133 function wpjam_chart($type='', ...$args){ 1134 if(in_array($type, ['line', 'bar', 'donut'], true)){ 1135 return ['WPJAM_Chart', $type](...$args); 1136 } 1137 1138 $object = wpjam_admin('chart', ...(is_array($type) ? [WPJAM_Chart::create($type)] : [])); 1139 1140 return $object && $type && !is_array($type) ? $object->$type(...$args) : $object; 1141 } 1142 1136 1143 function wpjam_add_admin_load($args){ 1137 if(wp_is_numeric_array($args)){ 1138 array_walk($args, 'wpjam_add_admin_load'); 1139 }else{ 1140 $type = wpjam_pull($args, 'type') ?: array_find(['base'=>'builtin_page', 'plugin_page'=>'plugin_page'], fn($v, $k)=> isset($args[$k])) ?: ''; 1141 1142 in_array($type, ['builtin_page', 'plugin_page']) && wpjam_admin($type.'_load[]', $args); 1143 } 1144 wp_is_numeric_array($args) ? array_walk($args, 'wpjam_add_admin_load') : $args && wpjam_admin('load', wpjam_pull($args, 'type'), $args); 1144 1145 } 1145 1146 … … 1180 1181 } 1181 1182 1182 function wpjam_chart($type, $data, $args){1183 }1184 1185 function wpjam_line_chart($data, $labels, $args=[]){1186 echo WPJAM_Chart::line(array_merge($args, ['labels'=>$labels, 'data'=>$data]));1187 }1188 1189 function wpjam_bar_chart($data, $labels, $args=[]){1190 echo WPJAM_Chart::line(array_merge($args, ['labels'=>$labels, 'data'=>$data]), 'Bar');1191 }1192 1193 function wpjam_donut_chart($data, ...$args){1194 $args = count($args) >= 2 ? array_merge($args[1], ['labels'=> $args[0]]) : ($args[0] ?? []);1195 1196 echo WPJAM_Chart::donut(array_merge($args, ['data'=>$data]));1197 }1198 1199 function wpjam_get_chart_parameter($key){1200 return (WPJAM_Chart::get_instance())->get_parameter($key);1201 }1202 1203 1183 function wpjam_render_callback($cb){ 1204 if(is_array($cb)){ 1205 $cb = (is_object($cb[0]) ? get_class($cb[0]).'->' : $cb[0].'::').(string)$cb[1]; 1206 }elseif(is_object($cb)){ 1207 $cb = get_class($cb); 1208 } 1209 1210 return wpautop($cb); 1184 return wpautop($is_array($cb) ? (is_object($cb[0]) ? get_class($cb[0]).'->' : $cb[0].'::').(string)$cb[1] : (is_object($cb) ? get_class($cb) : $cb)); 1211 1185 } 1212 1186 } -
wpjam-basic/trunk/public/wpjam-utils.php
r3440469 r3454739 202 202 ['firefox', 'firefox', '/firefox\/([\d\.]+)/i'], 203 203 ['opera', 'opera', '/(?:opera).([\d\.]+)/i'], 204 ['opr/', 'opera', '/(?:opr).([\d\.]+)/i'],204 ['opr/', 'opera', '/(?:opr).([\d\.]+)/i'], 205 205 ['msie', 'ie'], 206 206 ['trident', 'ie'], … … 254 254 $offset = $cache['offset']; 255 255 $index = $cache['index']; 256 $nip2 = pack('N', ip2long($nip));256 $nip2 = pack('N', ip2long($nip)); 257 257 $start = (int)$ipdot[0]*4; 258 258 $start = unpack('Vlen', $index[$start].$index[$start+1].$index[$start+2].$index[$start+3]); … … 310 310 311 311 function is_iphone(){ 312 return wpjam_get_device() == 'iP one';312 return wpjam_get_device() == 'iPhone'; 313 313 } 314 314 … … 458 458 459 459 $value2 = in_array($compare, ['IN', 'BETWEEN']) ? wp_parse_list($value2) : (is_string($value2) ? trim($value2) : $value2); 460 461 return [ 462 '=' => fn($a, $b)=> $strict ? $a === $b : $a == $b, 463 '>' => fn($a, $b)=> $a > $b, 464 '<' => fn($a, $b)=> $a < $b, 465 'IN' => fn($a, $b)=> is_array($a) ? array_all($a , fn($v)=> in_array($v, $b, $strict)) : in_array($a, $b, $strict), 466 'BETWEEN' => fn($a, $b)=> wpjam_between($a, ...$b) 467 ][$compare]($value, $value2); 460 [$a, $b]= [$value, $value2]; 461 462 switch($compare){ 463 case '=': return $a == $b; 464 case '>': return $a > $b; 465 case '<': return $a < $b; 466 case 'IN': return is_array($a) ? array_all($a , fn($v)=> in_array($v, $b, $strict)) : in_array($a, $b, $strict); 467 case 'IBETWEENN': return wpjam_between($a, ...$b); 468 } 469 } 470 471 function wpjam_calc(...$args){ 472 if(wpjam_is_assoc_array($args[0])){ 473 $item = $args[0]; 474 $formulas = $args[1]; 475 $if_errors = $args[2] ?? []; 476 $item = array_diff_key($item, $formulas); 477 478 foreach($formulas as $key => $formula){ 479 foreach($formula as &$t){ 480 if(str_starts_with($t, '$')){ 481 $k = substr($t, 1); 482 $v = $item[$k] ?? null; 483 $r = isset($v) ? wpjam_format($v, '-,', false) : false; 484 $t = $r === false ? ($if_errors[$k] ?? null) : $r; 485 486 if(!isset($t)){ 487 $item[$key] = $if_errors[$key] ?? (isset($v) ? '!!无法计算' : '!无法计算'); break; 488 } 489 } 490 } 491 492 try{ 493 $item[$key] = wpjam_calc($formula); 494 }catch(throwable $e){ 495 $item[$key] = $if_errors[$key] ?? ($e instanceof DivisionByZeroError ? '!除零错误' : '!'.$e->getMessage()); 496 } 497 } 498 499 return $item; 500 } 501 502 $exp = $args[0]; 503 $item = $args[1] ?? []; 504 $ops = ['+'=>'bcadd', '-'=>'bcsub', '*'=>'bcmul', '/'=>'bcdiv', '%'=>'bcmod', '**'=>'bcpow']; 505 $throw = fn($msg)=> wpjam_throw('invalid_calc', '计算错误:'.$msg); 506 $calc = []; 507 508 foreach(is_array($exp) ? $exp : wpjam_formula(...$args) as $t){ 509 if(is_numeric($t) || $t === '|'){ 510 $calc[] = $t; 511 }elseif(try_remove_prefix($t, '$')){ 512 $calc[] = $item[$t] ?? 0; 513 }elseif(in_array($t, ['sin', 'cos', 'abs', 'max', 'min', 'sqrt', 'pow', 'round', 'floor', 'ceil', 'fmod'])){ 514 $_args = array_slice(array_splice($calc, array_last(array_keys($calc, '|'))), 1); 515 $calc[] = $_args ? $t(...$_args) : $throw('函数「'.$t.'」无有效参数'); 516 }else{ 517 $a = array_pop($calc); 518 $b = array_pop($calc); 519 520 if(in_array($t, ['/', '%']) && in_array((string)$a, ['0', '0.0', ''])){ 521 throw new DivisionByZeroError('Division by zero'); 522 } 523 524 $calc[] = isset($ops[$t]) ? $ops[$t]((string)$b, (string)$a, 6) : wpjam_compare($b, $t, $a); 525 } 526 } 527 528 return count($calc) === 1 ? $calc[0] : $throw('计算栈剩余元素数还有'.count($calc).'个'); 529 } 530 531 function wpjam_formula(...$args){ 532 if(is_array($args[0])){ 533 $fields = array_shift($args); 534 535 if($args){ 536 $render = fn($key)=> '字段'.($fields[$key]['title'] ?? '').'「'.$key.'」'.'公式「'.$fields[$key]['formula'].'」'; 537 $key = $args[0]; 538 $parsed = $args[1]; 539 $path = $args[2] ?? []; 540 541 if(isset($parsed[$key])){ 542 return $parsed; 543 } 544 545 if(in_array($key, $path)){ 546 wpjam_throw('invalid_formula', '公式嵌套:'.implode(' → ', wpjam_map(array_slice($path, array_search($key, $path)), fn($k)=> $render($k)))); 547 } 548 549 $path[] = $key; 550 $formula = wpjam_formula($fields[$key]['formula'], $fields, $render($key).'错误'); 551 $parsed = array_reduce($formula, fn($c, $t)=> try_remove_prefix($t, '$') && !empty($fields[$t]['formula']) ? wpjam_formula($fields, $t, $c, $path) : $c, $parsed); 552 553 return $parsed+[$key => $formula]; 554 } 555 556 return wpjam_reduce($fields, fn($c, $v, $k)=> empty($v['formula']) ? $c : wpjam_formula($fields, $k, $c), []); 557 } 558 559 $formula = $args[0]; 560 $fields = $args[1] ?? []; 561 $error = $args[2] ?? ''; 562 $throw = fn($msg)=> wpjam_throw('invalid_formula', $error.':'.$msg); 563 $functions = ['sin', 'cos', 'abs', 'ceil', 'pow', 'sqrt', 'pi', 'max', 'min', 'fmod', 'round']; 564 $precedence = ['+'=>1, '-'=>1, '**'=>2, '*'=>2, '/'=>2, '%'=>2, '>='=>3, '<='=>3, '!='=>3, '=='=>3, '>'=>3, '<'=>3,]; 565 $signs = implode('|', array_map(fn($v)=> preg_quote($v, '/'), [...array_keys($precedence), '(', ')', ','])); 566 $formula = preg_split('/\s*('.$signs.')\s*/', trim($formula), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); 567 $output = $stack = []; 568 $pt = null; 569 570 foreach($formula as $i => $t){ 571 $nt = $formula[$i+1] ?? null; 572 573 if(is_numeric($t)){ 574 $output[] = str_ends_with($t, '.') ? $throw('无效的数字「'.$t.'」') : (float)$t; 575 }elseif(str_starts_with($t, '$')){ 576 $output[] = isset($fields[substr($t, 1)]) ? $t : $throw('「'.$t.'」未定义'); 577 }elseif(in_array($t, $functions, true)){ 578 $stack[] = $t; 579 $output[] = '|'; 580 }elseif($t === '('){ 581 $stack[] = $t; 582 }elseif($t === ')' || $t === ','){ 583 if(!in_array('(', $stack, true) || ($t === ',' && ($pt === '(' || !$nt || $nt === ','))){ 584 $throw(($t === ')' ? '未匹配' : '无效').'的「'.$t.'」'); 585 } 586 587 while(array_last($stack) !== '('){ 588 $output[] = array_pop($stack); 589 } 590 591 if($t === ')'){ 592 array_pop($stack); 593 594 in_array(array_last($stack), $functions) && array_push($output, array_pop($stack)); 595 } 596 }elseif(isset($precedence[$t])){ 597 $r = ((!$pt || in_array($pt, ['(', ','], true)) ? 1 : 0)+((!$nt || in_array($nt, [')', ','], true) || isset($precedence[$nt])) ? 2 : 0); 598 599 if(in_array($t, ['+', '-'], true) && $r == 1){ 600 $output[] = 0; 601 }elseif($r){ 602 $throw('操作符「'.$t.'」缺少操作数'); 603 } 604 605 while($stack && ($v = array_last($stack)) !== '('){ 606 if(in_array($v, $functions) || $precedence[$t] <= $precedence[$v]){ 607 $output[] = array_pop($stack); 608 }else{ 609 break; 610 } 611 } 612 613 $stack[] = $t; 614 }else{ 615 $throw('无效的符号「'.$t.'」'); 616 } 617 618 $pt = $t; 619 } 620 621 return array_merge($output, array_reverse(in_array('(', $stack, true) ? $throw('未匹配的「(」') : $stack)); 622 } 623 624 function wpjam_format($value, $format, ...$args){ 625 if(is_array($value) && is_array($format)){ 626 return wpjam_reduce($format ?: [], fn($c, $v, $k)=> isset($c[$k]) ? wpjam_set($c, $k, wpjam_format($c[$k], ...$v)) : $c, $value); 627 } 628 629 if(is_numeric($value)){ 630 if($format == ','){ 631 return number_format(trim($value), (int)($args[0] ?? 2)); 632 }elseif($format == '%'){ 633 return round($value * 100, ($args[0] ?? 2) ?: 2).'%'; 634 }elseif(!$format && $args && is_numeric($args[0])){ 635 return round($value, $args[0]); 636 } 637 638 return $value / 1; 639 } 640 641 if(in_array($format, ['-,', '-%'])){ 642 if(is_string($value)){ 643 $value = str_replace(',', '', trim($value)); 644 645 if($format == '-%' && try_remove_suffix($value, '%')){ 646 $value = is_numeric($value) ? $value / 100 : $value; 647 } 648 } 649 650 return is_numeric($value) ? $value / 1 : ($args ? $args[0] : $value); 651 } 652 653 return $value; 468 654 } 469 655 … … 506 692 } 507 693 508 function wpjam_matches($ item, $args, $op='AND'){694 function wpjam_matches($arr, $args, $op='AND'){ 509 695 $op = strtoupper($op); 510 696 511 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; 512 } 513 514 function wpjam_parse_show_if($if){ 515 if(wp_is_numeric_array($if) && count($if) >= 2){ 516 $keys = count($if) == 2 ? ['key', 'value'] : ['key', 'compare', 'value']; 517 518 if(count($if) > 3){ 519 if(is_array($if[3])){ 520 $args = $if[3]; 521 522 trigger_error(var_export($args, true)); // del 2025-12-30 523 } 524 525 $if = array_slice($if, 0, 3); 526 } 527 528 return array_combine($keys, $if)+($args ?? []); 529 }elseif(is_array($if) && !empty($if['key'])){ 530 return $if; 697 if(!in_array($op, ['AND', 'ALL', 'OR', 'ANY', 'NOT'])){ 698 return false; 699 } 700 701 if(!is_callable($args)){ 702 return wpjam_matches($args, fn($v, $k)=> wpjam_match($arr, ...(wpjam_is_assoc_array($v) ? [$v+['key'=>$k]] : [$k, $v])), $op); 703 } 704 705 if(in_array($op, ['AND', 'ALL'], true)){ 706 return array_all($arr, $args); 707 }elseif(in_array($op, ['OR', 'ANY'], true)){ 708 return array_any($arr, $args); 709 }else{ 710 return !array_all($arr, $args); 531 711 } 532 712 } … … 544 724 } 545 725 546 function wpjam_is_array_accessible($arr){ 547 return is_array($arr) || $arr instanceof ArrayAccess; 548 } 549 550 function wpjam_array($arr=null, ...$args){ 551 if(is_object($arr)){ 552 if(method_exists($arr, 'to_array')){ 553 $data = $arr->to_array(); 554 }elseif($arr instanceof Traversable){ 555 $data = iterator_to_array($arr); 556 }elseif($arr instanceof JsonSerializable){ 557 $data = $arr->jsonSerialize(); 558 $data = is_array($data) ? $data : []; 559 }else{ 560 $data = []; 561 } 562 }else{ 563 $data = (array)$arr; 564 } 565 566 $cb = $args && is_callable($args[0]) ? array_shift($args) : null; 567 726 function wpjam_array($arr=null, $cb=null, $skip_null=false){ 568 727 if(!$cb){ 569 return $data; 570 } 571 572 if($args){ 573 if(in_array($args[0], ['AND', 'ALL'], true)){ 574 return array_all($arr, $cb); 575 }elseif(in_array($args[0], ['OR', 'ANY'], true)){ 576 return array_any($arr, $cb); 577 }elseif($args[0] === 'NOT'){ 578 return !array_all($arr, $cb); 579 } 580 581 $skip_null = $args[0]; 582 } 583 584 $skip_null ??= false; 585 586 foreach($data as $k => $v){ 728 if(is_object($arr)){ 729 if(method_exists($arr, 'to_array')){ 730 return $arr->to_array(); 731 }elseif($arr instanceof Traversable){ 732 return iterator_to_array($arr); 733 }elseif($arr instanceof JsonSerializable){ 734 return is_array($data = $arr->jsonSerialize()) ? $data : []; 735 }else{ 736 return []; 737 } 738 } 739 740 return (array)$arr; 741 } 742 743 foreach($arr as $k => $v){ 587 744 $r = $cb($k, $v); 588 745 589 if(is_array($r)){ 590 if(count($r) < 2 || ($skip_null && is_null($r[1]))){ 591 continue; 592 } 593 746 if(is_scalar($r)){ 747 $k = $r; 748 }elseif(is_array($r) && count($r) >= 2 && !($skip_null && is_null($r[1]))){ 594 749 [$k, $v] = $r; 595 }elseif(is_scalar($r)){596 $k = $r;597 750 }else{ 598 751 continue; … … 600 753 601 754 if(is_null($k)){ 602 $ new[]= $v;755 $data[] = $v; 603 756 }else{ 604 $ new[$k] = $v;605 } 606 } 607 608 return $ new?? [];757 $data[$k] = $v; 758 } 759 } 760 761 return $data ?? []; 609 762 } 610 763 … … 613 766 } 614 767 615 function wpjam_pick($arr, $keys){ 616 return wpjam_array($keys, fn($i, $k)=> [$k, wpjam_get($arr, $k)], true); 617 } 618 619 function wpjam_reduce($arr, $cb, $carry=null, $key='', ...$args){ 620 [$options, $depth] = is_array($key) ? [$key, $args[0] ?? 0] : [['key'=>$key, 'max_depth'=>$args[0] ?? 0], 0]; 621 622 $key = $options['key'] ?? ''; 623 $max = $options['max_depth'] ?? null; 768 function wpjam_pick($arr, $args){ 769 return wpjam_array($args, fn($i, $k)=> [$k, wpjam_get($arr, $k)], true); 770 } 771 772 function wpjam_entries($arr, $key=null, $value=null){ 773 $key ??= 0; 774 $value ??= (int)($key === 0); 775 776 return wpjam_array($arr, fn($k, $v)=> [null, [$key=>$k, $value=>$v]]); 777 } 778 779 function wpjam_column($arr, $key=null, $index=null){ 780 return wpjam_array($arr, fn($k, $v)=> [ 781 is_null($index) || $index === false ? null : ($index === true ? $k : $v[$index]), 782 is_array($key) ? wpjam_array($key, fn($k, $v)=> [wpjam_is_assoc_array($key) ? $k : $v, wpjam_get($arr, $v)], true) : wpjam_get($v, $key) 783 ]); 784 } 785 786 function wpjam_map($arr, $cb, $args=[]){ 787 $args = (is_bool($args) || $args === 'deep' ? ['deep'=>(bool)$args] : (is_string($args) ? ['mode'=>$args] : $args))+['deep'=>false]; 788 $mode = in_array($args['mode'] ?? '', ['vk', 'kv', 'k', 'v']) ? $args['mode'] : 'vk'; 789 790 return wpjam_array($arr, fn($k, $v)=> [$k, ($args['deep'] && is_array($v)) ? wpjam_map($v, $cb, $args) : $cb(...array_map(fn($c) => $c === 'k' ? $k : $v, str_split($mode)))]); 791 } 792 793 function wpjam_reduce($arr, $cb, $carry=null, ...$args){ 794 $depth = $args[1] ?? 0; 795 $args = $args && is_array($args[0]) ? $args[0] : ['key'=>$args[0] ?? '']; 796 $key = $args['key'] ?? ''; 797 $max = $args['max_depth'] ?? 0; 624 798 625 799 foreach(wpjam_array($arr) as $k => $v){ … … 628 802 if($key && (!$max || $max > $depth+1) && is_array($v)){ 629 803 $sub = $key === true ? $v : wpjam_get($v, $key); 630 $carry = is_array($sub) ? wpjam_reduce($sub, $cb, $carry, $ options, $depth+1) : $carry;804 $carry = is_array($sub) ? wpjam_reduce($sub, $cb, $carry, $args, $depth+1) : $carry; 631 805 } 632 806 } … … 666 840 667 841 return $parse($group, 0, 0); 668 }669 670 function wpjam_map($arr, $cb, $deep=false){671 return wpjam_array($arr, fn($k, $v)=>[$k, ($deep && is_array($v)) ? wpjam_map($v, $cb, true) : $cb($v, $k)]);672 }673 674 function wpjam_sum($items, $keys){675 return wpjam_fill($keys, fn($k)=> array_reduce($items, fn($sum, $item)=> $sum+(is_numeric($v = str_replace(',', '', ($item[$k] ?? 0))) ? $v : 0), 0));676 842 } 677 843 … … 927 1093 $parts = preg_split('/(['.preg_quote('[]', '/').'])/', $key, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); 928 1094 929 if(count($parts) % 3 != 1) {1095 if(count($parts) % 3 != 1){ 930 1096 return []; 931 1097 } … … 1094 1260 } 1095 1261 1096 function_alias('wpjam_is_array_accessible', 'array_accessible');1097 function_alias('wpjam_every', 'array_all');1098 function_alias('wpjam_some', 'array_any');1099 function_alias('wpjam_array', 'array_wrap');1100 function_alias('wpjam_get', 'array_get');1101 function_alias('wpjam_set', 'array_set');1102 function_alias('wpjam_merge', 'merge_deep');1103 1104 1262 function wpjam_move($arr, $id, $data){ 1105 1263 $arr = array_values($arr); … … 1258 1416 } 1259 1417 1260 function wpjam_format($value, $format, $precision=null){1261 if(is_numeric($value)){1262 if($format == '%'){1263 return round($value * 100, $precision ?: 2).'%';1264 }elseif($format == ','){1265 return number_format(trim($value), (int)($precision ?? 2));1266 }elseif(is_numeric($precision)){1267 return round($value, $precision);1268 }1269 }1270 1271 return $value;1272 }1273 1274 1418 // 检查非法字符 1275 1419 function wpjam_blacklist_check($text, $name='内容'){ … … 1294 1438 1295 1439 return $str; 1296 }1297 1298 // Shortcode1299 function wpjam_do_shortcode($content, $tags, $ignore_html=false){1300 if($tags){1301 if(wpjam_is_assoc_array($tags)){1302 array_walk($tags, fn($cb, $tag)=> add_shortcode($tag, $cb));1303 1304 $tags = array_keys($tags);1305 }1306 1307 if(array_any($tags, fn($tag)=> str_contains($content, '['.$tag))){1308 $content = do_shortcodes_in_html_tags($content, $ignore_html, $tags);1309 $content = preg_replace_callback('/'.get_shortcode_regex($tags).'/', 'do_shortcode_tag', $content);1310 $content = unescape_invalid_shortcodes($content);1311 }1312 }1313 1314 return $content;1315 }1316 1317 function wpjam_parse_shortcode_attr($str, $tag){1318 return preg_match('/'.get_shortcode_regex((array)$tag).'/', $str, $m) ? shortcode_parse_atts($m[3]) : [];1319 1440 } 1320 1441 -
wpjam-basic/trunk/readme.txt
r3437425 r3454739 54 54 == Changelog == 55 55 56 = 6.9.2 = 57 * 开启多语言和新增函数 wpjam_translate 58 * 新增函数 wpjam_column 支持获取多列 59 * 新增函数 wpjam_entries 可以将关联数组转换成索引数组 60 * 增强函数 wpjam_chart 支持图表各种操作 61 * 新增函数 wpjam_formula 解析数学表达式 62 * 新增函数 wpjam_calc 计算数学表达式 63 56 64 = 6.9 = 57 65 * 新增函数 get_term_level … … 64 72 * 新增 PHP 8.5 array_first 和 array_last 兼容 65 73 * wpjam_try 和 wpjam_catch 函数新增 :: 和 -> 模式的支持 66 * wpjam_value _callback函数新增 model 的支持74 * wpjam_value 函数新增 model 的支持 67 75 * list_table_action 增加 update_setting 功能 68 76 * WPJAM_DB 和 list_table 支持 search_column -
wpjam-basic/trunk/static/form.js
r3423058 r3454739 173 173 } 174 174 }else{ 175 let label = this.data('label') || (this.hasClass('plupload-input') ? this.val().split('/').pop() : this.val());175 let label = this.data('label') || (this.hasClass('plupload-input') ? this.val().split('/').pop() : ''); 176 176 177 177 label && $('<span class="query-label">'+label+'</span>').prepend($('<span class="dashicons"></span>').on('click', ()=> this.trigger('query_label'))).addClass(this.closest('.tag-input').length ? '' : this.data('class')).insertBefore(this); -
wpjam-basic/trunk/static/script.js
r3440469 r3454739 395 395 $('a.page-title-action').remove(); 396 396 397 $('.wp-heading-inline').last().after(this.page_title_action || '');397 $('.wp-heading-inline').last().after(this.page_title_action); 398 398 } 399 399 … … 807 807 808 808 update = _.mapObject(update, (v, k)=> data[k] ? v : false); 809 810 data.search_box && $('p.search-box').empty().append($('<div>').html(data.search_box).find('.search-box').html());811 809 }else{ 812 810 $form.attr('novalidate', 'novalidate').on('submit', _.debounce(function(){ … … 957 955 }, 300, true)); 958 956 } 957 } 958 959 if(list_table.search){ 960 if(list_table.search.box){ 961 $('#list_table_form').find('p.search-box').remove().end().prepend(list_table.search.box); 962 }else{ 963 $('p.search-box').find('input[type="search"]').val(list_table.search.term); 964 } 965 966 list_table.search.columns && $('p.search-box').find('#search_columns').remove().end().prepend(list_table.search.columns); 959 967 } 960 968 -
wpjam-basic/trunk/static/style.css
r3427357 r3454739 1 1 .abscenter{left:50%; top:50%; transform:translate(-50%, -50%);} 2 2 .ui-autocomplete{z-index:1000000 !important;} /*要超过 TB z-index 才行,不然弹窗不行*/ 3 4 .wp-menu-image[class*=" ri-"]:before{display:inline-block; line-height:1; font-size:20px;} 3 5 4 6 .green{font-size:larger; font-weight:500; color:green;} … … 282 284 table.wp-list-table th.check-column .spinner{margin:4px 0 0 0;} 283 285 table.wp-list-table th.check-column .spinner + input{display:none;} 286 table.wp-list-table th.column-no{width:42px;} 284 287 285 288 table.wp-list-table .pending th, -
wpjam-basic/trunk/wpjam-basic.php
r3440469 r3454739 4 4 Plugin URI: https://blog.wpjam.com/project/wpjam-basic/ 5 5 Description: WPJAM 常用的函数和接口,屏蔽所有 WordPress 不常用的功能。 6 Version: 6.9. 1.26 Version: 6.9.2 7 7 Requires at least: 6.7 8 8 Tested up to: 6.9
Note: See TracChangeset
for help on using the changeset viewer.