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