| 1 |
<?php |
| 2 |
class WPJAM_Core extends WPJAM_Register{ |
| 3 |
public function __get($key){ |
| 4 |
if($key == 'title'){ |
| 5 |
return ($labels = $this->builtin('labels')) ? $labels->singular_name : $this->label; |
| 6 |
} |
| 7 |
|
| 8 |
$value = $this->builtin($key) ?? parent::__get($key); |
| 9 |
|
| 10 |
return $key == 'plural' ? ($value ?: ($this->rest_base ?: $this->name.'s')) : $value; |
| 11 |
} |
| 12 |
|
| 13 |
public function __set($key, $value){ |
| 14 |
$this->builtin($key, $value); |
| 15 |
|
| 16 |
return parent::__set($key, $value); |
| 17 |
} |
| 18 |
|
| 19 |
public function __call($method, $args){ |
| 20 |
return $this->call_dynamic_method($method, ...$args); |
| 21 |
} |
| 22 |
|
| 23 |
public function builtin($key='', ...$args){ |
| 24 |
$type = wpjam_get_builtin_type(get_class($this)); |
| 25 |
|
| 26 |
if(!$key){ |
| 27 |
return $type; |
| 28 |
} |
| 29 |
|
| 30 |
if($key != 'name' |
| 31 |
&& property_exists('WP_'.$type, $key) |
| 32 |
&& ($object = wpjam_call('get_'.$type.($type == 'post_type' ? '_object' : ''), $this->name)) |
| 33 |
){ |
| 34 |
return $args ? ($object->$key = $args[0]) : $object->$key; |
| 35 |
} |
| 36 |
} |
| 37 |
|
| 38 |
public function permastruct(){ |
| 39 |
if(!($value = trim($this->get_arg('permastruct') ?: '', '/'))){ |
| 40 |
return; |
| 41 |
} |
| 42 |
|
| 43 |
$name = $this->name; |
| 44 |
$type = $this->builtin(); |
| 45 |
$hook = 'registered_'.$type.'_'.$name; |
| 46 |
$qv = $type == 'post_type' ? 'p' : 'term_id'; |
| 47 |
$iv = $qv == 'p' ? '%post_id%' : '%term_id%'; |
| 48 |
$value = str_replace( |
| 49 |
($qv == 'p' ? ['%'.$name.'_id%', '%postname%'] : ['%'.$this->query_key.'%', '%termname%']), |
| 50 |
[$iv, '%'.$name.'%'], |
| 51 |
$value |
| 52 |
); |
| 53 |
|
| 54 |
$this->rewrite = $this->rewrite ?: true; |
| 55 |
|
| 56 |
if(str_contains($value, $iv)){ |
| 57 |
if($qv == 'p'){ |
| 58 |
if($this->hierarchical){ |
| 59 |
return; |
| 60 |
} |
| 61 |
}else{ |
| 62 |
$this->remove_support('slug'); |
| 63 |
} |
| 64 |
|
| 65 |
$this->query_var ??= false; |
| 66 |
|
| 67 |
add_action($hook, fn()=> remove_rewrite_tag('%'.$name.'%')); |
| 68 |
|
| 69 |
add_filter($name.'_rewrite_rules', fn($rules)=> wpjam_map($rules, fn($v)=> str_replace('?'.$qv.'=', '?'.$type.'='.$name.'&'.$qv.'=', $v))); |
| 70 |
}elseif($value == '%'.$name.'%'){ |
| 71 |
if($qv != 'p'){ |
| 72 |
$this->no_base = true; |
| 73 |
|
| 74 |
return; |
| 75 |
} |
| 76 |
} |
| 77 |
|
| 78 |
add_action($hook, fn()=> add_permastruct($name, $value, $GLOBALS['wp_rewrite']->extra_permastructs[$name])); |
| 79 |
} |
| 80 |
|
| 81 |
public function labels($labels){ |
| 82 |
$l = (array)$labels; |
| 83 |
$n = $l['name']; |
| 84 |
$h = $this->hierarchical; |
| 85 |
|
| 86 |
if($this->builtin() == 'post_type'){ |
| 87 |
$m = ['all_items'=>'所有'.$n, 'archives'=>$n.'归档']; |
| 88 |
$s = ['撰写新', '写文章', ...($h ? ['页面', 'page', 'Page'] : ['文章', 'post', 'Post'])]; |
| 89 |
$r = ['添加', '添加'.$n, $n, $n, ucfirst($n)]; |
| 90 |
}else{ |
| 91 |
$m = []; |
| 92 |
$s = $h ? ['分类', 'categories', 'Categories', 'Category'] : ['标签', 'Tag', 'tag']; |
| 93 |
$r = $h ? [$n, $n.'s', ucfirst($n).'s', ucfirst($n)] : [$n, ucfirst($n), $n]; |
| 94 |
} |
| 95 |
|
| 96 |
return array_merge(wpjam_map($l, fn($v, $k)=> $m[$k] ?? (($v && $v != $n) ? str_replace($s, $r, $v) : $v)), (array)$this->labels); |
| 97 |
} |
| 98 |
|
| 99 |
public function to_array(){ |
| 100 |
$this->filter_args(); |
| 101 |
$this->permastruct(); |
| 102 |
|
| 103 |
if($this->_jam){ |
| 104 |
$type = $this->builtin(); |
| 105 |
|
| 106 |
if(($v = $this->rewrite) !== false){ |
| 107 |
$this->rewrite = (is_array($v) ? $v : [])+['with_front'=>false]; |
| 108 |
} |
| 109 |
|
| 110 |
if(is_admin() && $this->show_ui){ |
| 111 |
add_filter($type.'_labels_'.$this->name, [$this, 'labels']); |
| 112 |
} |
| 113 |
|
| 114 |
wpjam_map($this->options ?:[], fn($v, $k)=> wpjam_register_meta_option($type == 'post_type' ? 'post' : 'term', $k, $v+[$type=>$this->name])); |
| 115 |
} |
| 116 |
|
| 117 |
return $this->args; |
| 118 |
} |
| 119 |
|
| 120 |
public function add_field($key, ...$args){ |
| 121 |
return $this->process_arg('_fields', fn($v)=> array_merge($v ?: [], is_callable($key) ? [$key] : (is_array($key) ? $key : [$key => $args[0]]))); |
| 122 |
} |
| 123 |
|
| 124 |
public function remove_field($key){ |
| 125 |
return $this->delete_arg('_fields['.$key.']'); |
| 126 |
} |
| 127 |
|
| 128 |
public function get_fields($id=0, $action_key=''){ |
| 129 |
return wpjam_reduce($this->get_arg('_fields[]'), fn($c, $v, $k)=> array_merge($c, is_callable($v) |
| 130 |
? wpjam_pack(wpjam_try($v, $id, $action_key), is_numeric($k) ? null : $k) |
| 131 |
: (wpjam_is_assoc_array($v) ? [$k => $v] : []) |
| 132 |
), []); |
| 133 |
} |
| 134 |
|
| 135 |
public static function filter_builtin_args($args, $name, $object_type=null){ |
| 136 |
if(!static::get($name) && !empty($args['public']) && (did_action('init') || empty($args['_builtin']))){ |
| 137 |
return (static::register($name, ['_jam'=>false]+array_filter(compact('object_type'))+$args))->to_array(); |
| 138 |
} |
| 139 |
|
| 140 |
return $args; |
| 141 |
} |
| 142 |
} |
| 143 |
/** |
| 144 |
* @config menu_page, admin_load, register_json, init |
| 145 |
**/ |
| 146 |
#[config('menu_page', 'admin_load', 'register_json', 'init')] |
| 147 |
class WPJAM_Post_Type extends WPJAM_Core{ |
| 148 |
public function to_array(){ |
| 149 |
parent::to_array(); |
| 150 |
|
| 151 |
if($this->_jam){ |
| 152 |
$this->public ??= true; |
| 153 |
$this->supports ??= ['title']; |
| 154 |
|
| 155 |
if($this->hierarchical){ |
| 156 |
$this->update_arg('supports[]', 'page-attributes'); |
| 157 |
} |
| 158 |
|
| 159 |
if(!is_array($this->taxonomies)){ |
| 160 |
$this->delete_arg('taxonomies'); |
| 161 |
} |
| 162 |
|
| 163 |
if($v = $this->menu_icon){ |
| 164 |
$this->menu_icon = wpjam_prefix($v, 'dashicons-'); |
| 165 |
} |
| 166 |
} |
| 167 |
|
| 168 |
return $this->args += ['model'=>'WPJAM_Post']; |
| 169 |
} |
| 170 |
|
| 171 |
public function get_menu_slug(){ |
| 172 |
return $this->menu_slug ?? (($v = $this->get_arg('menu_page')) && is_array($v) ? (wp_is_numeric_array($v) ? array_first($v) : $v)['menu_slug'] : null); |
| 173 |
} |
| 174 |
|
| 175 |
public function get_fields($id=0, $action_key=''){ |
| 176 |
$fields = ($this->supports('images') ? [ |
| 177 |
'images' => ['title'=>'图集', 'type'=>'mu-img', 'name'=>'meta_input[images]', 'item_type'=>'url', 'size'=>($this->images_sizes ?: [''])[0], 'max_items'=>$this->images_max_items] |
| 178 |
] : [])+($this->supports('video') ? [ |
| 179 |
'video' => ['title'=>'视频', 'type'=>'url', 'name'=>'meta_input[video]'] |
| 180 |
] : [])+parent::get_fields($id, $action_key); |
| 181 |
|
| 182 |
if(in_array($action_key, ['add', 'set'])){ |
| 183 |
$fields = [ |
| 184 |
'post_title' => ['type'=>'text', 'title'=>'标题', 'required'] |
| 185 |
]+($action_key == 'add' ? [ |
| 186 |
'post_type' => ['type'=>'hidden', 'value'=>$this->name], |
| 187 |
'post_status' => ['type'=>'hidden', 'value'=>'draft'] |
| 188 |
] : [])+($this->supports('excerpt') ? [ |
| 189 |
'post_excerpt' => ['title'=>'摘要', 'type'=>'textarea'] |
| 190 |
] : [])+($this->supports('thumbnail') ? [ |
| 191 |
'_thumbnail_id' => ['title'=>'头图', 'type'=>'img', 'size'=>'600x0', 'name'=>'meta_input[_thumbnail_id]'] |
| 192 |
] : [])+wpjam_map($fields, fn($v, $k)=> (empty($v['name']) && !property_exists('WP_Post', $k) ? ['name'=>'meta_input['.$k.']'] : [])+$v); |
| 193 |
} |
| 194 |
|
| 195 |
return $fields; |
| 196 |
} |
| 197 |
|
| 198 |
public function supports($feature){ |
| 199 |
return array_any(wp_parse_list($feature), fn($f)=> post_type_supports($this->name, $f)); |
| 200 |
} |
| 201 |
|
| 202 |
public function get_taxonomies(...$args){ |
| 203 |
$filter = $args && is_array($args[0]) ? array_shift($args) : []; |
| 204 |
$output = $args[0] ?? 'objects'; |
| 205 |
$data = get_object_taxonomies($this->name); |
| 206 |
|
| 207 |
if($filter || $output == 'objects'){ |
| 208 |
$data = wpjam_fill($data, 'wpjam_get_taxonomy'); |
| 209 |
$data = $filter ? wpjam_filter($data, $filter) : $data; |
| 210 |
$data = $output == 'objects' ? $data : array_keys($data); |
| 211 |
} |
| 212 |
|
| 213 |
return $data; |
| 214 |
} |
| 215 |
|
| 216 |
public function parse_images($images, $args=[]){ |
| 217 |
$ss = $this->images_sizes; |
| 218 |
$sizes = []; |
| 219 |
|
| 220 |
foreach(['large', 'thumbnail'] as $k){ |
| 221 |
if(($v = $args[$k.'_size'] ?? '') !== false){ |
| 222 |
if(!$v && $ss){ |
| 223 |
$v = $ss[$k == 'large' ? 0 : 1]; |
| 224 |
|
| 225 |
if($k == 'thumbnail' && count($images) == 1){ |
| 226 |
$i = array_first($images); |
| 227 |
$q = wpjam_image($i, 'query') ?: wpjam_tap(wpjam_image($i, 'size') ?: ['width'=>0, 'height'=>0], fn($q)=> update_post_meta($args['post_id'], 'images', [add_query_arg($q, $i)])); |
| 228 |
|
| 229 |
$v = ($o = $q['orientation'] ?? '') ? ($ss[$o == 'landscape' ? 2 : 3] ?? $v) : $v; |
| 230 |
} |
| 231 |
}else{ |
| 232 |
$v = $v ?: $this->{$k.'_size'}; |
| 233 |
} |
| 234 |
|
| 235 |
$sizes[$k] = $v ?: $k; |
| 236 |
} |
| 237 |
} |
| 238 |
|
| 239 |
$sizes += (!$sizes || ($args['full_size'] ?? true)) ? ['full'=>'full'] : []; |
| 240 |
|
| 241 |
foreach($images as $image){ |
| 242 |
$parsed = array_map(fn($s)=> wpjam_get_thumbnail($image, $s), $sizes); |
| 243 |
$parsed = array_merge($parsed, ($query = wpjam_image($image, 'query')) ? wpjam_pick($query, ['orientation', 'width', 'height'])+['width'=>0, 'height'=>0] : []); |
| 244 |
|
| 245 |
if(isset($sizes['thumbnail'])){ |
| 246 |
$size = wpjam_parse_size($sizes['thumbnail']); |
| 247 |
$parsed = array_reduce(['width', 'height'], fn($c, $k)=> $c+['thumbnail_'.$k=>$size[$k] ?? 0], $parsed); |
| 248 |
} |
| 249 |
|
| 250 |
$results[] = count($sizes) == 1 ? array_first($parsed) : $parsed; |
| 251 |
} |
| 252 |
|
| 253 |
return $results; |
| 254 |
} |
| 255 |
|
| 256 |
public function reset_invalid_parent($value=0){ |
| 257 |
$wpdb = $GLOBALS['wpdb']; |
| 258 |
$ids = $wpdb->get_col($wpdb->prepare("SELECT p1.ID FROM {$wpdb->posts} p1 LEFT JOIN {$wpdb->posts} p2 ON p1.post_parent = p2.ID WHERE p1.post_type=%s AND p1.post_parent > 0 AND p2.ID is null", $this->name)) ?: []; |
| 259 |
|
| 260 |
return count(array_map(fn($id)=> wp_update_post(['ID'=>$id, 'post_parent'=>$value]), $ids)); |
| 261 |
} |
| 262 |
|
| 263 |
public function registered(){ |
| 264 |
$this->_jam && wpjam_init(fn()=> register_post_type($this->name, $this->to_array())); |
| 265 |
} |
| 266 |
|
| 267 |
public static function filter_clauses($clauses, $query){ |
| 268 |
$wpdb = $GLOBALS['wpdb']; |
| 269 |
$orderby = $query->get('orderby'); |
| 270 |
$order = strtoupper($query->get('order')) == 'ASC' ? 'ASC' : 'DESC';; |
| 271 |
|
| 272 |
if($orderby == 'related'){ |
| 273 |
if($tt_ids = array_filter(wp_parse_id_list($query->get('term_taxonomy_ids')))){ |
| 274 |
$clauses['join'] .= "INNER JOIN {$wpdb->term_relationships} AS tr ON {$wpdb->posts}.ID = tr.object_id"; |
| 275 |
$clauses['where'] .= " AND tr.term_taxonomy_id IN (".implode(",", $tt_ids).")"; |
| 276 |
$clauses['groupby'] .= " tr.object_id"; |
| 277 |
$clauses['orderby'] = " count(tr.object_id) DESC, {$wpdb->posts}.ID DESC"; |
| 278 |
} |
| 279 |
}elseif($orderby == 'comment_date'){ |
| 280 |
$ct = $query->get('comment_type') ?: 'comment'; |
| 281 |
$str = $ct == 'comment' ? "'comment', ''" : "'".esc_sql($ct)."'"; |
| 282 |
$where = "ct.comment_type IN ({$str}) AND ct.comment_parent=0 AND ct.comment_approved NOT IN ('spam', 'trash', 'post-trashed')"; |
| 283 |
|
| 284 |
$clauses['join'] = "INNER JOIN {$wpdb->comments} AS ct ON {$wpdb->posts}.ID = ct.comment_post_ID AND {$where}"; |
| 285 |
$clauses['groupby'] = "ct.comment_post_ID"; |
| 286 |
$clauses['orderby'] = "MAX(ct.comment_ID) {$order}"; |
| 287 |
}elseif(in_array($orderby, ['views', 'comment_type'])){ |
| 288 |
$clauses['join'] .= $wpdb->prepare("LEFT JOIN {$wpdb->postmeta} jam_pm ON {$wpdb->posts}.ID = jam_pm.post_id AND jam_pm.meta_key = %s ", sanitize_key($orderby == 'comment_type' ? $query->get('comment_count') : 'views')); |
| 289 |
$clauses['orderby'] = "(COALESCE(jam_pm.meta_value, 0)+0) {$order}, " . $clauses['orderby']; |
| 290 |
$clauses['groupby'] = "{$wpdb->posts}.ID"; |
| 291 |
}elseif(in_array($orderby, ['', 'date', 'post_date'])){ |
| 292 |
$clauses['orderby'] .= ", {$wpdb->posts}.ID {$order}"; |
| 293 |
} |
| 294 |
|
| 295 |
return $clauses; |
| 296 |
} |
| 297 |
|
| 298 |
public static function filter_results($posts, $query){ |
| 299 |
$q = &$query->query_vars; |
| 300 |
|
| 301 |
if(($sticky_posts = array_diff(wp_parse_id_list(wpjam_pull($q, 'sticky_posts') ?: []), $q['post__not_in'])) |
| 302 |
&& ($stickies = get_posts([ |
| 303 |
'orderby' => 'post__in', |
| 304 |
'post__in' => $sticky_posts, |
| 305 |
'post_type' => $q['post_type'] ?: 'post', |
| 306 |
'post_status' => 'publish', |
| 307 |
'posts_per_page' => count($sticky_posts), |
| 308 |
]+wpjam_pick($q, ['suppress_filters', 'cache_results', 'update_post_meta_cache', 'update_post_term_cache', 'lazy_load_term_meta']))) |
| 309 |
){ |
| 310 |
$q['sticky_posts'] = array_column($stickies, 'ID'); |
| 311 |
|
| 312 |
return array_merge($stickies, array_filter($posts, fn($post)=> !in_array($post->ID, $q['sticky_posts'], true))); |
| 313 |
} |
| 314 |
|
| 315 |
return $posts; |
| 316 |
} |
| 317 |
|
| 318 |
public static function add_hooks(){ |
| 319 |
$hook = 'content_save_pre'; |
| 320 |
$cb = 'wp_filter_post_kses'; |
| 321 |
|
| 322 |
wpjam_hook($hook, 'tap', fn($c)=> is_serialized($c) && remove_filter($hook, $cb) && wpjam_once($hook, 'tap', fn()=> add_filter($hook, $cb), 11), 1); |
| 323 |
|
| 324 |
add_filter('post_type_link', fn($link, $post)=> str_replace('%post_id%', $post->ID, $link), 1, 2); |
| 325 |
|
| 326 |
add_filter('posts_clauses', [static::class, 'filter_clauses'], 1, 2); |
| 327 |
add_filter('posts_results', [static::class, 'filter_results'], 1, 2); |
| 328 |
} |
| 329 |
} |
| 330 |
|
| 331 |
/** |
| 332 |
* @config menu_page, admin_load, register_json |
| 333 |
**/ |
| 334 |
#[config('menu_page', 'admin_load', 'register_json')] |
| 335 |
class WPJAM_Taxonomy extends WPJAM_Core{ |
| 336 |
public function to_array(){ |
| 337 |
$this->filter_args(); |
| 338 |
|
| 339 |
$this->query_key = ['category'=>'cat', 'post_tag'=>'tag_id'][$this->name] ?? $this->name.'_id'; |
| 340 |
$this->column_name = ['category'=>'categories', 'post_tag'=>'tags'][$this->name] ?? 'taxonomy-'.$this->name; |
| 341 |
$this->supports = wpjam_array($this->supports ?? ['slug', 'description', ...($this->levels == 1 ? [] : ['parent'])], fn($k, $v)=> is_numeric($k) ? [$v, true] : [$k, $v]); |
| 342 |
|
| 343 |
parent::to_array(); |
| 344 |
|
| 345 |
return $this->args += ($this->_jam ? ['show_in_nav_menus'=>false, 'show_in_rest'=>true, 'show_admin_column'=>true, 'hierarchical'=>true] : [])+['model'=>'WPJAM_Term', 'show_in_posts_rest'=>$this->show_in_rest]; |
| 346 |
} |
| 347 |
|
| 348 |
public function add_support($feature, $value=true){ |
| 349 |
return $this->update_arg('supports['.$feature.']', $value); |
| 350 |
} |
| 351 |
|
| 352 |
public function remove_support($feature){ |
| 353 |
return $this->delete_arg('supports['.$feature.']'); |
| 354 |
} |
| 355 |
|
| 356 |
public function supports($feature, ...$args){ |
| 357 |
return is_array($feature) ? array_any($feature, [$this, $supports]) : (bool)$this->get_arg('supports['.$feature.']'); |
| 358 |
} |
| 359 |
|
| 360 |
public function selectable(){ |
| 361 |
return $this->selectable ?? (wp_count_terms(['taxonomy'=>$this->name, 'hide_empty'=>false]+($this->levels > 1 ? ['parent'=>0] : [])) <= 30); |
| 362 |
} |
| 363 |
|
| 364 |
public function get_fields($id=0, $action_key=''){ |
| 365 |
$fields = ($this->supports('thumbnail') ? [ |
| 366 |
'thumbnail' => ['title'=>'缩略图', 'size'=>$this->thumbnail_size]+array_combine(['type', 'item_type'], $this->thumbnail_type == 'image' ? ['image', 'image'] : ['img', 'url']) |
| 367 |
] : [])+($this->supports('banner') ? [ |
| 368 |
'banner' => ['title'=>'大图', 'type'=>'img', 'item_type'=>'url', 'size'=>$this->banner_size, 'show_if'=>['parent', -1]] |
| 369 |
] : [])+parent::get_fields($id, $action_key); |
| 370 |
|
| 371 |
if($action_key == 'set'){ |
| 372 |
$fields = [ |
| 373 |
'name' => ['title'=>'名称', 'type'=>'text', 'class'=>'', 'required'] |
| 374 |
]+($this->supports('slug') ? [ |
| 375 |
'slug' => ['title'=>'别名', 'type'=>'text', 'class'=>'', 'required'] |
| 376 |
] : [])+($this->hierarchical && $this->levels !== 1 && $this->supports('parent') ? [ |
| 377 |
'parent' => ['title'=>'父级', 'options'=>['-1'=>'无']+$this->get_options(apply_filters('taxonomy_parent_dropdown_args', ['exclude_tree'=>$id], $this->name, 'edit'))] |
| 378 |
] : [])+($this->supports('slug') ? [ |
| 379 |
'description' => ['title'=>'描述', 'type'=>'textarea'] |
| 380 |
] : [])+$fields; |
| 381 |
} |
| 382 |
|
| 383 |
return $fields; |
| 384 |
} |
| 385 |
|
| 386 |
public function get_options($args=[]){ |
| 387 |
return array_column(wpjam_get_terms($args+['taxonomy'=>$this->name, 'hide_empty'=>0, 'format'=>'flat', 'parse'=>false]), 'name', 'term_id'); |
| 388 |
} |
| 389 |
|
| 390 |
public function get_mapping($post_id){ |
| 391 |
$post = wpjam_try('wpjam_validate_post', $post_id, $this->mapping_post_type); |
| 392 |
$data = ['name'=>$post->post_title, 'slug'=>$post->post_type.'-'.$post_id, 'taxonomy'=>$this->name]; |
| 393 |
|
| 394 |
if($term_id = get_post_meta($post_id, $this->query_key, true)){ |
| 395 |
if($term = get_term($term_id, $this->name)){ |
| 396 |
if($term->name != $data['name'] || $term->slug != $data['slug']){ |
| 397 |
WPJAM_Term::update($term_id, $data); |
| 398 |
} |
| 399 |
|
| 400 |
return $term_id; |
| 401 |
} |
| 402 |
} |
| 403 |
|
| 404 |
return wpjam_tap(WPJAM_Term::insert($data), fn($term_id)=> update_post_meta($post_id, $this->query_key, $term_id)); |
| 405 |
} |
| 406 |
|
| 407 |
public function dropdown(){ |
| 408 |
$args = ['taxonomy'=>$this->name, 'name'=>$this->query_key]; |
| 409 |
$value = $this->get_param($this->query_key); |
| 410 |
|
| 411 |
if(is_null($value)){ |
| 412 |
$slug = ($var = $this->query_var) ? $this->get_param($var) : null; |
| 413 |
$slug ??= $this->get_param('taxonomy') == $this->name ? $this->get_param('term') : ''; |
| 414 |
$term = $slug ? get_term_by('slug', $slug, $this->name) : ''; |
| 415 |
$value = $term ? $term->term_id : ''; |
| 416 |
} |
| 417 |
|
| 418 |
if($this->hierarchical){ |
| 419 |
wp_dropdown_categories($args+[ |
| 420 |
'show_option_all' => $this->labels->all_items, |
| 421 |
'show_option_none' => '没有设置', |
| 422 |
'option_none_value' => 'none', |
| 423 |
'selected' => $value, |
| 424 |
'hierarchical' => true |
| 425 |
]); |
| 426 |
}else{ |
| 427 |
echo wpjam_field($args+[ |
| 428 |
'value' => $value, |
| 429 |
'type' => 'text', |
| 430 |
'data_type' => 'taxonomy', |
| 431 |
'filterable' => true, |
| 432 |
'placeholder' => '请输� |
| 433 |
�'.$this->title, |
| 434 |
'title' => '', |
| 435 |
'class' => '' |
| 436 |
]); |
| 437 |
} |
| 438 |
} |
| 439 |
|
| 440 |
public function registered(){ |
| 441 |
$this->_jam && wpjam_init(fn()=> register_taxonomy($this->name, $this->object_type, $this->to_array())); |
| 442 |
} |
| 443 |
|
| 444 |
public static function filter_request($vars){ |
| 445 |
if(($struct = get_option('permalink_structure')) |
| 446 |
&& ($request = $GLOBALS['wp']->request) |
| 447 |
&& ($no_base = static::get_by('no_base', true)) |
| 448 |
&& !isset($vars['module']) |
| 449 |
&& !is_admin() |
| 450 |
){ |
| 451 |
if(preg_match("#(.?.+?)/page/?([0-9]{1,})/?$#", $request, $matches)){ |
| 452 |
[, $request, $paged] = $matches; |
| 453 |
} |
| 454 |
|
| 455 |
if($GLOBALS['wp_rewrite']->use_verbose_page_rules){ |
| 456 |
if(($vars['error'] ?? '') == '404'){ |
| 457 |
$key = 'error'; |
| 458 |
}elseif(str_contains($struct, '/%postname%') && !empty($vars['name'])){ |
| 459 |
$key = 'name'; |
| 460 |
}elseif(!str_contains($request, '/')){ |
| 461 |
$type = array_find(['author', 'category'], fn($k)=> str_starts_with($struct, '/%'.$k.'%')); |
| 462 |
$key = $type && !empty($vars[$type.'_name']) ? [$type.'_name', 'name'] : ''; |
| 463 |
} |
| 464 |
}else{ |
| 465 |
$key = !empty($vars['pagename']) && !isset($_GET['page_id']) && !isset($_GET['pagename']) ? 'pagename' : ''; |
| 466 |
} |
| 467 |
|
| 468 |
foreach(!empty($key) ? array_keys($no_base) : [] as $tax){ |
| 469 |
$name = is_taxonomy_hierarchical($tax) ? wp_basename($request) : $request; |
| 470 |
|
| 471 |
if(array_find(wpjam_get_all_terms($tax), fn($term)=> $term->slug == $name)){ |
| 472 |
return ($tax == 'category' ? ['category_name'=>$name] : ['taxonomy'=>$tax, 'term'=>$name])+array_filter(['paged'=>$paged ?? 0])+wpjam_except($vars, $key); |
| 473 |
} |
| 474 |
} |
| 475 |
} |
| 476 |
|
| 477 |
return $vars; |
| 478 |
} |
| 479 |
|
| 480 |
public static function add_hooks(){ |
| 481 |
wpjam_init(fn()=> add_rewrite_tag('%term_id%', '([0-9]+)', 'term_id=')); |
| 482 |
|
| 483 |
wpjam_hook('query_vars', '+', ['term_id'], 11); |
| 484 |
|
| 485 |
add_filter('pre_term_link', fn($link, $term)=> wpjam_get_taxonomy_setting($term->taxonomy, 'no_base') ? '%'.$term->taxonomy.'%' : str_replace('%term_id%', $term->term_id, $link), 1, 2); |
| 486 |
|
| 487 |
add_filter('request', [self::class, 'filter_request']); |
| 488 |
} |
| 489 |
} |
| 490 |
|
| 491 |
class WPJAM_Post extends WPJAM_Instance{ |
| 492 |
public function __get($key){ |
| 493 |
if(in_array($key, ['id', 'post_id'])){ |
| 494 |
return $this->id; |
| 495 |
}elseif($key == 'views'){ |
| 496 |
return (int)$this->meta_get('views'); |
| 497 |
}elseif($key == 'viewable'){ |
| 498 |
return is_post_publicly_viewable($this->id); |
| 499 |
}elseif($key == 'type_object'){ |
| 500 |
return wpjam_get_post_type_object($this->post_type); |
| 501 |
}elseif($key == 'thumbnail'){ |
| 502 |
return $this->supports('thumbnail') ? get_the_post_thumbnail_url($this->id, 'full') : ''; |
| 503 |
}elseif($key == 'images'){ |
| 504 |
return $this->supports('images') ? array_values($this->meta_get('images') ?: []) : []; |
| 505 |
} |
| 506 |
|
| 507 |
return $this->builtin($key); |
| 508 |
} |
| 509 |
|
| 510 |
public function __call($method, $args){ |
| 511 |
if($method == 'get_type_setting'){ |
| 512 |
return $this->type_object->{$args[0]}; |
| 513 |
}elseif(in_array($method, ['get_taxonomies', 'supports'])){ |
| 514 |
return $this->type_object->$method(...$args); |
| 515 |
}elseif(in_array($method, ['get_content', 'get_excerpt', 'get_first_image_url', 'get_thumbnail_url', 'get_images'])){ |
| 516 |
return ('wpjam_get_post_'.substr($method, 4))($this->post, ...$args); |
| 517 |
}elseif($cb = ['get_terms'=>'get_the_terms', 'set_terms'=>'wp_set_post_terms', 'in_term'=>'is_object_in_term'][$method] ?? ''){ |
| 518 |
return $cb($this->id, ...$args); |
| 519 |
}elseif($method === 'in_taxonomy'){ |
| 520 |
return is_object_in_taxonomy($this->post, ...$args); |
| 521 |
} |
| 522 |
|
| 523 |
return $this->call_dynamic_method($method, ...$args); |
| 524 |
} |
| 525 |
|
| 526 |
public function save($data){ |
| 527 |
if(array_find(['post_status', 'status'], fn($k)=> ($data[$k] ?? '') === 'publish')){ |
| 528 |
if($cb = wpjam_callback([$this, 'is_publishable'])){ |
| 529 |
$result = wpjam_catch($cb) ?: new WP_Error('cannot_publish', '不可发布'); |
| 530 |
} |
| 531 |
} |
| 532 |
|
| 533 |
return wpjam_then($result ?? true, fn()=> $data ? self::update($this->id, $data, false) : true); |
| 534 |
} |
| 535 |
|
| 536 |
public function set_status($status){ |
| 537 |
return $this->save(['post_status'=>$status]); |
| 538 |
} |
| 539 |
|
| 540 |
public function publish(){ |
| 541 |
return $this->set_status('publish'); |
| 542 |
} |
| 543 |
|
| 544 |
public function unpublish(){ |
| 545 |
return $this->set_status('draft'); |
| 546 |
} |
| 547 |
|
| 548 |
public function get_unserialized(){ |
| 549 |
return wpjam_unserialize($this->content, fn($fixed)=> $this->save(['content'=>$fixed])) ?: []; |
| 550 |
} |
| 551 |
|
| 552 |
public function parse_for_json($args=[]){ |
| 553 |
if($args && is_string($args) && in_array($args, ['date', 'modified'])){ |
| 554 |
$ts = get_post_timestamp($this->id, $args); |
| 555 |
$prefix = $args == 'modified' ? $args.'_' : ''; |
| 556 |
$result = [$prefix.'timestamp'=>$ts, $prefix.'time'=>wpjam_human_time_diff($ts), $prefix.'date'=>wpjam_date('Y-m-d', $ts)]; |
| 557 |
|
| 558 |
return $result+($args == 'date' ? ['day'=>wpjam_human_date_diff($result['date'])] : []); |
| 559 |
} |
| 560 |
|
| 561 |
$args += self::get_default_args(); |
| 562 |
$query = $args['query'] ?? null; |
| 563 |
$main = $query && $query->is_main_query(); |
| 564 |
$single = $query && ($query->is_single($this->id) || $query->is_page($this->id)); |
| 565 |
$rest = $single ? 'show_in_rest' : 'show_in_posts_rest'; |
| 566 |
$json = wpjam_pick($this, ['id', 'type', 'post_type', 'status', 'views'])+['icon'=>(string)$this->type_object->icon]; |
| 567 |
$json += $this->viewable ? ['name'=>urldecode($this->name), 'post_url'=>str_replace(home_url(), '', get_permalink($this->id))] : []; |
| 568 |
$json += wpjam_fill(['title', 'excerpt'], fn($k)=> $this->supports($k) ? html_entity_decode(('get_the_'.$k)($this->id)) : ''); |
| 569 |
$json += ['thumbnail'=>$this->get_thumbnail_url($args['thumbnail_size'])]; |
| 570 |
$json += $this->supports('images') ? ['images'=>$this->get_images()] : []; |
| 571 |
$json += ['user_id'=>(int)$this->author]; |
| 572 |
$json += $this->supports('author') ? ['author'=>wpjam_get_user($this->author)] : []; |
| 573 |
$json += $this->parse_for_json('date')+$this->parse_for_json('modified'); |
| 574 |
$json += $this->password ? ['password_protected'=>true, 'password_required'=>post_password_required($this->id)] : []; |
| 575 |
$json += $this->supports('page-attributes') ? ['menu_order'=>(int)$this->menu_order] : []; |
| 576 |
$json += $this->supports('post-formats') ? ['format'=>get_post_format($this->id) ?: ''] : []; |
| 577 |
|
| 578 |
if($main || $args['options_required']){ |
| 579 |
$json += array_reduce(wpjam_get_post_options($this->type, [$rest=>true]), fn($c, $o)=> $c+$o->prepare($this->id), []); |
| 580 |
} |
| 581 |
|
| 582 |
if($main || $args['taxonomy_required']){ |
| 583 |
$json += array_reduce($this->get_taxonomies([$rest=>true], 'names'), fn($c, $t)=> $c+[$t=>wpjam_get_terms(['terms'=>$this->get_terms($t), 'taxonomy'=>$t])], []); |
| 584 |
} |
| 585 |
|
| 586 |
if(($main && $single) || $args['content_required']){ |
| 587 |
if($this->supports('editor')){ |
| 588 |
$json += ['content'=>$this->get_content(), 'multipage'=>(bool)$GLOBALS['multipage']]; |
| 589 |
$json += $json['multipage'] ? ['numpages'=>$GLOBALS['numpages'], 'page'=>$GLOBALS['page']] : []; |
| 590 |
}else{ |
| 591 |
$json += is_serialized($this->content) ? ['content'=>$this->get_unserialized()] : []; |
| 592 |
} |
| 593 |
} |
| 594 |
|
| 595 |
$filter = $args['suppress_filter'] ? '' : ($main ? 'wpjam_post_json' : ($args['filter'] ?? '')); |
| 596 |
|
| 597 |
return $filter ? apply_filters($filter, $json, $this->id, $args) : $json; |
| 598 |
} |
| 599 |
|
| 600 |
public function value_callback($field){ |
| 601 |
if($field == 'tax_input'){ |
| 602 |
return wpjam_fill($this->get_taxonomies('names'), fn($tax)=> array_column($this->get_terms($tax), 'term_id')); |
| 603 |
} |
| 604 |
|
| 605 |
return $this->post->$field ?? $this->meta_get($field); |
| 606 |
} |
| 607 |
|
| 608 |
public function update_callback($data, $defaults){ |
| 609 |
return wpjam_then( |
| 610 |
$this->save(wpjam_pull($data, [...array_keys($this->data), 'tax_input'])), |
| 611 |
fn($result)=> $data ? $this->meta_input($data, $defaults) : $result |
| 612 |
); |
| 613 |
} |
| 614 |
|
| 615 |
public static function get_default_args(){ |
| 616 |
return [ |
| 617 |
'suppress_filter' => false, |
| 618 |
'options_required' => true, |
| 619 |
'taxonomy_required' => true, |
| 620 |
'content_required' => false, |
| 621 |
'thumbnail_size' => null |
| 622 |
]; |
| 623 |
} |
| 624 |
|
| 625 |
public static function get_instance($post=null, $type=null, $wp_error=false){ |
| 626 |
return wpjam_then( |
| 627 |
static::validate($post ?: get_post(), $type), |
| 628 |
fn($v)=> self::instance($v->ID, fn($id)=> [wpjam_get_post_type_setting(get_post_type($id), 'model') ?: 'WPJAM_Post', 'create_instance']($id)), |
| 629 |
fn($e)=> $wp_error ? $e : null |
| 630 |
); |
| 631 |
} |
| 632 |
|
| 633 |
public static function validate($value, $type=null){ |
| 634 |
$type ??= static::get_current_post_type(); |
| 635 |
|
| 636 |
return ($post = $value ? self::get_post($value) : null) |
| 637 |
? ((!post_type_exists($post->post_type) || ($type && $type !== 'any' && !in_array($post->post_type, (array)$type))) |
| 638 |
? new WP_Error('invalid_post_type') |
| 639 |
: $post |
| 640 |
) |
| 641 |
: new WP_Error('invalid_id'); |
| 642 |
} |
| 643 |
|
| 644 |
public static function get($post){ |
| 645 |
if($data = self::get_post($post, ARRAY_A)){ |
| 646 |
$key = 'post_content'; |
| 647 |
$data = ['id'=>$data['ID']]+(is_serialized($data[$key]) ? [$key=>wpjam_unserialize($data[$key])] : [])+$data; |
| 648 |
$data += wpjam_array($data, fn($k, $v)=> try_prefix($k, '-', 'post_') ? [$k, $v] : null); |
| 649 |
} |
| 650 |
|
| 651 |
return $data; |
| 652 |
} |
| 653 |
|
| 654 |
public static function update($post_id, $data, $validate=true){ |
| 655 |
return wpjam_then( |
| 656 |
$validate ? static::validate($post_id) : null, |
| 657 |
fn()=> parent::update($post_id, $data) |
| 658 |
); |
| 659 |
} |
| 660 |
|
| 661 |
protected static function call_method($method, ...$args){ |
| 662 |
if($method == 'insert'){ |
| 663 |
$data = $args[0]; |
| 664 |
$type = array_unique(array_filter([$data['post_type'] ?? '', static::get_current_post_type()])); |
| 665 |
$type = count($type) <= 1 ? (array_first($type) ?: 'post') : ''; |
| 666 |
|
| 667 |
$data['post_type'] = $type && post_type_exists($type) ? $type : wpjam_throw('invalid_post_type'); |
| 668 |
$data['post_status'] ??= current_user_can(get_post_type_object($type)->cap->publish_posts) ? 'publish' : 'draft'; |
| 669 |
$data['post_author'] ??= get_current_user_id(); |
| 670 |
$data['post_date'] ??= wpjam_date('Y-m-d H:i:s'); |
| 671 |
|
| 672 |
return wp_insert_post(wp_slash($data), true, true); |
| 673 |
}elseif($method == 'update'){ |
| 674 |
return wp_update_post(wp_slash(['ID'=>$args[0]]+$args[1]), true, true); |
| 675 |
}elseif($method == 'delete'){ |
| 676 |
return wp_delete_post($args[0], true) ?: wpjam_throw('delete_error', '删除失败'); |
| 677 |
} |
| 678 |
} |
| 679 |
|
| 680 |
protected static function sanitize_data($data, $post_id=0){ |
| 681 |
$key = 'post_content'; |
| 682 |
$data += wpjam_array(get_class_vars('WP_Post'), fn($k, $v)=> try_prefix($k, '-', 'post_') && isset($data[$k]) ? ['post_'.$k, $data[$k]] : null); |
| 683 |
|
| 684 |
return (is_array($data[$key] ?? '') ? [$key=>serialize($data[$key])] : [])+$data |
| 685 |
+(!$post_id && method_exists(static::class, 'is_publishable') ? ['post_status'=>'draft'] : []); |
| 686 |
} |
| 687 |
|
| 688 |
public static function get_by_ids($post_ids){ |
| 689 |
return array_map('get_post', array_filter(self::update_caches($post_ids))); |
| 690 |
} |
| 691 |
|
| 692 |
public static function update_caches($post_ids, $update_term_cache=false, $update_meta_cache=false){ |
| 693 |
if($post_ids = array_filter(wp_parse_id_list($post_ids))){ |
| 694 |
_prime_post_caches($post_ids, $update_term_cache, $update_meta_cache); |
| 695 |
|
| 696 |
$group = wpjam_group(wp_cache_get_multiple($post_ids, 'posts'), fn($v)=> $v ? 1 : 0); |
| 697 |
|
| 698 |
do_action('wpjam_deleted_ids', 'post', array_keys($group[0] ?? [])); |
| 699 |
do_action('wpjam_update_post_caches', ($group[1] ?? []), compact('update_term_cache', 'update_meta_cache')); |
| 700 |
|
| 701 |
return $group[1] ?? []; |
| 702 |
} |
| 703 |
|
| 704 |
return []; |
| 705 |
} |
| 706 |
|
| 707 |
public static function get_post($post, $output=OBJECT, $filter='raw'){ |
| 708 |
return wpjam_tap(get_post($post, $output, $filter), fn($v)=> $post && is_numeric($post) && !$v && do_action('wpjam_deleted_ids', 'post', $post)); |
| 709 |
} |
| 710 |
|
| 711 |
public static function get_current_post_type(){ |
| 712 |
if(static::class !== self::class){ |
| 713 |
return (WPJAM_Post_Type::get(static::class, 'model', self::class) ?: [])['name'] ?? null; |
| 714 |
} |
| 715 |
} |
| 716 |
|
| 717 |
public static function get_path($args, $item=[]){ |
| 718 |
$type = $item['post_type']; |
| 719 |
|
| 720 |
return $args === 'fields' |
| 721 |
? (get_post_type_object($type) ? [$type.'_id' => self::get_field(['post_type'=>$type, 'required'=>true])] : []) |
| 722 |
: (($id = is_array($args) ? (int)($args[$type.'_id'] ?? 0) : $args) |
| 723 |
? ($item['platform'] == 'template' ? get_permalink($id) : str_replace('%post_id%', $id, $item['path'])) |
| 724 |
: new WP_Error('invalid_id', [wpjam_get_post_type_setting($type, 'title')]) |
| 725 |
); |
| 726 |
} |
| 727 |
|
| 728 |
public static function get_field($args){ |
| 729 |
$args['title'] ??= is_string($args['post_type'] ?? null) ? wpjam_get_post_type_setting($args['post_type'], 'title') : null; |
| 730 |
$placeholder = '请输� |
| 731 |
�'.$args['title'].'ID或� |
| 732 |
输� |
| 733 |
�� |
| 734 |
�键字筛选'; |
| 735 |
|
| 736 |
return $args+compact('placeholder')+['type'=>'text', 'class'=>'all-options', 'data_type'=>'post_type']; |
| 737 |
} |
| 738 |
|
| 739 |
public static function with_field($method, $field, $value){ |
| 740 |
$type = $field->post_type; |
| 741 |
|
| 742 |
if($method == 'validate'){ |
| 743 |
return (is_numeric($value) && wpjam_try(static::class.'::validate', $value, $type)) ? (int)$value : null; |
| 744 |
}elseif($method == 'parse'){ |
| 745 |
return wpjam_get_post($value, ['post_type'=>$type, 'thumbnail_size'=>$field->size]); |
| 746 |
} |
| 747 |
} |
| 748 |
|
| 749 |
public static function query_items($args){ |
| 750 |
if(wpjam_pull($args, 'data_type')){ |
| 751 |
return wpjam_get_posts($args+[ |
| 752 |
's' => $args['search'] ?? null, |
| 753 |
'posts_per_page' => $args['number'] ?? 10, |
| 754 |
'suppress_filters' => false, |
| 755 |
]); |
| 756 |
} |
| 757 |
|
| 758 |
$args['post_status'] = wpjam_pull($args, 'status') ?: 'any'; |
| 759 |
$args['post_type'] ??= static::get_current_post_type(); |
| 760 |
$args['posts_per_page'] ??= $args['number'] ?? 10; |
| 761 |
|
| 762 |
return [ |
| 763 |
'items' => $GLOBALS['wp_query']->query($args), |
| 764 |
'total' => $GLOBALS['wp_query']->found_posts |
| 765 |
]; |
| 766 |
} |
| 767 |
|
| 768 |
public static function query_calendar($args){ |
| 769 |
return array_reduce($GLOBALS['wp_query']->query([ |
| 770 |
'posts_per_page' => -1, |
| 771 |
'post_status' => wpjam_pull($args, 'status') ?: 'any' |
| 772 |
]+$args+[ |
| 773 |
'post_type' => static::get_current_post_type(), |
| 774 |
'monthnum' => $args['month'] |
| 775 |
]), fn($c, $p)=> wpjam_set($c, wpjam_at($p->post_date, ' ', 0).'[]', $p), []); |
| 776 |
} |
| 777 |
|
| 778 |
public static function get_views(){ |
| 779 |
if(!in_array(get_current_screen()->base, ['edit', 'upload'])){ |
| 780 |
$counts = array_filter((array)wp_count_posts(static::get_current_post_type())); |
| 781 |
$views = ['all'=>['filter'=>['status'=>null, 'show_sticky'=>null], 'label'=>'� |
| 782 |
�部', 'count'=>array_sum($counts)]]; |
| 783 |
|
| 784 |
return wpjam_reduce($counts, fn($c, $v, $k)=> $c+(($object = get_post_status_object($k)) && $object->show_in_admin_status_list ? [$k=>['filter'=>['status'=>$k], 'label'=>$object->label, 'count'=>$v]] : []), $views); |
| 785 |
} |
| 786 |
} |
| 787 |
|
| 788 |
public static function filter_fields($fields, $id){ |
| 789 |
return ($id && !is_array($id) && !isset($fields['title']) && !isset($fields['post_title']) ? ['title'=>['title'=>wpjam_get_post_type_setting(get_post_type($id), 'title').'标题', 'type'=>'view', 'value'=>get_the_title($id)]] : [])+$fields; |
| 790 |
} |
| 791 |
|
| 792 |
public static function get_meta($post_id, ...$args){ // deprecated |
| 793 |
return wpjam_get_metadata('post', $post_id, ...$args); |
| 794 |
} |
| 795 |
|
| 796 |
public static function update_meta($post_id, ...$args){ // deprecated |
| 797 |
return wpjam_update_metadata('post', $post_id, ...$args); |
| 798 |
} |
| 799 |
|
| 800 |
public static function update_metas($post_id, $data, $meta_keys=[]){ |
| 801 |
return static::update_meta($post_id, $data, $meta_keys); |
| 802 |
} |
| 803 |
} |
| 804 |
|
| 805 |
class WPJAM_Term extends WPJAM_Instance{ |
| 806 |
public function __get($key){ |
| 807 |
if($key == 'id'){ |
| 808 |
return $this->id; |
| 809 |
}elseif($key == 'tax_object'){ |
| 810 |
return wpjam_get_taxonomy($this->taxonomy); |
| 811 |
}elseif($key == 'object_type'){ |
| 812 |
return $this->tax_object->$key ?: []; |
| 813 |
}elseif($key == 'level'){ |
| 814 |
return get_term_level($this->id); |
| 815 |
}elseif($key == 'depth'){ |
| 816 |
return get_term_depth($this->id); |
| 817 |
}elseif($key == 'link'){ |
| 818 |
return get_term_link($this->term); |
| 819 |
} |
| 820 |
|
| 821 |
return $this->builtin($key); |
| 822 |
} |
| 823 |
|
| 824 |
public function __call($method, $args){ |
| 825 |
if($method == 'get_tax_setting'){ |
| 826 |
return $this->tax_object->{$args[0]}; |
| 827 |
}elseif(in_array($method, ['get_taxonomies', 'supports'])){ |
| 828 |
return $this->tax_object->$method(...$args); |
| 829 |
}elseif(in_array($method, ['set_object', 'add_object', 'remove_object'])){ |
| 830 |
$cb = 'wp_'.$method.'_terms'; |
| 831 |
|
| 832 |
return $cb(array_shift($args), [$this->id], $this->taxonomy, ...$args); |
| 833 |
}elseif($method == 'is_object_in'){ |
| 834 |
return is_object_in_term($args[0], $this->taxonomy, $this->id); |
| 835 |
} |
| 836 |
|
| 837 |
return $this->call_dynamic_method($method, ...$args); |
| 838 |
} |
| 839 |
|
| 840 |
public function value_callback($field){ |
| 841 |
return $this->term->$field ?? $this->meta_get($field); |
| 842 |
} |
| 843 |
|
| 844 |
public function update_callback($data, $defaults){ |
| 845 |
return wpjam_then( |
| 846 |
$this->save(wpjam_pull($data, ['name', 'parent', 'slug', 'description', 'alias_of'])), |
| 847 |
fn($result)=> $data ? $this->meta_input($data, $defaults) : $result |
| 848 |
); |
| 849 |
} |
| 850 |
|
| 851 |
public function save($data){ |
| 852 |
return $data ? self::update($this->id, $data, false) : true; |
| 853 |
} |
| 854 |
|
| 855 |
public function get_object_type(){ |
| 856 |
return $this->object_type; |
| 857 |
} |
| 858 |
|
| 859 |
public function get_thumbnail_url($size='full', $crop=1){ |
| 860 |
return wpjam_get_term_thumbnail_url($this->term, $size, $crop); |
| 861 |
} |
| 862 |
|
| 863 |
public function parse_for_json($args=[]){ |
| 864 |
$id = $this->id; |
| 865 |
$tax = $this->taxonomy; |
| 866 |
$json = ['id'=>$id, 'name'=>html_entity_decode($this->name)]+wpjam_pick($this, ['name', 'taxonomy', 'count', ...(is_taxonomy_viewable($tax) ? ['slug'] : []), ...(is_taxonomy_hierarchical($tax) ? ['parent'] : []), 'description']); |
| 867 |
|
| 868 |
return apply_filters('wpjam_term_json', array_reduce(wpjam_get_term_options($tax), fn($c, $v)=> array_merge($c, $v->prepare($id)), $json), $id); |
| 869 |
} |
| 870 |
|
| 871 |
public static function get_instance($term, $tax=null, $wp_error=false){ |
| 872 |
return wpjam_then( |
| 873 |
self::validate($term, $tax), |
| 874 |
fn($v)=> self::instance($v->term_id, fn($id)=> [wpjam_get_taxonomy_setting(get_term_taxonomy($id), 'model') ?: 'WPJAM_Term', 'create_instance']($id)), |
| 875 |
fn($e)=> $wp_error ? $e : null |
| 876 |
); |
| 877 |
} |
| 878 |
|
| 879 |
public static function get($term){ |
| 880 |
return wpjam_then( |
| 881 |
$term ? self::get_term($term, '', ARRAY_A) : [], |
| 882 |
fn($data)=> $data ? $data+['id'=>$data['term_id']] : $data |
| 883 |
); |
| 884 |
} |
| 885 |
|
| 886 |
public static function update($term_id, $data, $validate=true){ |
| 887 |
return wpjam_then( |
| 888 |
$validate ? static::validate($term_id) : null, |
| 889 |
fn()=> parent::update($term_id, $data) |
| 890 |
); |
| 891 |
} |
| 892 |
|
| 893 |
protected static function call_method($method, ...$args){ |
| 894 |
if($method == 'insert'){ |
| 895 |
$data = $args[0]; |
| 896 |
$tax = array_unique(array_filter([wpjam_pull($data, 'taxonomy'), static::get_current_taxonomy()])); |
| 897 |
$tax = count($tax) == 1 ? array_first($tax) : null; |
| 898 |
|
| 899 |
return wp_insert_term(wp_slash(wpjam_pull($data, 'name')), $tax, wp_slash($data))['term_id']; |
| 900 |
}elseif($method == 'update'){ |
| 901 |
$data = $args[1]; |
| 902 |
$tax = wpjam_pull($data, 'taxonomy') ?: get_term_field('taxonomy', $args[0]); |
| 903 |
|
| 904 |
return wp_update_term($args[0], $tax, wp_slash($data)); |
| 905 |
}elseif($method == 'delete'){ |
| 906 |
return wp_delete_term($args[0], get_term_field('taxonomy', $args[0])); |
| 907 |
} |
| 908 |
} |
| 909 |
|
| 910 |
public static function get_meta($term_id, ...$args){ // deprecated |
| 911 |
return wpjam_get_metadata('term', $term_id, ...$args); |
| 912 |
} |
| 913 |
|
| 914 |
public static function update_meta($term_id, ...$args){ // deprecated |
| 915 |
return wpjam_update_metadata('term', $term_id, ...$args); |
| 916 |
} |
| 917 |
|
| 918 |
public static function update_metas($term_id, $data, $meta_keys=[]){ // deprecated |
| 919 |
return self::update_meta($term_id, $data, $meta_keys); |
| 920 |
} |
| 921 |
|
| 922 |
public static function get_by_ids($term_ids){ |
| 923 |
return self::update_caches($term_ids); |
| 924 |
} |
| 925 |
|
| 926 |
public static function update_caches($term_ids){ |
| 927 |
if($term_ids = array_filter(wp_parse_id_list($term_ids))){ |
| 928 |
_prime_term_caches($term_ids); |
| 929 |
|
| 930 |
$group = wpjam_group(wp_cache_get_multiple($term_ids, 'terms'), fn($v)=> $v ? 1 : 0); |
| 931 |
|
| 932 |
do_action('wpjam_deleted_ids', 'term', array_keys($group[0] ?? [])); |
| 933 |
|
| 934 |
return $group[1] ?? []; |
| 935 |
} |
| 936 |
|
| 937 |
return []; |
| 938 |
} |
| 939 |
|
| 940 |
public static function get_term($term, $tax='', $output=OBJECT, $filter='raw'){ |
| 941 |
return wpjam_tap(get_term($term, $tax, $output, $filter), fn($v)=> $term && is_numeric($term) && !$v && do_action('wpjam_deleted_ids', 'term', $term)); |
| 942 |
} |
| 943 |
|
| 944 |
public static function get_current_taxonomy(){ |
| 945 |
if(static::class !== self::class){ |
| 946 |
return (WPJAM_Taxonomy::get(static::class, 'model', self::class) ?: [])['name'] ?? null; |
| 947 |
} |
| 948 |
} |
| 949 |
|
| 950 |
public static function get_path($args, $item=[]){ |
| 951 |
$tax = $item['taxonomy']; |
| 952 |
$key = wpjam_get_taxonomy_setting($tax, 'query_key'); |
| 953 |
|
| 954 |
return $args === 'fields' |
| 955 |
? ($key ? [$key=> self::get_field(['taxonomy'=>$tax, 'required'=>true])] : []) |
| 956 |
: (($id = is_array($args) ? (int)wpjam_get($args, $key) : $args) |
| 957 |
? ($item['platform'] == 'template' ? get_term_link($id) : str_replace('%term_id%', $id, $item['path'])) |
| 958 |
: new WP_Error('invalid_id', [wpjam_get_taxonomy_setting($tax, 'title')]) |
| 959 |
); |
| 960 |
} |
| 961 |
|
| 962 |
public static function get_field($args=[]){ |
| 963 |
$object = isset($args['taxonomy']) && is_string($args['taxonomy']) ? wpjam_get_taxonomy($args['taxonomy']) : null; |
| 964 |
$type = $args['type'] ?? ''; |
| 965 |
$title = $args['title'] ??= $object ? $object->title : null; |
| 966 |
$args += ['data_type'=>'taxonomy']; |
| 967 |
|
| 968 |
if($object && $object->hierarchical){ |
| 969 |
if(!$type && is_admin() && $object->levels > 1 && $object->selectable()){ |
| 970 |
$type = 'cascade'; |
| 971 |
}elseif(!$type || ($type == 'mu-text' && empty($args['item_type']))){ |
| 972 |
$type = (!is_admin() || $object->selectable()) ? ($type ? 'mu-' : '').'select' : $type; |
| 973 |
}elseif($type == 'mu-text' && $args['item_type'] == 'select'){ |
| 974 |
$type = 'mu-select'; |
| 975 |
} |
| 976 |
} |
| 977 |
|
| 978 |
if(in_array($type, ['select', 'mu-select', 'cascade'])){ |
| 979 |
if(($k = 'show_option_all') && ($v = array_first(wpjam_pull($args, [$k, 'option_all']))) !== false){ |
| 980 |
$args[$k] = $v === true || is_null($v) ? '请选择' : $v; |
| 981 |
} |
| 982 |
|
| 983 |
return ['type'=>$type]+($type == 'cascade' ? ['filter_key'=>'parent'] : ['options'=> fn()=> $object->get_options()])+$args; |
| 984 |
} |
| 985 |
|
| 986 |
return $args+['type'=>'text', 'class'=>'all-options', 'placeholder'=>'请输� |
| 987 |
�'.$title.'ID或� |
| 988 |
输� |
| 989 |
�� |
| 990 |
�键字筛选']; |
| 991 |
} |
| 992 |
|
| 993 |
public static function with_field($method, $field, $value){ |
| 994 |
$tax = $field->taxonomy; |
| 995 |
|
| 996 |
if($method == 'render'){ |
| 997 |
$terms = get_terms(['taxonomy'=>$tax, 'hide_empty'=>0]); |
| 998 |
$values = $value ? array_reverse([$value, ...get_ancestors($value, $tax, 'taxonomy')]) : []; |
| 999 |
|
| 1000 |
for($i = 0; $i < wpjam_get_taxonomy_setting($tax, 'levels'); $i++){ |
| 1001 |
$parent = $i ? ($values[$i-1] ?? null) : 0; |
| 1002 |
$options[] = is_null($parent) ? [] : array_column(wp_list_filter($terms, ['parent'=>$parent]), 'name', 'term_id'); |
| 1003 |
} |
| 1004 |
|
| 1005 |
return ['value'=>$values, 'options'=>$options]; |
| 1006 |
}elseif($method == 'validate'){ |
| 1007 |
if(is_array($value)){ |
| 1008 |
$value = array_first(wpjam_sort(array_filter($value), 'kr')) ?: 0; |
| 1009 |
} |
| 1010 |
|
| 1011 |
if(is_numeric($value)){ |
| 1012 |
return !$value || wpjam_try('get_term', $value, $tax) ? (int)$value : null; |
| 1013 |
} |
| 1014 |
|
| 1015 |
$result = term_exists($value, $tax); |
| 1016 |
|
| 1017 |
return $result ? (is_array($result) ? $result['term_id'] : $result) : ($field->creatable ? wpjam_try('WPJAM_Term::insert', ['name'=>$value, 'taxonomy'=>$tax]) : null); |
| 1018 |
}elseif($method == 'parse'){ |
| 1019 |
return wpjam_get_term($value, $tax); |
| 1020 |
} |
| 1021 |
} |
| 1022 |
|
| 1023 |
public static function query_items($args){ |
| 1024 |
if(wpjam_pull($args, 'data_type')){ |
| 1025 |
return array_values(get_terms($args+['number'=>(isset($args['parent']) ? 0 : 10), 'hide_empty'=>false])); |
| 1026 |
} |
| 1027 |
|
| 1028 |
$defaults = ['hide_empty'=>false, 'taxonomy'=>static::get_current_taxonomy()]; |
| 1029 |
|
| 1030 |
return ['items'=>get_terms($args+$defaults), 'total'=>wp_count_terms($defaults)]; |
| 1031 |
} |
| 1032 |
|
| 1033 |
public static function validate($id, $tax=null){ |
| 1034 |
$tax ??= self::get_current_taxonomy(); |
| 1035 |
|
| 1036 |
return wpjam_then(self::get_term($id), fn($v)=> (!$v || !($v instanceof WP_Term)) |
| 1037 |
? new WP_Error('invalid_term_id') |
| 1038 |
: (($tax && $tax !== 'any' && !in_array($v->taxonomy, (array)$tax)) ? new WP_Error('invalid_taxonomy') : $v) |
| 1039 |
); |
| 1040 |
} |
| 1041 |
|
| 1042 |
public static function filter_fields($fields, $id){ |
| 1043 |
return ($id && !is_array($id) && !isset($fields['name']) ? ['name'=>['title'=>wpjam_get_taxonomy_setting(get_term_field('taxonomy', $id), 'title'), 'type'=>'view', 'value'=>get_term_field('name', $id)]] : [])+$fields; |
| 1044 |
} |
| 1045 |
} |
| 1046 |
|
| 1047 |
class WPJAM_User extends WPJAM_Instance{ |
| 1048 |
public function __get($key){ |
| 1049 |
if(in_array($key, ['id', 'user_id'])){ |
| 1050 |
return $this->id; |
| 1051 |
}elseif($key == 'role'){ |
| 1052 |
return array_first($this->roles); |
| 1053 |
}elseif($key === 'data'){ |
| 1054 |
return get_userdata($this->id); |
| 1055 |
} |
| 1056 |
|
| 1057 |
return $this->builtin($key); |
| 1058 |
} |
| 1059 |
|
| 1060 |
public function value_callback($field){ |
| 1061 |
return $this->$field; |
| 1062 |
} |
| 1063 |
|
| 1064 |
public function save($data){ |
| 1065 |
return $data ? self::update($this->id, $data) : true; |
| 1066 |
} |
| 1067 |
|
| 1068 |
public function parse_for_json($size=96){ |
| 1069 |
return apply_filters('wpjam_user_json', [ |
| 1070 |
'id' => $this->id, |
| 1071 |
'nickname' => $this->nickname, |
| 1072 |
'name' => $this->display_name, |
| 1073 |
'display_name' => $this->display_name, |
| 1074 |
'avatar' => get_avatar_url($this->user, $size), |
| 1075 |
], $this->id); |
| 1076 |
} |
| 1077 |
|
| 1078 |
public function add_role($role, $blog_id=0){ |
| 1079 |
return $role ? wpjam_call_for_blog($blog_id, fn()=> $this->roles && !in_array($role, $this->roles) |
| 1080 |
? new WP_Error('error', '你已有权限,如果需要更改权限,请联系管理员直接修改。') |
| 1081 |
: wpjam_tap($this, fn()=> $this->user->add_role($role))) : $this; |
| 1082 |
} |
| 1083 |
|
| 1084 |
public function login(){ |
| 1085 |
wp_set_auth_cookie($this->id, true, is_ssl()); |
| 1086 |
wp_set_current_user($this->id); |
| 1087 |
do_action('wp_login', $this->user_login, $this->user); |
| 1088 |
|
| 1089 |
return $this; |
| 1090 |
} |
| 1091 |
|
| 1092 |
public static function get_instance($id, $wp_error=false){ |
| 1093 |
return wpjam_then( |
| 1094 |
self::validate($id), |
| 1095 |
fn($v)=> self::instance($v->ID, fn($id)=> new self($id)), |
| 1096 |
fn($e)=> $wp_error ? $e : null |
| 1097 |
); |
| 1098 |
} |
| 1099 |
|
| 1100 |
public static function validate($user_id){ |
| 1101 |
return ($user_id && ($user = self::get_user($user_id)) && ($user instanceof WP_User)) ? $user : new WP_Error('invalid_user_id'); |
| 1102 |
} |
| 1103 |
|
| 1104 |
public static function update_caches($ids){ |
| 1105 |
$ids = array_filter(wp_parse_id_list($ids)); |
| 1106 |
|
| 1107 |
return $ids && (cache_users($ids) || true) ? array_map('get_userdata', $ids) : []; |
| 1108 |
} |
| 1109 |
|
| 1110 |
public static function get_by_ids($ids){ |
| 1111 |
return self::update_caches($ids); |
| 1112 |
} |
| 1113 |
|
| 1114 |
public static function get_user($user){ |
| 1115 |
return $user && is_numeric($user) ? wpjam_tap(get_userdata($user), fn($v)=> !$v && do_action('wpjam_deleted_ids', 'user', $user)) : $user; |
| 1116 |
} |
| 1117 |
|
| 1118 |
public static function get_authors($args=[]){ |
| 1119 |
return get_users(array_merge($args, ['capability'=>'edit_posts'])); |
| 1120 |
} |
| 1121 |
|
| 1122 |
public static function get_path($args, $item=[]){ |
| 1123 |
return $args === 'fields' |
| 1124 |
? ['author' => ['type'=>'select', 'options'=>fn()=> wp_list_pluck(WPJAM_User::get_authors(), 'display_name', 'ID')]] |
| 1125 |
: (($id = is_array($args) ? (int)wpjam_get($args, 'author') : $args) |
| 1126 |
? ($item['platform'] == 'template' ? get_author_posts_url($id) : str_replace('%author%', $id, $item['path'])) |
| 1127 |
: new WP_Error('invalid_author', ['作� |
| 1128 |
']) |
| 1129 |
); |
| 1130 |
} |
| 1131 |
|
| 1132 |
public static function options_callback($field){ |
| 1133 |
return wp_list_pluck(self::get_authors(), 'display_name', 'ID'); |
| 1134 |
} |
| 1135 |
|
| 1136 |
public static function get($id){ |
| 1137 |
return ($user = get_userdata($id)) ? $user->to_array() : []; |
| 1138 |
} |
| 1139 |
|
| 1140 |
protected static function call_method($method, ...$args){ |
| 1141 |
if($method == 'create'){ |
| 1142 |
$args = $args[0]+[ |
| 1143 |
'user_pass' => wp_generate_password(12, false), |
| 1144 |
'user_login' => '', |
| 1145 |
'user_email' => '', |
| 1146 |
'nickname' => '', |
| 1147 |
// 'avatarurl' => '', |
| 1148 |
]; |
| 1149 |
|
| 1150 |
if(!wpjam_pull($args, 'users_can_register', get_option('users_can_register'))){ |
| 1151 |
return new WP_Error('registration_closed', '用户注册� |
| 1152 |
�闭,请联系管理员手动添加!'); |
| 1153 |
} |
| 1154 |
|
| 1155 |
if(empty($args['user_email'])){ |
| 1156 |
return new WP_Error('empty_user_email', '用户的邮箱不能为空。'); |
| 1157 |
} |
| 1158 |
|
| 1159 |
$args['user_login'] = preg_replace('/\s+/', '', sanitize_user($args['user_login'], true)); |
| 1160 |
|
| 1161 |
$lock_key = $args['user_login'] ? $args['user_login'].'_register_lock' : ''; |
| 1162 |
|
| 1163 |
if($lock_key && wpjam_lock($lock_key, 5, 'users')){ |
| 1164 |
return new WP_Error('error', '该用户名正在注册中,请稍后再试!'); |
| 1165 |
} |
| 1166 |
|
| 1167 |
$data = wpjam_pick($args, ['user_login', 'user_pass', 'user_email', 'role']); |
| 1168 |
$data += $args['nickname'] ? ['nickname'=>$args['nickname'], 'display_name'=>$args['nickname']] : []; |
| 1169 |
$id = static::insert($data); |
| 1170 |
|
| 1171 |
if($lock_key){ |
| 1172 |
wpjam_lock($lock_key, -1, 'users'); |
| 1173 |
} |
| 1174 |
|
| 1175 |
return wpjam_then($id, fn()=> static::get_instance($id)); |
| 1176 |
}elseif($method == 'insert'){ |
| 1177 |
return wp_insert_user(wp_slash($args[0])); |
| 1178 |
}elseif($method == 'update'){ |
| 1179 |
return wp_update_user(wp_slash(array_merge($args[1], ['ID'=>$args[0]]))); |
| 1180 |
}elseif($method == 'delete'){ |
| 1181 |
return wp_delete_user($args[0]); |
| 1182 |
} |
| 1183 |
} |
| 1184 |
|
| 1185 |
public static function create($args){ |
| 1186 |
return wpjam_call_for_blog(wpjam_get($args, 'blog_id'), fn()=> static::call_method('create', $args)); |
| 1187 |
} |
| 1188 |
|
| 1189 |
public static function query_items($args){ |
| 1190 |
if(wpjam_pull($args, 'data_type')){ |
| 1191 |
return get_users(array_merge($args, ['search'=> !empty($args['search']) ? '*'.$args['search'].'*' : ''])); |
| 1192 |
} |
| 1193 |
} |
| 1194 |
|
| 1195 |
public static function filter_fields($fields, $id){ |
| 1196 |
if($id && !is_array($id)){ |
| 1197 |
$object = self::get_instance($id); |
| 1198 |
$fields = array_merge(['name'=>['title'=>'用户', 'type'=>'view', 'value'=>$object->display_name]], $fields); |
| 1199 |
} |
| 1200 |
|
| 1201 |
return $fields; |
| 1202 |
} |
| 1203 |
} |
| 1204 |
|
| 1205 |
class WPJAM_Bind extends WPJAM_Register{ |
| 1206 |
public function __construct($type, $appid){ |
| 1207 |
parent::__construct($type.':'.$appid, [ |
| 1208 |
'type' => $type, |
| 1209 |
'appid' => $appid, |
| 1210 |
'bind_key' => wpjam_join('_', $type, $appid), |
| 1211 |
'domain' => $type == 'phone' ? 'phone.sms' : $appid.'.'.$type |
| 1212 |
]); |
| 1213 |
} |
| 1214 |
|
| 1215 |
public function get_appid(){ |
| 1216 |
return $this->appid; |
| 1217 |
} |
| 1218 |
|
| 1219 |
public function get_openid($meta_type, $object_id){ |
| 1220 |
return get_metadata($meta_type, $object_id, $this->bind_key, true); |
| 1221 |
} |
| 1222 |
|
| 1223 |
public function update_openid($meta_type, $object_id, $openid){ |
| 1224 |
if(!$openid){ |
| 1225 |
return delete_metadata($meta_type, $object_id, $this->bind_key); |
| 1226 |
} |
| 1227 |
|
| 1228 |
return update_metadata($meta_type, $object_id, $this->bind_key, $openid); |
| 1229 |
} |
| 1230 |
|
| 1231 |
public function bind_openid($meta_type, $object_id, $openid){ |
| 1232 |
$bound = ($current = $this->get_openid($meta_type, $object_id)) && $current != $openid; |
| 1233 |
|
| 1234 |
if($bound = $bound ?: wpjam_then($this->get_by_openid($meta_type, $openid), fn($v)=> $v && $v->id != $object_id)){ |
| 1235 |
return wpjam_then($bound, new WP_Error('is_bound', '已绑定� |
| 1236 |
�他账号,请� |
| 1237 |
�解绑再试!')); |
| 1238 |
} |
| 1239 |
|
| 1240 |
$this->update_value($openid, $meta_type.'_id', $object_id); |
| 1241 |
$this->update_openid($meta_type, $object_id, $openid); |
| 1242 |
|
| 1243 |
return $openid; |
| 1244 |
} |
| 1245 |
|
| 1246 |
public function unbind_openid($meta_type, $object_id, $openid=null){ |
| 1247 |
$openid = $openid ?: $this->get_openid($meta_type, $object_id); |
| 1248 |
|
| 1249 |
if($openid = $openid ?: wpjam_call_method($this, 'get_openid_by', $meta_type.'_id', $object_id)){ |
| 1250 |
$this->update_openid($meta_type, $object_id, ''); |
| 1251 |
$this->update_value($openid, $meta_type.'_id', 0); |
| 1252 |
} |
| 1253 |
|
| 1254 |
return $openid; |
| 1255 |
} |
| 1256 |
|
| 1257 |
public function get_by_openid($meta_type, $openid){ |
| 1258 |
if(!$this->get_value($openid)){ |
| 1259 |
return new WP_Error('invalid_openid'); |
| 1260 |
} |
| 1261 |
|
| 1262 |
$cb = 'wpjam_get_'.$meta_type.'_object'; |
| 1263 |
$object = wpjam_call($cb, $this->get_value($openid, $meta_type.'_id')); |
| 1264 |
$object ??= ($meta = wpjam_get_by_meta($meta_type, $this->bind_key, $openid)) ? wpjam_call($cb, array_first($meta)[$meta_type.'_id']) : null; |
| 1265 |
|
| 1266 |
return $object ?: (($meta_type == 'user' && ($user_id = username_exists($openid))) ? wpjam_get_user($user_id, 'object') : null); |
| 1267 |
} |
| 1268 |
|
| 1269 |
public function get_by_user_email($meta_type, $email){ |
| 1270 |
if($email && try_suffix($email, '-', '@'.$this->domain)){ |
| 1271 |
return $this->get_value($email, $meta_type.'_id'); |
| 1272 |
} |
| 1273 |
} |
| 1274 |
|
| 1275 |
protected function get_value($openid, $key=null){ |
| 1276 |
return wpjam_get(method_exists($this, 'get_user') ? $this->get_user($openid) : ['openid'=>$openid], $key ?: null); |
| 1277 |
} |
| 1278 |
|
| 1279 |
protected function update_value($openid, $key, $value){ |
| 1280 |
return method_exists($this, 'update_user') ? $this->update_user($openid, [$key=>$value]) : true; |
| 1281 |
} |
| 1282 |
|
| 1283 |
public function get_user_email($openid){ |
| 1284 |
return $openid.'@'.$this->domain; |
| 1285 |
} |
| 1286 |
|
| 1287 |
public function get_email($openid){ |
| 1288 |
return $this->get_user_email($openid); |
| 1289 |
} |
| 1290 |
|
| 1291 |
public function get_avatarurl($openid){ |
| 1292 |
return $this->get_value($openid, 'avatarurl'); |
| 1293 |
} |
| 1294 |
|
| 1295 |
public function get_nickname($openid){ |
| 1296 |
return $this->get_value($openid, 'nickname'); |
| 1297 |
} |
| 1298 |
|
| 1299 |
public function get_unionid($openid){ |
| 1300 |
return $this->get_value($openid, 'unionid'); |
| 1301 |
} |
| 1302 |
|
| 1303 |
public function get_phone_data($openid){ |
| 1304 |
return ($phone = $this->get_value($openid, 'phone')) ? ['phone'=>$phone, 'country_code'=>$this->get_value($openid, 'country_code') ?: 86] : []; |
| 1305 |
} |
| 1306 |
} |
| 1307 |
|
| 1308 |
class WPJAM_User_Signup extends WPJAM_Register{ |
| 1309 |
public function __call($method, $args){ |
| 1310 |
return [wpjam_get_bind($this->type, $this->appid), $method](...(str_ends_with($method, '_openid') ? ['user', ...$args] : $args)); |
| 1311 |
} |
| 1312 |
|
| 1313 |
public function signup($data, $args=null){ |
| 1314 |
if(is_array($data)){ |
| 1315 |
$by = $this->by; |
| 1316 |
$args ??= ($data['args'] ?? '') ?: []; |
| 1317 |
$key = $by == 'code' ? '' : ($data[$by] ?? ''); |
| 1318 |
$user = apply_filters('wpjam_user_signup', null, $by, $key, $data['code'] ?? '') ?: $this->signup($this->verify($data), $args); |
| 1319 |
|
| 1320 |
return wpjam_tap($user, null, fn()=> do_action('wpjam_user_signup_failed', $by, $key, $user)); |
| 1321 |
} |
| 1322 |
|
| 1323 |
$openid = $data; |
| 1324 |
$args = apply_filters('wpjam_user_signup_args', $args ?? [], $this->type, $this->appid, $openid); |
| 1325 |
$user = wpjam_then($openid, fn()=> wpjam_then( |
| 1326 |
$this->get_by_openid($openid), |
| 1327 |
fn($user)=> $user ? $user->add_role($args['role'] ?? '', $args['blog_id'] ?? 0) : WPJAM_User::create([ |
| 1328 |
'user_login' => $openid, |
| 1329 |
'user_email' => $this->get_user_email($openid), |
| 1330 |
'nickname' => $this->get_nickname($openid) |
| 1331 |
]+$args) |
| 1332 |
)); |
| 1333 |
|
| 1334 |
return wpjam_tap($user, fn()=> $this->bind($openid, $user->id) && do_action('wpjam_user_signuped', $user->login()->data, $args)); |
| 1335 |
} |
| 1336 |
|
| 1337 |
public function bind($data, $user_id=null){ |
| 1338 |
$user = wpjam_get_user($user_id ?? get_current_user_id(), 'object'); |
| 1339 |
$openid = is_array($data) ? $this->verify($data) : $data; |
| 1340 |
$openid = wpjam_then($openid, fn()=> $this->bind_openid($user->id, $openid)); |
| 1341 |
|
| 1342 |
if(!wpjam_if_error($openid, '')){ |
| 1343 |
if(($avatarurl = $this->get_avatarurl($openid)) && $avatarurl !== $user->avatarurl){ |
| 1344 |
$user->meta_input('avatarurl', $avatarurl); |
| 1345 |
} |
| 1346 |
|
| 1347 |
if(($nickname = $this->get_nickname($openid)) && $nickname !== $user->nickname){ |
| 1348 |
$user->save(['nickname'=>$nickname, 'display_name'=>$nickname]); |
| 1349 |
} |
| 1350 |
} |
| 1351 |
|
| 1352 |
return $openid; |
| 1353 |
} |
| 1354 |
|
| 1355 |
public function unbind($user_id=null){ |
| 1356 |
return $this->unbind_openid($user_id ?? get_current_user_id()); |
| 1357 |
} |
| 1358 |
|
| 1359 |
public function verify($data){ |
| 1360 |
return $this->qrcode |
| 1361 |
? wpjam_then($this->qrcode->verify($data['scene'], $data['code']), fn($qrcode)=> $qrcode['openid']) |
| 1362 |
: $this->call('verify', $data); |
| 1363 |
} |
| 1364 |
|
| 1365 |
public function get_fields($action='login', $for='admin'){ |
| 1366 |
if($action == 'bind' && ($openid = $this->get_openid(get_current_user_id()))){ |
| 1367 |
$view = wpjam_join("<br />", [ |
| 1368 |
($avatar = $this->get_avatarurl($openid)) ? '<img src="'.str_replace('/132', '/0', $avatar).'" width="272" />' : '', |
| 1369 |
($nickname = $this->get_nickname($openid)) ? '<strong>'.$nickname.'</strong>' : '' |
| 1370 |
]); |
| 1371 |
|
| 1372 |
return [ |
| 1373 |
'view' => ['type'=>'view', 'title'=>'已绑定', 'value'=>($view ?: $openid)], |
| 1374 |
'action' => ['type'=>'hidden', 'value'=>'unbind'], |
| 1375 |
]; |
| 1376 |
} |
| 1377 |
|
| 1378 |
$fields = $this->qrcode |
| 1379 |
? wpjam_then($this->qrcode->get_fields($action), fn($v)=> wpjam_set($v, 'qrcode[title]', $this->title)) |
| 1380 |
: ((is_callable($this->fields) ? $this->call('fields', $action, $for) : $this->fields) ?: []); |
| 1381 |
|
| 1382 |
return wpjam_then($fields, $fields+['action' => ['type'=>'hidden', 'value'=>$action]]); |
| 1383 |
} |
| 1384 |
|
| 1385 |
public function get_attr($action='login', $for=''){ |
| 1386 |
return wpjam_then($this->get_fields($action, $for), fn($fields)=> array_merge( |
| 1387 |
$action == 'bind' ? ['submit_text'=>$fields['action']['value'] == 'unbind' ? '解除绑定' : '立刻绑定'] : [], |
| 1388 |
$for != 'admin' ? wpjam_ajax($this->name.'-signup')->to_array() : [], |
| 1389 |
['fields'=>$for != 'admin' ? wpjam_fields($fields)->render(['wrap_tag'=>'p']) : $fields] |
| 1390 |
)); |
| 1391 |
} |
| 1392 |
|
| 1393 |
public function get_form(){ |
| 1394 |
return $this->get_attr('bind', 'admin')+[ |
| 1395 |
'callback' => [$this, 'callback'], |
| 1396 |
'capability' => 'read', |
| 1397 |
'validate' => true, |
| 1398 |
'response' => 'redirect' |
| 1399 |
]; |
| 1400 |
} |
| 1401 |
|
| 1402 |
public function callback($data){ |
| 1403 |
$action = wpjam_pull($data, 'action'); |
| 1404 |
|
| 1405 |
return try_prefix($action, '-', 'get-') |
| 1406 |
? $this->get_attr($action) |
| 1407 |
: wpjam_then(wpjam_catch([$this, $action == 'login' ? 'signup' : $action], ...($action == 'unbind' ? [] : [$data])), true); |
| 1408 |
} |
| 1409 |
|
| 1410 |
public function registered(){ |
| 1411 |
wpjam_ajax($this->name.'-signup', [ |
| 1412 |
'nopriv' => true, |
| 1413 |
'callback' => [$this, 'callback'], |
| 1414 |
'nonce_action' => fn($data)=> str_starts_with($data['action'] ?? '', 'get-') ? '' : $this->name.'-signup' |
| 1415 |
]); |
| 1416 |
} |
| 1417 |
|
| 1418 |
public static function create($type, $args){ |
| 1419 |
if(wpjam_get_bind($type, $args['appid'] ?? '')){ |
| 1420 |
$model = wpjam_pull($args, 'model') ?: 'WPJAM_User_Signup'; |
| 1421 |
$model = is_object($model) ? get_class($model) : $model; // � |
| 1422 |
�容 |
| 1423 |
|
| 1424 |
return self::register(new $model($type, $args+['type'=>$type])); |
| 1425 |
} |
| 1426 |
} |
| 1427 |
|
| 1428 |
public static function on_admin_init(){ |
| 1429 |
$objects = self::get_registereds(); |
| 1430 |
$tabs = wpjam_array($objects, fn($k, $v)=> $v->bind ? [$k, [ |
| 1431 |
'title' => $v->title, |
| 1432 |
'capability' => 'read', |
| 1433 |
'function' => 'form', |
| 1434 |
'form' => [$v, 'get_form'] |
| 1435 |
]] : null); |
| 1436 |
|
| 1437 |
$tabs && wpjam_add_menu_page([ |
| 1438 |
'parent' => 'users', |
| 1439 |
'menu_slug' => 'wpjam-bind', |
| 1440 |
'menu_title' => '账号绑定', |
| 1441 |
'order' => 20, |
| 1442 |
'capability' => 'read', |
| 1443 |
'function' => 'tab', |
| 1444 |
'tabs' => $tabs |
| 1445 |
]); |
| 1446 |
|
| 1447 |
$objects && wpjam_add_admin_load([ |
| 1448 |
'base' => 'users', |
| 1449 |
'callback' => fn()=> wpjam_register_list_table_column('openid', [ |
| 1450 |
'title' => '绑定账号', |
| 1451 |
'order' => 20, |
| 1452 |
'callback' => fn($user_id)=> wpjam_join('<br /><br />', wpjam_map($objects, fn($v)=> ($openid = $v->get_openid($user_id)) ? $v->title.':<br />'.$openid : '')) |
| 1453 |
]) |
| 1454 |
]); |
| 1455 |
} |
| 1456 |
|
| 1457 |
public static function on_login_init(){ |
| 1458 |
$action = ($_REQUEST['action'] ?? '') ?: 'login'; |
| 1459 |
$type = $_REQUEST[$action.'_type'] ?? ''; |
| 1460 |
|
| 1461 |
if(in_array($action, ['login', 'bind']) && ($objects = self::get_registereds([$action=>true]))){ |
| 1462 |
if($action == 'login'){ |
| 1463 |
$type = $type ?: apply_filters('wpjam_default_login_type', $action); |
| 1464 |
$type = $type ?: ($_SERVER['REQUEST_METHOD'] == 'POST' ? 'login' : array_key_first($objects)); |
| 1465 |
|
| 1466 |
if(isset($objects[$type])){ |
| 1467 |
wpjam_call($objects[$type]->login_action); |
| 1468 |
} |
| 1469 |
|
| 1470 |
if(empty($_COOKIE[TEST_COOKIE])){ |
| 1471 |
$_COOKIE[TEST_COOKIE] = 'WP Cookie check'; |
| 1472 |
} |
| 1473 |
|
| 1474 |
$objects['login'] = '使用账号和密码登录'; |
| 1475 |
}else{ |
| 1476 |
is_user_logged_in() ? wpjam_hook('login_display_language_dropdown', false) : wp_die('登录之后才能执行绑定操作!'); |
| 1477 |
} |
| 1478 |
|
| 1479 |
$type = $type && isset($objects[$type]) ? $type : array_key_first($objects); |
| 1480 |
$tag = wpjam_tag('p', ['class'=>'types', 'data'=>['action'=>$action]])->append(wpjam_map($objects, fn($v, $k)=>['a', [ |
| 1481 |
'class' => $type == $k ? 'current' : '', |
| 1482 |
'data' => ['type'=>$k]+($k == 'login' ? [] : ['action'=>$k.'-signup', 'data'=>['action'=>'get-'.$action]]) |
| 1483 |
], $k == 'login' ? $v : ($action == 'bind' ? '绑定'.$v->title : $v->login_title)])); |
| 1484 |
|
| 1485 |
wp_enqueue_script('wpjam-login', wpjam_url(dirname(__DIR__).'/static/login.js'), ['wpjam-ajax']); |
| 1486 |
|
| 1487 |
wpjam_echo($tag, 'login_form'); |
| 1488 |
} |
| 1489 |
|
| 1490 |
wp_add_inline_style('login', join("\n", [ |
| 1491 |
'.login .message, .login #login_error{margin-bottom: 0;}', |
| 1492 |
'.code_wrap label:last-child{display:flex;}', |
| 1493 |
'.code_wrap input.button{margin-bottom:10px;}', |
| 1494 |
'.login form .input, .login input[type=password], .login input[type=text]{font-size:20px; margin-bottom:10px;}', |
| 1495 |
|
| 1496 |
'p.types{line-height:2; float:left; clear:left; margin-top:10px;}', |
| 1497 |
'p.types a{text-decoration: none; display:block;}', |
| 1498 |
'p.types a.current{display:none;}', |
| 1499 |
'div.fields{margin-bottom:10px;}', |
| 1500 |
])); |
| 1501 |
} |
| 1502 |
|
| 1503 |
public static function add_hooks(){ |
| 1504 |
if(wp_using_ext_object_cache()){ |
| 1505 |
add_action('login_init', [self::class, 'on_login_init']); |
| 1506 |
add_action('wpjam_admin_init', [self::class, 'on_admin_init']); |
| 1507 |
} |
| 1508 |
} |
| 1509 |
} |