PluginProbe ʕ •ᴥ•ʔ
Custom Post Type UI / 1.18.1
Custom Post Type UI v1.18.1
1.19.2 1.19.1 1.19.0 trunk 0.7.0.0 0.7.1.0 0.7.2.0 0.8.0.0 0.8.1 0.8.2 0.8.3 0.8.4 0.8.5 0.9.0 0.9.5 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1.0 1.1.1 1.1.2 1.1.3 1.10.0 1.10.1 1.10.2 1.11.0 1.11.1 1.11.2 1.12.0 1.12.1 1.13.0 1.13.1 1.13.2 1.13.3 1.13.4 1.13.5 1.13.6 1.13.7 1.14.0 1.15.0 1.15.1 1.16.0 1.17.0 1.17.1 1.17.2 1.17.3 1.18.0 1.18.1 1.18.2 1.18.3 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.1 1.6.2 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.8.0 1.8.1 1.8.2 1.9.0 1.9.1 1.9.2
custom-post-type-ui / custom-post-type-ui.php
custom-post-type-ui Last commit date
build 6 months ago classes 6 months ago external 6 months ago images 6 months ago inc 6 months ago LICENSE 6 months ago custom-post-type-ui.php 6 months ago readme.txt 6 months ago wordfence-vendor.txt 6 months ago wpml-config.xml 6 months ago
custom-post-type-ui.php
1132 lines
1 <?php
2 /**
3 * Custom Post Type UI.
4 *
5 * For all your post type and taxonomy needs.
6 *
7 * @package CPTUI
8 * @subpackage Loader
9 * @author WebDevStudios
10 * @since 0.1.0.0
11 * @license GPL-2.0+
12 */
13
14 /**
15 * Plugin Name: Custom Post Type UI
16 * Plugin URI: https://github.com/WebDevStudios/custom-post-type-ui/
17 * Description: Admin UI panel for registering custom post types and taxonomies
18 * Author: WebDevStudios
19 * Version: 1.18.1
20 * Author URI: https://webdevstudios.com/
21 * Text Domain: custom-post-type-ui
22 * Domain Path: /languages
23 * License: GPL-2.0+
24 * Requires at least: 6.6
25 * Requires PHP: 7.4
26 */
27
28 // phpcs:disable WebDevStudios.All.RequireAuthor
29 // phpcs:set WordPress.WP.I18n check_translator_comments false
30
31 // Exit if accessed directly.
32 if ( ! defined( 'ABSPATH' ) ) {
33 exit;
34 }
35
36 define( 'CPT_VERSION', '1.18.1' ); // Left for legacy purposes.
37 define( 'CPTUI_VERSION', '1.18.1' );
38 define( 'CPTUI_WP_VERSION', get_bloginfo( 'version' ) );
39
40 /**
41 * Load our Admin UI class that powers our form inputs.
42 *
43 * @since 1.0.0
44 *
45 * @internal
46 */
47 function cptui_load_ui_class() {
48 require_once plugin_dir_path( __FILE__ ) . 'classes/class.cptui_admin_ui.php';
49 require_once plugin_dir_path( __FILE__ ) . 'classes/class.cptui_debug_info.php';
50 }
51 add_action( 'init', 'cptui_load_ui_class' );
52
53 /**
54 * Set a transient used for redirection upon activation.
55 *
56 * @since 1.4.0
57 */
58 function cptui_activation_redirect() {
59 // Bail if activating from network, or bulk.
60 if ( is_network_admin() ) {
61 return;
62 }
63
64 // Add the transient to redirect.
65 set_transient( 'cptui_activation_redirect', true, 30 );
66 }
67 add_action( 'activate_' . plugin_basename( __FILE__ ), 'cptui_activation_redirect' );
68
69 /**
70 * Redirect user to CPTUI about page upon plugin activation.
71 *
72 * @since 1.4.0
73 */
74 function cptui_make_activation_redirect() {
75
76 if ( ! get_transient( 'cptui_activation_redirect' ) ) {
77 return;
78 }
79
80 delete_transient( 'cptui_activation_redirect' );
81
82 // Bail if activating from network, or bulk.
83 if ( is_network_admin() ) {
84 return;
85 }
86
87 if ( ! cptui_is_new_install() ) {
88 return;
89 }
90
91 // Redirect to CPTUI about page.
92 wp_safe_redirect(
93 add_query_arg(
94 [ 'page' => 'cptui_main_menu' ],
95 cptui_admin_url( 'admin.php?page=cptui_main_menu' )
96 )
97 );
98 }
99 add_action( 'admin_init', 'cptui_make_activation_redirect', 1 );
100
101 /**
102 * Flush our rewrite rules on deactivation.
103 *
104 * @since 0.8.0
105 *
106 * @internal
107 */
108 function cptui_deactivation() {
109 flush_rewrite_rules();
110 }
111 register_deactivation_hook( __FILE__, 'cptui_deactivation' );
112
113 /**
114 * Register our text domain.
115 *
116 * @since 0.8.0
117 *
118 * @internal
119 */
120 function cptui_load_textdomain() {
121 load_plugin_textdomain( 'custom-post-type-ui' );
122 }
123 add_action( 'init', 'cptui_load_textdomain' );
124
125 /**
126 * Load our main menu.
127 *
128 * Submenu items added in version 1.1.0
129 *
130 * @since 0.1.0
131 *
132 * @internal
133 */
134 function cptui_plugin_menu() {
135
136 /**
137 * Filters the required capability to manage CPTUI settings.
138 *
139 * @since 1.3.0
140 *
141 * @param string $value Capability required.
142 */
143 $capability = apply_filters( 'cptui_required_capabilities', 'manage_options' );
144 $parent_slug = 'cptui_main_menu';
145
146 add_menu_page( esc_html__( 'Custom Post Types', 'custom-post-type-ui' ), esc_html__( 'CPT UI', 'custom-post-type-ui' ), $capability, $parent_slug, 'cptui_settings', cptui_menu_icon() );
147 add_submenu_page( $parent_slug, esc_html__( 'Add/Edit Post Types', 'custom-post-type-ui' ), esc_html__( 'Add/Edit Post Types', 'custom-post-type-ui' ), $capability, 'cptui_manage_post_types', 'cptui_manage_post_types' );
148 add_submenu_page( $parent_slug, esc_html__( 'Add/Edit Taxonomies', 'custom-post-type-ui' ), esc_html__( 'Add/Edit Taxonomies', 'custom-post-type-ui' ), $capability, 'cptui_manage_taxonomies', 'cptui_manage_taxonomies' );
149 add_submenu_page( $parent_slug, esc_html__( 'Registered Types and Taxes', 'custom-post-type-ui' ), esc_html__( 'Registered Types/Taxes', 'custom-post-type-ui' ), $capability, 'cptui_listings', 'cptui_listings' );
150 add_submenu_page( $parent_slug, esc_html__( 'Custom Post Type UI Tools', 'custom-post-type-ui' ), esc_html__( 'Tools', 'custom-post-type-ui' ), $capability, 'cptui_tools', 'cptui_tools' );
151 add_submenu_page( $parent_slug, esc_html__( 'Help/Support', 'custom-post-type-ui' ), esc_html__( 'Help/Support', 'custom-post-type-ui' ), $capability, 'cptui_support', 'cptui_support' );
152
153 /**
154 * Fires after the default submenu pages.
155 *
156 * @since 1.3.0
157 *
158 * @param string $value Parent slug for Custom Post Type UI menu.
159 * @param string $capability Capability required to manage CPTUI settings.
160 */
161 do_action( 'cptui_extra_menu_items', $parent_slug, $capability );
162
163 // Remove the default one so we can add our customized version.
164 remove_submenu_page( $parent_slug, 'cptui_main_menu' );
165 add_submenu_page( $parent_slug, esc_html__( 'About CPT UI', 'custom-post-type-ui' ), esc_html__( 'About CPT UI', 'custom-post-type-ui' ), $capability, 'cptui_main_menu', 'cptui_settings' );
166 }
167 add_action( 'admin_menu', 'cptui_plugin_menu' );
168
169 /**
170 * Fire our CPTUI Loaded hook.
171 *
172 * @since 1.3.0
173 *
174 * @internal Use `cptui_loaded` hook.
175 */
176 function cptui_loaded() {
177
178 if ( class_exists( 'WPGraphQL' ) ) {
179 require_once plugin_dir_path( __FILE__ ) . 'external/wpgraphql.php';
180 }
181
182 /**
183 * Fires upon plugins_loaded WordPress hook.
184 *
185 * CPTUI loads its required files on this hook.
186 *
187 * @since 1.3.0
188 */
189 do_action( 'cptui_loaded' );
190 }
191 add_action( 'plugins_loaded', 'cptui_loaded' );
192
193 /**
194 * Load our submenus.
195 *
196 * @since 1.0.0
197 *
198 * @internal
199 */
200 function cptui_includes() {
201 require_once plugin_dir_path( __FILE__ ) . 'inc/about.php';
202 require_once plugin_dir_path( __FILE__ ) . 'inc/utility.php';
203 require_once plugin_dir_path( __FILE__ ) . 'inc/post-types.php';
204 require_once plugin_dir_path( __FILE__ ) . 'inc/taxonomies.php';
205 require_once plugin_dir_path( __FILE__ ) . 'inc/listings.php';
206 require_once plugin_dir_path( __FILE__ ) . 'inc/tools.php';
207 require_once plugin_dir_path( __FILE__ ) . 'inc/tools-sections/tools-post-types.php';
208 require_once plugin_dir_path( __FILE__ ) . 'inc/tools-sections/tools-taxonomies.php';
209 require_once plugin_dir_path( __FILE__ ) . 'inc/tools-sections/tools-get-code.php';
210 require_once plugin_dir_path( __FILE__ ) . 'inc/tools-sections/tools-debug.php';
211 require_once plugin_dir_path( __FILE__ ) . 'inc/support.php';
212
213 if ( defined( 'WP_CLI' ) && WP_CLI ) {
214 require_once plugin_dir_path( __FILE__ ) . 'inc/wp-cli.php';
215 }
216 }
217 add_action( 'cptui_loaded', 'cptui_includes' );
218
219 /**
220 * Fire our CPTUI init hook.
221 *
222 * @since 1.3.0
223 *
224 * @internal Use `cptui_init` hook.
225 */
226 function cptui_init() {
227
228 /**
229 * Fires upon init WordPress hook.
230 *
231 * @since 1.3.0
232 */
233 do_action( 'cptui_init' );
234 }
235 add_action( 'init', 'cptui_init' );
236
237 /**
238 * Enqueue CPTUI admin styles.
239 *
240 * @since 1.0.0
241 *
242 * @internal
243 */
244 function cptui_add_styles() {
245 if ( wp_doing_ajax() ) {
246 return;
247 }
248 $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
249 wp_register_script( 'cptui', plugins_url( "build/cptui$min.js", __FILE__ ), [ 'jquery', 'jquery-ui-dialog', 'postbox' ], CPTUI_VERSION, true );
250 wp_register_script( 'dashicons-picker', plugins_url( "build/dashiconsPicker$min.js", __FILE__ ), [ 'jquery'], '1.0.0', true );
251 wp_register_style( 'cptui-css', plugins_url( "build/cptui-styles$min.css", __FILE__ ), [ 'wp-jquery-ui-dialog' ], CPTUI_VERSION );
252 }
253 add_action( 'admin_enqueue_scripts', 'cptui_add_styles' );
254
255 /**
256 * Register our users' custom post types.
257 *
258 * @since 0.5.0
259 *
260 * @internal
261 */
262 function cptui_create_custom_post_types() {
263 $cpts = get_option( 'cptui_post_types', [] );
264 /**
265 * Filters an override array of post type data to be registered instead of our saved option.
266 *
267 * @since 1.10.0
268 *
269 * @param array $value Default override value.
270 */
271 $cpts_override = apply_filters( 'cptui_post_types_override', [] );
272
273 if ( empty( $cpts ) && empty( $cpts_override ) ) {
274 return;
275 }
276
277 // Assume good intent, and we're also not wrecking the option so things are always reversable.
278 if ( is_array( $cpts_override ) && ! empty( $cpts_override ) ) {
279 $cpts = $cpts_override;
280 }
281
282 /**
283 * Fires before the start of the post type registrations.
284 *
285 * @since 1.3.0
286 *
287 * @param array $cpts Array of post types to register.
288 */
289 do_action( 'cptui_pre_register_post_types', $cpts );
290
291 if ( is_array( $cpts ) ) {
292 foreach ( $cpts as $post_type ) {
293
294 if ( ! is_string( $post_type['name'] ) ) {
295 $post_type['name'] = (string) $post_type['name'];
296 }
297 /**
298 * Filters whether or not to skip registration of the current iterated post type.
299 *
300 * Dynamic part of the filter name is the chosen post type slug.
301 *
302 * @since 1.7.0
303 *
304 * @param bool $value Whether or not to skip the post type.
305 * @param array $post_type Current post type being registered.
306 */
307 if ( (bool) apply_filters( "cptui_disable_{$post_type['name']}_cpt", false, $post_type ) ) {
308 continue;
309 }
310
311 /**
312 * Filters whether or not to skip registration of the current iterated post type.
313 *
314 * @since 1.7.0
315 *
316 * @param bool $value Whether or not to skip the post type.
317 * @param array $post_type Current post type being registered.
318 */
319 if ( (bool) apply_filters( 'cptui_disable_cpt', false, $post_type ) ) {
320 continue;
321 }
322
323 cptui_register_single_post_type( $post_type );
324 }
325 }
326
327 /**
328 * Fires after the completion of the post type registrations.
329 *
330 * @since 1.3.0
331 *
332 * @param array $cpts Array of post types registered.
333 */
334 do_action( 'cptui_post_register_post_types', $cpts );
335 }
336 add_action( 'init', 'cptui_create_custom_post_types' ); // Leave on standard init for legacy purposes.
337
338 /**
339 * Helper function to register the actual post_type.
340 *
341 * @since 1.0.0
342 *
343 * @internal
344 *
345 * @param array $post_type Post type array to register. Optional.
346 * @return null Result of register_post_type.
347 */
348 function cptui_register_single_post_type( array $post_type = [] ) {
349
350 /**
351 * Filters the map_meta_cap value.
352 *
353 * @since 1.0.0
354 *
355 * @param bool $value True.
356 * @param string $name Post type name being registered.
357 * @param array $post_type All parameters for post type registration.
358 */
359 $post_type['map_meta_cap'] = apply_filters( 'cptui_map_meta_cap', true, $post_type['name'], $post_type );
360
361 if ( empty( $post_type['supports'] ) ) {
362 $post_type['supports'] = [];
363 }
364
365 /**
366 * Filters custom supports parameters for 3rd party plugins.
367 *
368 * @since 1.0.0
369 *
370 * @param array $value Empty array to add supports keys to.
371 * @param string $name Post type slug being registered.
372 * @param array $post_type Array of post type arguments to be registered.
373 */
374 $user_supports_params = apply_filters( 'cptui_user_supports_params', [], $post_type['name'], $post_type );
375
376 if ( is_array( $user_supports_params ) && ! empty( $user_supports_params ) ) {
377 if ( is_array( $post_type['supports'] ) ) {
378 $post_type['supports'] = array_merge( $post_type['supports'], $user_supports_params );
379 } else {
380 $post_type['supports'] = [ $user_supports_params ];
381 }
382 }
383
384 $yarpp = false; // Prevent notices.
385 if ( ! empty( $post_type['custom_supports'] ) ) {
386 $custom = explode( ',', $post_type['custom_supports'] );
387 foreach ( $custom as $part ) {
388 // We'll handle YARPP separately.
389 if ( in_array( $part, [ 'YARPP', 'yarpp' ], true ) ) {
390 $yarpp = true;
391 continue;
392 }
393 $post_type['supports'][] = trim( $part );
394 }
395 }
396
397 if ( isset( $post_type['supports'] ) && is_array( $post_type['supports'] ) && in_array( 'none', $post_type['supports'], true ) ) {
398 $post_type['supports'] = false;
399 }
400
401 $labels = [
402 'name' => $post_type['label'],
403 'singular_name' => $post_type['singular_label'],
404 ];
405
406 $preserved = cptui_get_preserved_keys( 'post_types' );
407 $preserved_labels = cptui_get_preserved_labels();
408 foreach ( $post_type['labels'] as $key => $label ) {
409
410 if ( ! empty( $label ) ) {
411 if ( 'parent' === $key ) {
412 $labels['parent_item_colon'] = $label;
413 } else {
414 $labels[ $key ] = $label;
415 }
416 } elseif ( empty( $label ) && in_array( $key, $preserved, true ) ) {
417 $singular_or_plural = ( in_array( $key, array_keys( $preserved_labels['post_types']['plural'] ) ) ) ? 'plural' : 'singular'; // phpcs:ignore.
418 $label_plurality = ( 'plural' === $singular_or_plural ) ? $post_type['label'] : $post_type['singular_label'];
419 $labels[ $key ] = sprintf( $preserved_labels['post_types'][ $singular_or_plural ][ $key ], $label_plurality );
420 }
421 }
422
423 $has_archive = isset( $post_type['has_archive'] ) ? get_disp_boolean( $post_type['has_archive'] ) : false;
424 if ( $has_archive && ! empty( $post_type['has_archive_string'] ) ) {
425 $has_archive = $post_type['has_archive_string'];
426 }
427
428 $show_in_menu = get_disp_boolean( $post_type['show_in_menu'] );
429 if ( ! empty( $post_type['show_in_menu_string'] ) ) {
430 $show_in_menu = $post_type['show_in_menu_string'];
431 }
432
433 $rewrite = get_disp_boolean( $post_type['rewrite'] );
434 if ( false !== $rewrite ) {
435 // Core converts to an empty array anyway, so safe to leave this instead of passing in boolean true.
436 $rewrite = [];
437 $rewrite['slug'] = ! empty( $post_type['rewrite_slug'] ) ? $post_type['rewrite_slug'] : $post_type['name'];
438
439 $rewrite['with_front'] = true; // Default value.
440 if ( isset( $post_type['rewrite_withfront'] ) ) {
441 $rewrite['with_front'] = 'false' === disp_boolean( $post_type['rewrite_withfront'] ) ? false : true;
442 }
443 }
444
445 $menu_icon = ! empty( $post_type['menu_icon'] ) ? $post_type['menu_icon'] : null;
446 $register_meta_box_cb = ! empty( $post_type['register_meta_box_cb'] ) ? $post_type['register_meta_box_cb'] : null;
447
448 if ( in_array( $post_type['query_var'], [ 'true', 'false', '0', '1' ], true ) ) {
449 $post_type['query_var'] = get_disp_boolean( $post_type['query_var'] );
450 }
451 if ( ! empty( $post_type['query_var_slug'] ) ) {
452 $post_type['query_var'] = $post_type['query_var_slug'];
453 }
454
455 $menu_position = null;
456 if ( ! empty( $post_type['menu_position'] ) ) {
457 $menu_position = (int) $post_type['menu_position'];
458 }
459
460 $delete_with_user = null;
461 if ( ! empty( $post_type['delete_with_user'] ) ) {
462 $delete_with_user = get_disp_boolean( $post_type['delete_with_user'] );
463 }
464
465 $capability_type = 'post';
466 if ( ! empty( $post_type['capability_type'] ) ) {
467 $capability_type = $post_type['capability_type'];
468 if ( false !== strpos( $post_type['capability_type'], ',' ) ) {
469 $caps = array_map( 'trim', explode( ',', $post_type['capability_type'] ) );
470 if ( count( $caps ) > 2 ) {
471 $caps = array_slice( $caps, 0, 2 );
472 }
473 $capability_type = $caps;
474 }
475 }
476
477 $public = get_disp_boolean( $post_type['public'] );
478 if ( ! empty( $post_type['exclude_from_search'] ) ) {
479 $exclude_from_search = get_disp_boolean( $post_type['exclude_from_search'] );
480 } else {
481 $exclude_from_search = false === $public;
482 }
483
484 $queryable = ( ! empty( $post_type['publicly_queryable'] ) && isset( $post_type['publicly_queryable'] ) ) ? get_disp_boolean( $post_type['publicly_queryable'] ) : $public;
485
486 if ( empty( $post_type['show_in_nav_menus'] ) ) {
487 // Defaults to value of public.
488 $post_type['show_in_nav_menus'] = $public;
489 }
490
491 if ( empty( $post_type['show_in_rest'] ) ) {
492 $post_type['show_in_rest'] = false;
493 }
494
495 $rest_base = null;
496 if ( ! empty( $post_type['rest_base'] ) ) {
497 $rest_base = $post_type['rest_base'];
498 }
499
500 $rest_controller_class = null;
501 if ( ! empty( $post_type['rest_controller_class'] ) ) {
502 $rest_controller_class = $post_type['rest_controller_class'];
503 }
504
505 $rest_namespace = null;
506 if ( ! empty( $post_type['rest_namespace'] ) ) {
507 $rest_namespace = $post_type['rest_namespace'];
508 }
509
510 $can_export = null;
511 if ( ! empty( $post_type['can_export'] ) ) {
512 $can_export = get_disp_boolean( $post_type['can_export'] );
513 }
514
515 $args = [
516 'labels' => $labels,
517 'description' => $post_type['description'],
518 'public' => get_disp_boolean( $post_type['public'] ),
519 'publicly_queryable' => $queryable,
520 'show_ui' => get_disp_boolean( $post_type['show_ui'] ),
521 'show_in_nav_menus' => get_disp_boolean( $post_type['show_in_nav_menus'] ),
522 'has_archive' => $has_archive,
523 'show_in_menu' => $show_in_menu,
524 'delete_with_user' => $delete_with_user,
525 'show_in_rest' => get_disp_boolean( $post_type['show_in_rest'] ),
526 'rest_base' => $rest_base,
527 'rest_controller_class' => $rest_controller_class,
528 'rest_namespace' => $rest_namespace,
529 'exclude_from_search' => $exclude_from_search,
530 'capability_type' => $capability_type,
531 'map_meta_cap' => $post_type['map_meta_cap'],
532 'hierarchical' => get_disp_boolean( $post_type['hierarchical'] ),
533 'can_export' => $can_export,
534 'rewrite' => $rewrite,
535 'menu_position' => $menu_position,
536 'menu_icon' => $menu_icon,
537 'register_meta_box_cb' => $register_meta_box_cb,
538 'query_var' => $post_type['query_var'],
539 'supports' => $post_type['supports'],
540 'taxonomies' => $post_type['taxonomies'],
541 ];
542
543 if ( true === $yarpp ) {
544 $args['yarpp_support'] = $yarpp;
545 }
546
547 /**
548 * Filters the arguments used for a post type right before registering.
549 *
550 * @since 1.0.0
551 * @since 1.3.0 Added original passed in values array
552 *
553 * @param array $args Array of arguments to use for registering post type.
554 * @param string $value Post type slug to be registered.
555 * @param array $post_type Original passed in values for post type.
556 */
557 $args = apply_filters( 'cptui_pre_register_post_type', $args, $post_type['name'], $post_type );
558
559 return register_post_type( $post_type['name'], $args );
560 }
561
562 /**
563 * Register our users' custom taxonomies.
564 *
565 * @since 0.5.0
566 *
567 * @internal
568 */
569 function cptui_create_custom_taxonomies() {
570 $taxes = get_option( 'cptui_taxonomies', [] );
571 /**
572 * Filters an override array of taxonomy data to be registered instead of our saved option.
573 *
574 * @since 1.10.0
575 *
576 * @param array $value Default override value.
577 */
578 $taxes_override = apply_filters( 'cptui_taxonomies_override', [] );
579
580 if ( empty( $taxes ) && empty( $taxes_override ) ) {
581 return;
582 }
583
584 // Assume good intent, and we're also not wrecking the option so things are always reversable.
585 if ( is_array( $taxes_override ) && ! empty( $taxes_override ) ) {
586 $taxes = $taxes_override;
587 }
588
589 /**
590 * Fires before the start of the taxonomy registrations.
591 *
592 * @since 1.3.0
593 *
594 * @param array $taxes Array of taxonomies to register.
595 */
596 do_action( 'cptui_pre_register_taxonomies', $taxes );
597
598 if ( is_array( $taxes ) ) {
599 foreach ( $taxes as $tax ) {
600
601 if ( ! is_string( $tax['name'] ) ) {
602 $tax['name'] = (string) $tax['name'];
603 }
604 /**
605 * Filters whether or not to skip registration of the current iterated taxonomy.
606 *
607 * Dynamic part of the filter name is the chosen taxonomy slug.
608 *
609 * @since 1.7.0
610 *
611 * @param bool $value Whether or not to skip the taxonomy.
612 * @param array $tax Current taxonomy being registered.
613 */
614 if ( (bool) apply_filters( "cptui_disable_{$tax['name']}_tax", false, $tax ) ) {
615 continue;
616 }
617
618 /**
619 * Filters whether or not to skip registration of the current iterated taxonomy.
620 *
621 * @since 1.7.0
622 *
623 * @param bool $value Whether or not to skip the taxonomy.
624 * @param array $tax Current taxonomy being registered.
625 */
626 if ( (bool) apply_filters( 'cptui_disable_tax', false, $tax ) ) {
627 continue;
628 }
629
630 cptui_register_single_taxonomy( $tax );
631 }
632 }
633
634 /**
635 * Fires after the completion of the taxonomy registrations.
636 *
637 * @since 1.3.0
638 *
639 * @param array $taxes Array of taxonomies registered.
640 */
641 do_action( 'cptui_post_register_taxonomies', $taxes );
642 }
643 add_action( 'init', 'cptui_create_custom_taxonomies', 9 ); // Leave on standard init for legacy purposes.
644
645 /**
646 * Helper function to register the actual taxonomy.
647 *
648 * @since 1.0.0
649 *
650 * @internal
651 *
652 * @param array $taxonomy Taxonomy array to register. Optional.
653 * @return null Result of register_taxonomy.
654 */
655 function cptui_register_single_taxonomy( array $taxonomy = [] ) {
656
657 $labels = [
658 'name' => $taxonomy['label'],
659 'singular_name' => $taxonomy['singular_label'],
660 ];
661
662 $description = '';
663 if ( ! empty( $taxonomy['description'] ) ) {
664 $description = $taxonomy['description'];
665 }
666
667 $preserved = cptui_get_preserved_keys( 'taxonomies' );
668 $preserved_labels = cptui_get_preserved_labels();
669 foreach ( $taxonomy['labels'] as $key => $label ) {
670
671 if ( ! empty( $label ) ) {
672 $labels[ $key ] = $label;
673 } elseif ( in_array( $key, $preserved, true ) ) {
674 $singular_or_plural = ( in_array( $key, array_keys( $preserved_labels['taxonomies']['plural'] ) ) ) ? 'plural' : 'singular'; // phpcs:ignore.
675 $label_plurality = ( 'plural' === $singular_or_plural ) ? $taxonomy['label'] : $taxonomy['singular_label'];
676 $labels[ $key ] = sprintf( $preserved_labels['taxonomies'][ $singular_or_plural ][ $key ], $label_plurality );
677 }
678 }
679
680 $rewrite = get_disp_boolean( $taxonomy['rewrite'] );
681 if ( false !== get_disp_boolean( $taxonomy['rewrite'] ) ) {
682 $rewrite = [];
683 $rewrite['slug'] = ! empty( $taxonomy['rewrite_slug'] ) ? $taxonomy['rewrite_slug'] : $taxonomy['name'];
684 $rewrite['with_front'] = true;
685 if ( isset( $taxonomy['rewrite_withfront'] ) ) {
686 $rewrite['with_front'] = ( 'false' === disp_boolean( $taxonomy['rewrite_withfront'] ) ) ? false : true;
687 }
688 $rewrite['hierarchical'] = false;
689 if ( isset( $taxonomy['rewrite_hierarchical'] ) ) {
690 $rewrite['hierarchical'] = ( 'true' === disp_boolean( $taxonomy['rewrite_hierarchical'] ) ) ? true : false;
691 }
692 }
693
694 if ( in_array( $taxonomy['query_var'], [ 'true', 'false', '0', '1' ], true ) ) {
695 $taxonomy['query_var'] = get_disp_boolean( $taxonomy['query_var'] );
696 }
697 if ( true === $taxonomy['query_var'] && ! empty( $taxonomy['query_var_slug'] ) ) {
698 $taxonomy['query_var'] = $taxonomy['query_var_slug'];
699 }
700
701 $public = ( ! empty( $taxonomy['public'] ) && false === get_disp_boolean( $taxonomy['public'] ) ) ? false : true;
702 $publicly_queryable = ( ! empty( $taxonomy['publicly_queryable'] ) && false === get_disp_boolean( $taxonomy['publicly_queryable'] ) ) ? false : true;
703 if ( empty( $taxonomy['publicly_queryable'] ) ) {
704 $publicly_queryable = $public;
705 }
706
707 $show_admin_column = ( ! empty( $taxonomy['show_admin_column'] ) && false !== get_disp_boolean( $taxonomy['show_admin_column'] ) ) ? true : false;
708
709 $show_in_menu = ( ! empty( $taxonomy['show_in_menu'] ) && false !== get_disp_boolean( $taxonomy['show_in_menu'] ) ) ? true : false;
710
711 if ( empty( $taxonomy['show_in_menu'] ) ) {
712 $show_in_menu = get_disp_boolean( $taxonomy['show_ui'] );
713 }
714
715 $show_in_nav_menus = ( ! empty( $taxonomy['show_in_nav_menus'] ) && false !== get_disp_boolean( $taxonomy['show_in_nav_menus'] ) ) ? true : false;
716 if ( empty( $taxonomy['show_in_nav_menus'] ) ) {
717 $show_in_nav_menus = $public;
718 }
719
720 $show_tagcloud = ( ! empty( $taxonomy['show_tagcloud'] ) && false !== get_disp_boolean( $taxonomy['show_tagcloud'] ) ) ? true : false;
721 if ( empty( $taxonomy['show_tagcloud'] ) ) {
722 $show_tagcloud = get_disp_boolean( $taxonomy['show_ui'] );
723 }
724
725 $show_in_rest = ( ! empty( $taxonomy['show_in_rest'] ) && false !== get_disp_boolean( $taxonomy['show_in_rest'] ) ) ? true : false;
726
727 $show_in_quick_edit = ( ! empty( $taxonomy['show_in_quick_edit'] ) && false !== get_disp_boolean( $taxonomy['show_in_quick_edit'] ) ) ? true : false;
728
729 $sort = ( ! empty( $taxonomy['sort'] ) && false !== get_disp_boolean( $taxonomy['sort'] ) ) ? true : false;
730
731 $rest_base = null;
732 if ( ! empty( $taxonomy['rest_base'] ) ) {
733 $rest_base = $taxonomy['rest_base'];
734 }
735
736 $rest_controller_class = null;
737 if ( ! empty( $taxonomy['rest_controller_class'] ) ) {
738 $rest_controller_class = $taxonomy['rest_controller_class'];
739 }
740
741 $rest_namespace = null;
742 if ( ! empty( $taxonomy['rest_namespace'] ) ) {
743 $rest_namespace = $taxonomy['rest_namespace'];
744 }
745
746 $meta_box_cb = null;
747 if ( ! empty( $taxonomy['meta_box_cb'] ) ) {
748 $meta_box_cb = ( false !== get_disp_boolean( $taxonomy['meta_box_cb'] ) ) ? $taxonomy['meta_box_cb'] : false;
749 }
750 $default_term = null;
751 if ( ! empty( $taxonomy['default_term'] ) ) {
752 $term_parts = explode( ',', $taxonomy['default_term'] );
753 if ( ! empty( $term_parts[0] ) ) {
754 $default_term['name'] = trim( $term_parts[0] );
755 }
756 if ( ! empty( $term_parts[1] ) ) {
757 $default_term['slug'] = trim( $term_parts[1] );
758 }
759 if ( ! empty( $term_parts[2] ) ) {
760 $default_term['description'] = trim( $term_parts[2] );
761 }
762 }
763
764 $args = [
765 'labels' => $labels,
766 'label' => $taxonomy['label'],
767 'description' => $description,
768 'public' => $public,
769 'publicly_queryable' => $publicly_queryable,
770 'hierarchical' => get_disp_boolean( $taxonomy['hierarchical'] ),
771 'show_ui' => get_disp_boolean( $taxonomy['show_ui'] ),
772 'show_in_menu' => $show_in_menu,
773 'show_in_nav_menus' => $show_in_nav_menus,
774 'show_tagcloud' => $show_tagcloud,
775 'query_var' => $taxonomy['query_var'],
776 'rewrite' => $rewrite,
777 'show_admin_column' => $show_admin_column,
778 'show_in_rest' => $show_in_rest,
779 'rest_base' => $rest_base,
780 'rest_controller_class' => $rest_controller_class,
781 'rest_namespace' => $rest_namespace,
782 'show_in_quick_edit' => $show_in_quick_edit,
783 'sort' => $sort,
784 'meta_box_cb' => $meta_box_cb,
785 'default_term' => $default_term,
786 ];
787
788 $object_type = ! empty( $taxonomy['object_types'] ) ? $taxonomy['object_types'] : '';
789
790 /**
791 * Filters the arguments used for a taxonomy right before registering.
792 *
793 * @since 1.0.0
794 * @since 1.3.0 Added original passed in values array
795 * @since 1.6.0 Added $obect_type variable to passed parameters.
796 *
797 * @param array $args Array of arguments to use for registering taxonomy.
798 * @param string $value Taxonomy slug to be registered.
799 * @param array $taxonomy Original passed in values for taxonomy.
800 * @param array $object_type Array of chosen post types for the taxonomy.
801 */
802 $args = apply_filters( 'cptui_pre_register_taxonomy', $args, $taxonomy['name'], $taxonomy, $object_type );
803
804 return register_taxonomy( $taxonomy['name'], $object_type, $args );
805 }
806
807 /**
808 * Construct and output tab navigation.
809 *
810 * @since 1.0.0
811 *
812 * @param string $page Whether it's the CPT or Taxonomy page. Optional. Default "post_types".
813 * @return string
814 */
815 function cptui_settings_tab_menu( string $page = 'post_types' ) {
816
817 /**
818 * Filters the tabs to render on a given page.
819 *
820 * @since 1.3.0
821 *
822 * @param array $value Array of tabs to render.
823 * @param string $page Current page being displayed.
824 */
825 $tabs = (array) apply_filters( 'cptui_get_tabs', [], $page );
826
827 if ( empty( $tabs['page_title'] ) ) {
828 return '';
829 }
830
831 $tmpl = '<h1>%s</h1><nav class="nav-tab-wrapper wp-clearfix" aria-label="%s">%s</nav>';
832
833 $tab_output = '';
834 foreach ( $tabs['tabs'] as $tab ) {
835 $tab_output .= sprintf(
836 '<a class="%s" href="%s" aria-selected="%s">%s</a>',
837 implode( ' ', $tab['classes'] ),
838 $tab['url'],
839 $tab['aria-selected'],
840 $tab['text']
841 );
842 }
843
844 printf(
845 $tmpl, // phpcs:ignore.
846 $tabs['page_title'], // phpcs:ignore.
847 esc_attr__( 'Secondary menu', 'custom-post-type-ui' ), // phpcs:ignore
848 $tab_output // phpcs:ignore.
849 );
850 }
851
852 /**
853 * Convert our old settings to the new options keys.
854 *
855 * These are left with standard get_option/update_option function calls for legacy and pending update purposes.
856 *
857 * @since 1.0.0
858 *
859 * @internal
860 *
861 * @return bool Whether or not options were successfully updated.
862 */
863 function cptui_convert_settings() {
864
865 if ( wp_doing_ajax() ) {
866 return false;
867 }
868
869 $retval = '';
870
871 if ( false === get_option( 'cptui_post_types' ) && ( $post_types = get_option( 'cpt_custom_post_types' ) ) ) { // phpcs:ignore.
872
873 $new_post_types = [];
874 foreach ( $post_types as $type ) {
875 $new_post_types[ $type['name'] ] = $type; // This one assigns the # indexes. Named arrays are our friend.
876 $new_post_types[ $type['name'] ]['supports'] = ! empty( $type[0] ) ? $type[0] : []; // Especially for multidimensional arrays.
877 $new_post_types[ $type['name'] ]['taxonomies'] = ! empty( $type[1] ) ? $type[1] : [];
878 $new_post_types[ $type['name'] ]['labels'] = ! empty( $type[2] ) ? $type[2] : [];
879 unset(
880 $new_post_types[ $type['name'] ][0],
881 $new_post_types[ $type['name'] ][1],
882 $new_post_types[ $type['name'] ][2]
883 ); // Remove our previous indexed versions.
884 }
885
886 $retval = update_option( 'cptui_post_types', $new_post_types );
887 }
888
889 if ( false === get_option( 'cptui_taxonomies' ) && ( $taxonomies = get_option( 'cpt_custom_tax_types' ) ) ) { // phpcs:ignore.
890
891 $new_taxonomies = [];
892 foreach ( $taxonomies as $tax ) {
893 $new_taxonomies[ $tax['name'] ] = $tax; // Yep, still our friend.
894 $new_taxonomies[ $tax['name'] ]['labels'] = $tax[0]; // Taxonomies are the only thing with.
895 $new_taxonomies[ $tax['name'] ]['object_types'] = $tax[1]; // "tax" in the name that I like.
896 unset(
897 $new_taxonomies[ $tax['name'] ][0],
898 $new_taxonomies[ $tax['name'] ][1]
899 );
900 }
901
902 $retval = update_option( 'cptui_taxonomies', $new_taxonomies );
903 }
904
905 if ( ! empty( $retval ) ) {
906 flush_rewrite_rules();
907 }
908
909 return $retval;
910 }
911 add_action( 'admin_init', 'cptui_convert_settings' );
912
913 /**
914 * Return a notice based on conditions.
915 *
916 * @since 1.0.0
917 *
918 * @param string $action The type of action that occurred. Optional. Default empty string.
919 * @param string $object_type Whether it's from a post type or taxonomy. Optional. Default empty string.
920 * @param bool $success Whether the action succeeded or not. Optional. Default true.
921 * @param string $custom Custom message if necessary. Optional. Default empty string.
922 * @return bool|string false on no message, else HTML div with our notice message.
923 */
924 function cptui_admin_notices( string $action = '', string $object_type = '', bool $success = true, string $custom = '' ) {
925
926 $class = [];
927 $class[] = $success ? 'updated' : 'error';
928 $class[] = 'notice is-dismissible';
929 $object_type = esc_attr( $object_type );
930
931 $messagewrapstart = '<div id="message" class="' . implode( ' ', $class ) . '"><p>';
932 $message = '';
933
934 $messagewrapend = '</p></div>';
935
936 if ( 'add' === $action ) {
937 if ( $success ) {
938 $message .= sprintf( esc_html__( '%s has been successfully added', 'custom-post-type-ui' ), $object_type );
939 } else {
940 $message .= sprintf( esc_html__( '%s has failed to be added', 'custom-post-type-ui' ), $object_type );
941 }
942 } elseif ( 'update' === $action ) {
943 if ( $success ) {
944 $message .= sprintf( esc_html__( '%s has been successfully updated', 'custom-post-type-ui' ), $object_type );
945 } else {
946 $message .= sprintf( esc_html__( '%s has failed to be updated', 'custom-post-type-ui' ), $object_type );
947 }
948 } elseif ( 'delete' === $action ) {
949 if ( $success ) {
950 $message .= sprintf( esc_html__( '%s has been successfully deleted', 'custom-post-type-ui' ), $object_type );
951 } else {
952 $message .= sprintf( esc_html__( '%s has failed to be deleted', 'custom-post-type-ui' ), $object_type );
953 }
954 } elseif ( 'import' === $action ) {
955 if ( $success ) {
956 $message .= sprintf( esc_html__( '%s has been successfully imported', 'custom-post-type-ui' ), $object_type );
957 } else {
958 $message .= sprintf( esc_html__( '%s has failed to be imported', 'custom-post-type-ui' ), $object_type );
959 }
960 } elseif ( 'error' === $action ) {
961 if ( ! empty( $custom ) ) {
962 $message = $custom;
963 }
964 }
965
966 if ( $message ) {
967
968 /**
969 * Filters the custom admin notice for CPTUI.
970 *
971 * @since 1.0.0
972 *
973 * @param string $value Complete HTML output for notice.
974 * @param string $action Action whose message is being generated.
975 * @param string $message The message to be displayed.
976 * @param string $messagewrapstart Beginning wrap HTML.
977 * @param string $messagewrapend Ending wrap HTML.
978 */
979 return apply_filters( 'cptui_admin_notice', $messagewrapstart . $message . $messagewrapend, $action, $message, $messagewrapstart, $messagewrapend );
980 }
981
982 return false;
983 }
984
985 /**
986 * Return array of keys needing preserved.
987 *
988 * @since 1.0.5
989 *
990 * @param string $type Type to return. Either 'post_types' or 'taxonomies'. Optional. Default empty string.
991 * @return array Array of keys needing preservered for the requested type.
992 */
993 function cptui_get_preserved_keys( string $type = '' ) {
994
995 $preserved_labels = [
996 'post_types' => [
997 'add_new_item',
998 'edit_item',
999 'new_item',
1000 'view_item',
1001 'view_items',
1002 'all_items',
1003 'search_items',
1004 'not_found',
1005 'not_found_in_trash',
1006 ],
1007 'taxonomies' => [
1008 'search_items',
1009 'popular_items',
1010 'all_items',
1011 'parent_item',
1012 'parent_item_colon',
1013 'edit_item',
1014 'update_item',
1015 'add_new_item',
1016 'new_item_name',
1017 'separate_items_with_commas',
1018 'add_or_remove_items',
1019 'choose_from_most_used',
1020 ],
1021 ];
1022 return ! empty( $type ) ? $preserved_labels[ $type ] : [];
1023 }
1024
1025 /**
1026 * Return label for the requested type and label key.
1027 *
1028 * @since 1.0.5
1029 *
1030 * @deprecated
1031 *
1032 * @param string $type Type to return. Either 'post_types' or 'taxonomies'. Optional. Default empty string.
1033 * @param string $key Requested label key. Optional. Default empty string.
1034 * @param string $plural Plural verbiage for the requested label and type. Optional. Default empty string.
1035 * @param string $singular Singular verbiage for the requested label and type. Optional. Default empty string.
1036 * @return string Internationalized default label.
1037 */
1038 function cptui_get_preserved_label( string $type = '', string $key = '', string $plural = '', string $singular = '' ) {
1039
1040 $preserved_labels = [
1041 'post_types' => [
1042 'add_new_item' => sprintf( esc_html__( 'Add new %s', 'custom-post-type-ui' ), $singular ),
1043 'edit_item' => sprintf( esc_html__( 'Edit %s', 'custom-post-type-ui' ), $singular ),
1044 'new_item' => sprintf( esc_html__( 'New %s', 'custom-post-type-ui' ), $singular ),
1045 'view_item' => sprintf( esc_html__( 'View %s', 'custom-post-type-ui' ), $singular ),
1046 'view_items' => sprintf( esc_html__( 'View %s', 'custom-post-type-ui' ), $plural ),
1047 'all_items' => sprintf( esc_html__( 'All %s', 'custom-post-type-ui' ), $plural ),
1048 'search_items' => sprintf( esc_html__( 'Search %s', 'custom-post-type-ui' ), $plural ),
1049 'not_found' => sprintf( esc_html__( 'No %s found.', 'custom-post-type-ui' ), $plural ),
1050 'not_found_in_trash' => sprintf( esc_html__( 'No %s found in trash.', 'custom-post-type-ui' ), $plural ),
1051 ],
1052 'taxonomies' => [
1053 'search_items' => sprintf( esc_html__( 'Search %s', 'custom-post-type-ui' ), $plural ),
1054 'popular_items' => sprintf( esc_html__( 'Popular %s', 'custom-post-type-ui' ), $plural ),
1055 'all_items' => sprintf( esc_html__( 'All %s', 'custom-post-type-ui' ), $plural ),
1056 'parent_item' => sprintf( esc_html__( 'Parent %s', 'custom-post-type-ui' ), $singular ),
1057 'parent_item_colon' => sprintf( esc_html__( 'Parent %s:', 'custom-post-type-ui' ), $singular ),
1058 'edit_item' => sprintf( esc_html__( 'Edit %s', 'custom-post-type-ui' ), $singular ),
1059 'update_item' => sprintf( esc_html__( 'Update %s', 'custom-post-type-ui' ), $singular ),
1060 'add_new_item' => sprintf( esc_html__( 'Add new %s', 'custom-post-type-ui' ), $singular ),
1061 'new_item_name' => sprintf( esc_html__( 'New %s name', 'custom-post-type-ui' ), $singular ),
1062 'separate_items_with_commas' => sprintf( esc_html__( 'Separate %s with commas', 'custom-post-type-ui' ), $plural ),
1063 'add_or_remove_items' => sprintf( esc_html__( 'Add or remove %s', 'custom-post-type-ui' ), $plural ),
1064 'choose_from_most_used' => sprintf( esc_html__( 'Choose from the most used %s', 'custom-post-type-ui' ), $plural ),
1065 ],
1066 ];
1067
1068 return $preserved_labels[ $type ][ $key ];
1069 }
1070
1071 /**
1072 * Returns an array of translated labels, ready for use with sprintf().
1073 *
1074 * Replacement for cptui_get_preserved_label for the sake of performance.
1075 *
1076 * @since 1.6.0
1077 *
1078 * @return array
1079 */
1080 function cptui_get_preserved_labels() {
1081 return [
1082 'post_types' => [
1083 'singular' => [
1084 'add_new_item' => esc_html__( 'Add new %s', 'custom-post-type-ui' ),
1085 'edit_item' => esc_html__( 'Edit %s', 'custom-post-type-ui' ),
1086 'new_item' => esc_html__( 'New %s', 'custom-post-type-ui' ),
1087 'view_item' => esc_html__( 'View %s', 'custom-post-type-ui' ),
1088 'template_name' => esc_html__( 'Single item: %s', 'custom-post-type-ui' ),
1089 ],
1090 'plural' => [
1091 'view_items' => esc_html__( 'View %s', 'custom-post-type-ui' ),
1092 'all_items' => esc_html__( 'All %s', 'custom-post-type-ui' ),
1093 'search_items' => esc_html__( 'Search %s', 'custom-post-type-ui' ),
1094 'not_found' => esc_html__( 'No %s found.', 'custom-post-type-ui' ),
1095 'not_found_in_trash' => esc_html__( 'No %s found in trash.', 'custom-post-type-ui' ),
1096 ],
1097 ],
1098 'taxonomies' => [
1099 'singular' => [
1100 'parent_item' => esc_html__( 'Parent %s', 'custom-post-type-ui' ),
1101 'parent_item_colon' => esc_html__( 'Parent %s:', 'custom-post-type-ui' ),
1102 'edit_item' => esc_html__( 'Edit %s', 'custom-post-type-ui' ),
1103 'update_item' => esc_html__( 'Update %s', 'custom-post-type-ui' ),
1104 'add_new_item' => esc_html__( 'Add new %s', 'custom-post-type-ui' ),
1105 'new_item_name' => esc_html__( 'New %s name', 'custom-post-type-ui' ),
1106 'template_name' => esc_html__( '%s Archives', 'custom-post-type-ui' ),
1107 ],
1108 'plural' => [
1109 'search_items' => esc_html__( 'Search %s', 'custom-post-type-ui' ),
1110 'popular_items' => esc_html__( 'Popular %s', 'custom-post-type-ui' ),
1111 'all_items' => esc_html__( 'All %s', 'custom-post-type-ui' ),
1112 'separate_items_with_commas' => esc_html__( 'Separate %s with commas', 'custom-post-type-ui' ),
1113 'add_or_remove_items' => esc_html__( 'Add or remove %s', 'custom-post-type-ui' ),
1114 'choose_from_most_used' => esc_html__( 'Choose from the most used %s', 'custom-post-type-ui' ),
1115 ],
1116 ],
1117 ];
1118 }
1119
1120
1121 /**
1122 * Add "Back to top" button on admin pages.
1123 *
1124 * @since 1.14.0
1125 */
1126 function cptui_inside_wrap_callback() {
1127 ?>
1128 <a class="button button-secondary cptui-back-to-top" href="#"><?php esc_html_e( 'Back to top', 'custom-post-type-ui' ); ?> &uarr;</a>
1129 <?php
1130 }
1131 add_action( 'cptui_inside_wrap', 'cptui_inside_wrap_callback' );
1132