├── .gitignore
├── .release-please-manifest.json
├── languages
├── types-de_DE.mo
├── types-nl_NL.mo
├── types.pot
├── types-nl_NL.po
└── types-de_DE.po
├── autoload.php
├── release-please-config.json
├── .github
└── workflows
│ └── release.yml
├── composer.json
├── LICENSE.md
├── lib
├── functions.php
├── Post_Type_Page_State.php
├── Post_Type_Query.php
├── Post_Slug.php
├── Post_Type_Page_Option.php
├── Taxonomy.php
├── Post_Type.php
├── Taxonomy_Labels.php
├── Post_Type_Page.php
├── Post_Type_Labels.php
└── Post_Type_Columns.php
├── CHANGELOG.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/.release-please-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | ".": "2.5.8"
3 | }
4 |
--------------------------------------------------------------------------------
/languages/types-de_DE.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindkomm/types/HEAD/languages/types-de_DE.mo
--------------------------------------------------------------------------------
/languages/types-nl_NL.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindkomm/types/HEAD/languages/types-nl_NL.mo
--------------------------------------------------------------------------------
/autoload.php:
--------------------------------------------------------------------------------
1 | =7.0.0"
8 | },
9 | "autoload": {
10 | "psr-4": {
11 | "Types\\": "lib/"
12 | },
13 | "files": [
14 | "autoload.php"
15 | ]
16 | },
17 | "scripts": {
18 | "i18n": "wp i18n make-pot . languages/types.pot --domain=mind/types"
19 | },
20 | "authors": [
21 | {
22 | "name": "Lukas Gaechter",
23 | "email": "lukas.gaechter@mind.ch",
24 | "homepage": "https://www.mind.ch"
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 MIND Kommunikation GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/functions.php:
--------------------------------------------------------------------------------
1 | menu_item_parent ) {
17 | return $menu_items;
18 | }
19 |
20 | foreach ( $menu_items as $item ) {
21 | if ( (int) $item->ID === (int) $child->menu_item_parent ) {
22 | if ( $with_parent ) {
23 | $item->current_item_parent = true;
24 | $item->classes[] = 'current-menu-parent';
25 | }
26 |
27 | $item->current_item_ancestor = true;
28 | $item->classes[] = 'current-menu-ancestor';
29 |
30 | if ( (int) $item->menu_item_parent ) {
31 | $menu_items = menu_items_ancestors( $item, $menu_items, false );
32 | }
33 |
34 | break;
35 | }
36 | }
37 |
38 | return $menu_items;
39 | }
40 |
--------------------------------------------------------------------------------
/lib/Post_Type_Page_State.php:
--------------------------------------------------------------------------------
1 | post_type = $post_type;
30 | $this->option_name = "page_for_{$this->post_type}";
31 | }
32 |
33 | /**
34 | * Inits hooks.
35 | */
36 | public function init() {
37 | if ( ! is_admin() ) {
38 | return;
39 | }
40 |
41 | add_filter( 'display_post_states', [ $this, 'update_post_states' ], 10, 2 );
42 | }
43 |
44 | /**
45 | * Updates post states with page for event.
46 | *
47 | * @param string[] $post_states An array of post display states.
48 | * @param \WP_Post $post The current post object.
49 | *
50 | * @return string[] Updates post states.
51 | */
52 | public function update_post_states( $post_states, $post ) {
53 | $post_type_object = get_post_type_object( $this->post_type );
54 |
55 | if ( 'page' === $post->post_type
56 | && (int) get_option( $this->option_name ) === $post->ID
57 | ) {
58 | $post_states[ $this->option_name ] = sprintf(
59 | /* translators: Post type label. */
60 | __( 'Page for %s', 'mind/types' ),
61 | $post_type_object->label
62 | );
63 | }
64 |
65 | return $post_states;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/Post_Type_Query.php:
--------------------------------------------------------------------------------
1 | post_type = $post_type;
31 | $this->query_args = $this->parse_query_args( $query_args );
32 | }
33 |
34 | /**
35 | * Inits hooks.
36 | */
37 | public function init() {
38 | add_action( 'pre_get_posts', [ $this, 'pre_get_posts' ], 9 );
39 | }
40 |
41 | /**
42 | * Parses the query args.
43 | *
44 | * Returns an associative array with key `frontend` and `backend` that each contain query
45 | * settings.
46 | *
47 | * @since 2.2.0
48 | *
49 | * @param array $args An array of query args.
50 | *
51 | * @return array An array of query args.
52 | */
53 | public function parse_query_args( $args ) {
54 | $query_args = [
55 | 'frontend' => $args,
56 | 'backend' => $args,
57 | ];
58 |
59 | if ( isset( $args['frontend'] ) || isset( $args['backend'] ) ) {
60 | foreach ( [ 'frontend', 'backend' ] as $query_type ) {
61 | $query_args[ $query_type ] = isset( $args[ $query_type ] )
62 | ? $args[ $query_type ]
63 | : [];
64 | }
65 | }
66 |
67 | return $query_args;
68 | }
69 |
70 | /**
71 | * Alters the query.
72 | *
73 | * @param \WP_Query $query A WP_Query object.
74 | */
75 | public function pre_get_posts( $query ) {
76 | global $typenow;
77 |
78 | /**
79 | * Check if we should modify the query.
80 | *
81 | * As a hint for for future condition updates: We can’t use $query->is_post_type_archive(),
82 | * because some post_types have 'has_archive' set to false.
83 | */
84 | if ( ! is_admin() ) {
85 | if (
86 | // Special case for post in a page_for_posts setting.
87 | ( 'post' === $this->post_type && ! $query->is_home() )
88 | // All other post types.
89 | || ( 'post' !== $this->post_type && $this->post_type !== $query->get( 'post_type' ) )
90 | ) {
91 | return;
92 | }
93 | } elseif ( ! $query->is_main_query() || $typenow !== $this->post_type ) {
94 | return;
95 | }
96 |
97 | // Differ between frontend and backend queries.
98 | $query_args = $this->query_args[ is_admin() ? 'backend' : 'frontend' ];
99 |
100 | if ( empty( $query_args ) ) {
101 | return;
102 | }
103 |
104 | /**
105 | * When certain args are explicitly set through a $_GET parameter, then ignore them by
106 | * removing them from the query args. Otherwise, sorting the list table in the admin won’t
107 | * work.
108 | */
109 | if ( is_admin() ) {
110 | foreach( [ 'order', 'orderby' ] as $arg ) {
111 | if ( ! empty( $_GET[ $arg ] ) && isset( $query_args[ $arg ] ) ) {
112 | unset( $query_args[$arg ] );
113 | }
114 | }
115 | }
116 |
117 | // Set query args.
118 | foreach ( $query_args as $key => $arg ) {
119 | $query->set( $key, $arg );
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/Post_Slug.php:
--------------------------------------------------------------------------------
1 | $callback ) {
32 | $this->post_types[ $post_type ] = [
33 | 'callback' => $callback,
34 | ];
35 | }
36 | }
37 |
38 | /**
39 | * Registers date suffixes for post slugs.
40 | *
41 | * @param array $post_types An associative array of post types and their suffix args.
42 | */
43 | public function register_suffix_date( $post_types = [] ) {
44 | foreach ( $post_types as $post_type => $args ) {
45 | $this->post_types[ $post_type ] = [
46 | 'callback' => function( $post_slug, $post_data, $post_id ) use ( $args ) {
47 | $args = wp_parse_args( $args, [
48 | 'meta_key' => 'date_start',
49 | 'input_format' => 'Ymd',
50 | 'output_format' => 'Y-m-d',
51 | ] );
52 |
53 | $meta_value = get_post_meta( $post_id, $args['meta_key'], true );
54 |
55 | if ( ! $meta_value ) {
56 | return $post_slug;
57 | }
58 |
59 | $date = \DateTime::createFromFormat( $args['input_format'], $meta_value );
60 |
61 | if ( $date ) {
62 | $post_slug = $post_data['post_title'] . '-'
63 | . $date->format( $args['output_format'] );
64 | }
65 |
66 | return $post_slug;
67 | },
68 | ];
69 | }
70 | }
71 |
72 | /**
73 | * Customizes the post slug.
74 | *
75 | * @param array $data An array of slashed post data.
76 | * @param array $postarr An array of sanitized, but otherwise unmodified post data.
77 | *
78 | * @return array
79 | */
80 | public function customize_slug( $data, $postarr ) {
81 | $bailout_states = [ 'auto-draft', 'trash' ];
82 | $post_status = $postarr['post_status'];
83 |
84 | // Bailout if it’s not the right state.
85 | if ( in_array( $post_status, $bailout_states, true ) ) {
86 | return $data;
87 | }
88 |
89 | $post_type = $postarr['post_type'];
90 |
91 | // Bailout if no callback could be found.
92 | if ( ! in_array( $post_type, array_keys( $this->post_types ), true )
93 | || ! is_callable( $this->post_types[ $post_type ]['callback'] )
94 | ) {
95 | return $data;
96 | }
97 |
98 | $post_id = $postarr['ID'];
99 | $post_slug = $postarr['post_name'];
100 | $post_parent = $postarr['post_parent'];
101 |
102 | // Filter post slug through user-defined callback.
103 | $post_slug = call_user_func( $this->post_types[ $post_type ]['callback'], $post_slug, $postarr, $post_id );
104 |
105 | // Make sure the post slug is sanitized and unique.
106 | $post_slug = sanitize_title( $post_slug );
107 | $post_slug = wp_unique_post_slug( $post_slug, $post_id, $post_status, $post_type, $post_parent );
108 |
109 | $data['post_name'] = $post_slug;
110 |
111 | return $data;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/lib/Post_Type_Page_Option.php:
--------------------------------------------------------------------------------
1 | post_type = $post_type;
44 | $this->customizer_section = $customizer_section;
45 | $this->option_name = "page_for_{$this->post_type}";
46 | }
47 |
48 | /**
49 | * Inits hooks.
50 | */
51 | public function init() {
52 | if ( ! is_admin() && ! is_customize_preview() ) {
53 | return;
54 | }
55 |
56 | add_action( 'customize_register', [ $this, 'register_settings' ] );
57 |
58 | /**
59 | * Rewrite rules need to be flushed in the next page load after the Custom Post Type was
60 | * registered. That’s why we first need to set a transient that we check on the next admin
61 | * page load.
62 | */
63 | add_action(
64 | "update_option_{$this->option_name}",
65 | [ $this, 'maybe_set_flush_transient' ],
66 | 10, 2
67 | );
68 | add_action( 'admin_init', [ $this, 'maybe_flush_rewrite_rules' ] );
69 | }
70 |
71 | /**
72 | * Adds Customizer setting and control.
73 | *
74 | * @param \WP_Customize_Manager $wp_customize Customizer instance.
75 | */
76 | public function register_settings( WP_Customize_Manager $wp_customize ) {
77 | $post_type_object = get_post_type_object( $this->post_type );
78 |
79 | $wp_customize->add_setting( $this->option_name, [
80 | 'type' => 'option',
81 | ] );
82 |
83 | $wp_customize->add_control( $this->option_name, [
84 | 'label' => sprintf(
85 | /* translators: Post type label. */
86 | __( 'Page for %s', 'mind/types' ),
87 | $post_type_object->label
88 | ),
89 | 'section' => $this->customizer_section,
90 | 'type' => 'dropdown-pages',
91 | 'allow_addition' => true,
92 | ] );
93 | }
94 |
95 | /**
96 | * Sets transient to flush rewrite rules when option value changes.
97 | *
98 | * @param mixed $old_value The old option value.
99 | * @param mixed $value The new option value.
100 | */
101 | public function maybe_set_flush_transient( $old_value, $value ) {
102 | if ( $old_value !== $value ) {
103 | set_transient( "flush_{$this->option_name}", true );
104 | }
105 | }
106 |
107 | /**
108 | * Flushes rewrite rules when transient is set.
109 | */
110 | public function maybe_flush_rewrite_rules() {
111 | $transient_name = "flush_{$this->option_name}";
112 |
113 | if ( get_transient( $transient_name ) ) {
114 | delete_transient( $transient_name );
115 |
116 | add_action( 'shutdown', function() {
117 | flush_rewrite_rules( false );
118 | } );
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/lib/Taxonomy.php:
--------------------------------------------------------------------------------
1 | $args ) {
23 | $args = self::parse_args( $args );
24 | self::register_extensions( $taxonomy, $args );
25 |
26 | $for_post_types = $args['for_post_types'];
27 |
28 | // Defaults for taxonomy registration.
29 | $args = wp_parse_args( $args['args'], [
30 | 'public' => false,
31 | 'hierarchical' => false,
32 | 'show_ui' => true,
33 | 'show_admin_column' => true,
34 | 'show_tag_cloud' => false,
35 | ] );
36 |
37 | register_taxonomy( $taxonomy, $for_post_types, $args );
38 | }
39 | }
40 |
41 | /**
42 | * Updates settings for a taxonomy.
43 | *
44 | * Here, you use the same settings that you also use for the `register()` funciton.
45 | *
46 | * Run this function before the `init` hook.
47 | *
48 | * @see register_taxonomy()
49 | * @since 2.2.0
50 | *
51 | * @param array $taxonomies An associative array of post types and its arguments that should be updated. See the
52 | * `register()` function for all the arguments that you can use.
53 | */
54 | public static function update( $taxonomies = [] ) {
55 | foreach ( $taxonomies as $taxonomy => $args ) {
56 | $args = self::parse_args( $args );
57 | self::register_extensions( $taxonomy, $args );
58 |
59 | if ( isset( $args['args'] ) ) {
60 | add_filter( 'register_taxonomy_args', function( $defaults, $name ) use ( $taxonomy, $args ) {
61 | if ( $taxonomy !== $name ) {
62 | return $defaults;
63 | }
64 |
65 | $args = wp_parse_args( $args['args'], $defaults );
66 |
67 | return $args;
68 | }, 10, 2 );
69 | }
70 | }
71 | }
72 |
73 | /**
74 | * Renames a taxonomy.
75 | *
76 | * Run this function before the `init` hook.
77 | *
78 | * @since 2.2.0
79 | *
80 | * @param string $taxonomy The taxonomy to rename.
81 | * @param string $name_singular The new singular name.
82 | * @param string $name_plural The new plural name.
83 | */
84 | public static function rename( $taxonomy, $name_singular, $name_plural ) {
85 | if ( ! taxonomy_exists( $taxonomy ) ) {
86 | return;
87 | }
88 |
89 | ( new Taxonomy_Labels( $taxonomy, $name_singular, $name_plural ) )->init();
90 | }
91 |
92 | /**
93 | * Adds missing arguments for taxonomy.
94 | *
95 | * @since 2.2.0
96 | *
97 | * @param array $args An array of arguments.
98 | *
99 | * @return mixed
100 | */
101 | private static function parse_args( $args ) {
102 | if ( isset( $args['name_singular'] ) && ! isset( $args['name_plural'] ) ) {
103 | $args['name_plural'] = $args['name_singular'];
104 | }
105 |
106 | return $args;
107 | }
108 |
109 | /**
110 | * Registers extensions.
111 | *
112 | * @since 2.2.0
113 | *
114 | * @param string $taxonomy The taxonomy name.
115 | * @param array $args Arguments for the taxonomy.
116 | */
117 | private static function register_extensions( $taxonomy, $args ) {
118 | if ( isset( $args['name_singular'] ) ) {
119 | ( new Taxonomy_Labels( $taxonomy, $args['name_singular'], $args['name_plural'] ) )->init();
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/Post_Type.php:
--------------------------------------------------------------------------------
1 | $args ) {
27 | $args = self::parse_args( $args );
28 |
29 | self::register_extensions( $post_type, $args );
30 |
31 | // Defaults for post registration.
32 | $args = wp_parse_args( $args['args'], [
33 | 'description' => $args['name_plural'],
34 | 'public' => false,
35 | 'show_ui' => true,
36 | 'show_in_nav_menus' => true,
37 | ] );
38 |
39 | register_post_type( $post_type, $args );
40 | }
41 | }
42 |
43 | /**
44 | * Updates settings for a post type.
45 | *
46 | * Here, you use the same settings that you also use for the `register()` function.
47 | * Run this function before the `init` hook.
48 | *
49 | * @see register_post_type()
50 | * @since 2.2.0
51 | *
52 | * @param array $post_types An associative array of post types and its arguments that should be
53 | * updated. See the `register()` function for all the arguments that
54 | * you can use.
55 | */
56 | public static function update( $post_types = [] ) {
57 | foreach ( $post_types as $post_type => $args ) {
58 | $args = self::parse_args( $args );
59 |
60 | self::register_extensions( $post_type, $args );
61 |
62 | if ( isset( $args['args'] ) ) {
63 | add_filter( 'register_post_type_args', function( $defaults, $name ) use ( $post_type, $args ) {
64 | if ( $post_type !== $name ) {
65 | return $defaults;
66 | }
67 |
68 | $args = wp_parse_args( $args['args'], $defaults );
69 |
70 | return $args;
71 | }, 10, 2 );
72 | }
73 | }
74 | }
75 |
76 | /**
77 | * Renames a post type.
78 | *
79 | * Run this function before the `init` hook.
80 | *
81 | * @since 2.1.1
82 | *
83 | * @param string $post_type The post type to rename.
84 | * @param string $name_singular The new singular name.
85 | * @param string $name_plural The new plural name.
86 | */
87 | public static function rename( $post_type, $name_singular, $name_plural ) {
88 | ( new Post_Type_Labels( $post_type, $name_singular, $name_plural ) )->init();
89 | }
90 |
91 | /**
92 | * Registers admin column settings for a post type.
93 | *
94 | * @since 2.1.0
95 | *
96 | * @param array $post_types An associative array of post types, where the name of the post type
97 | * is the key of an array that defines the admin column settings for
98 | * this post type.
99 | */
100 | public static function admin_columns( $post_types = [] ) {
101 | foreach ( $post_types as $name => $column_settings ) {
102 | ( new Post_Type_Columns( $name, $column_settings ) )->init();
103 | }
104 | }
105 |
106 | /**
107 | * Adds missing arguments for post type.
108 | *
109 | * @since 2.2.0
110 | *
111 | * @param array $args An array of arguments.
112 | *
113 | * @return mixed
114 | */
115 | private static function parse_args( $args ) {
116 | if ( isset( $args['name_singular'] ) && ! isset( $args['name_plural'] ) ) {
117 | $args['name_plural'] = $args['name_singular'];
118 | }
119 |
120 | return $args;
121 | }
122 |
123 | /**
124 | * Registers extensions.
125 | *
126 | * @since 2.2.0
127 | *
128 | * @param string $post_type The post type name.
129 | * @param array $args Arguments for the post type.
130 | */
131 | private static function register_extensions( $post_type, $args ) {
132 | if ( isset( $args['name_singular'] ) ) {
133 | ( new Post_Type_Labels( $post_type, $args['name_singular'], $args['name_plural'] ) )->init();
134 | }
135 |
136 | if ( isset( $args['query'] ) ) {
137 | ( new Post_Type_Query( $post_type, $args['query'] ) )->init();
138 | }
139 |
140 | if ( isset( $args['admin_columns'] ) ) {
141 | ( new Post_Type_Columns( $post_type, $args['admin_columns'] ) )->init();
142 | }
143 |
144 | if ( isset( $args['page_for_archive'] ) ) {
145 | $page_for_archive = wp_parse_args( $args['page_for_archive'], [
146 | 'post_id' => null,
147 | 'is_singular_public' => true,
148 | 'customizer_section' => '',
149 | 'show_post_state' => true,
150 | ] );
151 |
152 | ( new Post_Type_Page(
153 | $post_type,
154 | $page_for_archive['post_id'],
155 | $page_for_archive
156 | ) )->init();
157 |
158 | if ( ! empty( $page_for_archive['customizer_section'] ) ) {
159 | ( new Post_Type_Page_Option(
160 | $post_type,
161 | $page_for_archive['customizer_section']
162 | ) )->init();
163 | }
164 |
165 | if ( $page_for_archive['show_post_state'] ) {
166 | ( new Post_Type_Page_State( $post_type ) )->init();
167 | }
168 | }
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Types
2 |
3 | ## [2.5.8](https://github.com/mindkomm/types/compare/v2.5.7...v2.5.8) (2025-12-12)
4 |
5 |
6 | ### Bug Fixes
7 |
8 | * Fix a bug when post types couldn’t be renamed ([4a33bb2](https://github.com/mindkomm/types/commit/4a33bb2634b4f32d2a39524b61830db7b17fa283))
9 |
10 | ## [2.5.7](https://github.com/mindkomm/types/compare/2.5.6...v2.5.7) (2025-04-23)
11 |
12 |
13 | ### Bug Fixes
14 |
15 | * Fix a bug with environments where site_url() is different to home_url() ([#9](https://github.com/mindkomm/types/issues/9)) ([77ee7f7](https://github.com/mindkomm/types/commit/77ee7f75d2e1550093383c42c58225313d37f6d0))
16 | * **i18n:** Update post type labels ([#10](https://github.com/mindkomm/types/issues/10)) ([6d3c6d6](https://github.com/mindkomm/types/commit/6d3c6d64da9a7e2407ba6ce1e5758217e323b5a6))
17 |
18 | ## 2.5.6 - 2022-10-13
19 |
20 | - Fixed return type for label filter.
21 | - Fixed bugs when trying to access column data on columns that are not arrays (e.g. when column is set to `false`).
22 | - Improved default compatibility with custom permalink structure when using the `page_for_archive` option.
23 |
24 | ## 2.5.5 - 2021-11-30
25 |
26 | - Fixed a bug with orderby query parameters that are arrays.
27 |
28 | ## 2.5.4 - 2020-08-19
29 |
30 | - Fixed error notice.
31 |
32 | ## 2.5.3 - 2020-08-18
33 |
34 | - Added a new `column_order` argument for the `admin_columns` option.
35 | - Added a new `image` type for the `admin_columns` option.
36 | - Added a new `custom` type for the `admin_columns` option.
37 | - Fixed a bug when updating the label for a custom post type didn’t work properly.
38 | - Fixed a bug when search for meta for title.
39 |
40 | ## 2.5.2 - 2020-07-29
41 |
42 | - Fixed a bug when wrong translation loaded in admin.
43 | - Fixed a bug when searching for post titles didn’t work in combination with meta value searches.
44 | - Fixed some code style issues (thanks, @szepeviktor).
45 |
46 | ## 2.5.1 - 2020-07-08
47 |
48 | - Fixed a PHP notice.
49 |
50 | ## 2.5.0 - 2020-07-08
51 |
52 | - Fixed `sortable` parameter for the `admin_columns` option. Sorting didn’t work properly before. It should work now.
53 | - Changed default for `sortable` parameter for the `admin_columns` option from `true` to `false`.
54 | - Added new `orderby` parameter for the `admin_columns` option that will be used in combination with the `sortable` parameter.
55 | - Fixed a bug when the `query` option was interfering with sorting queries in post list tables.
56 |
57 | ## 2.4.4 - 2020-02-11
58 |
59 | - Added Dutch translations.
60 | - Added `searchable` option as an option for admin columns to make meta columns searchable.
61 | - Changed default column type for admin columns from `default` to `meta` to be more explicit.
62 |
63 | ## 2.4.3 - 2019-11-13
64 |
65 | This release improves compatibility with multisite environments, especially when working with [MultilingualPress](https://multilingualpress.de/).
66 |
67 | - Fixed bug when page archives didn’t work in multilingual multisite environments.
68 | - Fixed bug when proper archive link couldn’t be selected in multisite environment.
69 |
70 | ## 2.4.2 - 2019-10-17
71 |
72 | - Fixed bug when no page was selected for a custom post type archive in `Post_Type_Page_Option`.
73 |
74 | ## 2.4.1 - 2019-08-05
75 |
76 | - Added filter to update the title for the post type archive when using `post_type_archive_title()`.
77 |
78 | ## 2.4.0 - 2019-06-28
79 |
80 | - Added `Post_Type_Page_Option` class, which registers an option to select the page to act as the custom post type archive in the Customizer for you.
81 | - Added `Post_Type_Page_State` class, which adds a post state label to the the pages overview in the admin to recognize pages that act as custom post type archives quicker.
82 |
83 | Read more about these functionalities in the [`page_for_archive`](https://github.com/mindkomm/types#page_for_archive) section in the README.
84 |
85 | ## 2.3.2 - 2019-06-07
86 |
87 | - Added edit page link to admin bar for archive pages.
88 |
89 | ## 2.3.1 - 2019-03-18
90 |
91 | - Fixed CSS classes added to parent and ancestor menu items.
92 |
93 | ## 2.3.0 - 2019-03-06
94 |
95 | - Added new `Types\Post_Type_Page` class. This class allows you to define a page that should act as the archive for a Custom Post Type [using the `page_for_archive` option](https://github.com/mindkomm/types#page_for_archive).
96 | - Fixed a bug with an undefined function #2 (Thanks @roylodder).
97 |
98 | ## 2.2.3 - 2019-01-17
99 |
100 | - Added new post type labels ().
101 | - Fixed wrong label assignment.
102 |
103 | ## 2.2.2 - 2018-10-08
104 |
105 | - Updated post slug feature to not run when a post is being trashed.
106 | - Fixed bug when a post slug couldn’t be set when a date couldn’t be parsed. When the date can’t be parsed, the post slug won’t be changed.
107 |
108 | ## 2.2.1 - 2018-09-20
109 |
110 | - Fixed bug when certain values didn’t exist yet for a post.
111 |
112 | ## 2.2.0 - 2018-08-29
113 |
114 | - Added better handling of labels by updating the messages displayed in the backend and making it possible to properly translate the labels. This will open up the repository for additional languages.
115 | - Added new function `update()` to update the settings for existing post types and taxonomies.
116 | - Added new function `rename()` to rename existing post types and taxonomies.
117 | - Added option for post types to have separate queries with a `frontend` and `backend` argument for `query`.
118 | - Fixed when a post slug wasn’t updated on first save.
119 |
120 | ## 2.1.0 - 2018-08-27
121 |
122 | - Added new function `admin_columns()` to customize admin columns for already registered post types.
123 | - Added special `thumbnail` column key to display the featured image.
124 | - Added `sortable` option for a column to define whether it’s sortable.
125 |
126 | ## 2.0.1 - 2018-08-23
127 |
128 | - Fixed undefined index notices.
129 |
130 | ## 2.0.0 - 2018-08-22
131 |
132 | - Renamed package from «Custom Types» to just «Types».
133 | - Renamed classes.
134 | - Renamed registration methods.
135 | - Added helper class to customize post slugs when posts are saved.
136 |
137 | ## 1.1.0 - 2018-08-21
138 |
139 | - Added `query` argument to define how posts are queried in the front- and backend.
140 | - Added `admin_columns` argument to define the admin columns that should be displayed.
141 |
142 | ## 1.0.0 - 2018-02-13
143 |
144 | Initial release.
145 |
--------------------------------------------------------------------------------
/lib/Taxonomy_Labels.php:
--------------------------------------------------------------------------------
1 | taxonomy = $taxonomy;
50 | $this->name_singular = $name_singular;
51 | $this->name_plural = $name_plural;
52 | $this->labels = $this->get_labels( $name_singular, $name_plural );
53 | }
54 |
55 | /**
56 | * Inits hooks.
57 | */
58 | public function init() {
59 | add_filter( "taxonomy_labels_{$this->taxonomy}", function() {
60 | return $this->labels;
61 | } );
62 |
63 | if ( is_admin() ) {
64 | // Update messages in backend.
65 | add_filter( 'term_updated_messages', [ $this, 'add_term_updated_messages' ] );
66 | }
67 | }
68 |
69 | /**
70 | * Get labels for taxonomy base on singular and plural name.
71 | *
72 | * The following labels are not translated, because they don’t contain the post type name:
73 | * most_used
74 | *
75 | * @link https://developer.wordpress.org/reference/functions/get_taxonomy_labels/
76 | *
77 | * @param string $name_singular Singular name for taxonomy.
78 | * @param string $name_plural Plural name for taxonomy.
79 | *
80 | * @return array The translated labels.
81 | */
82 | public function get_labels( $name_singular, $name_plural ) {
83 | $labels = [
84 | 'name' => $name_plural,
85 | 'singular_name' => $name_singular,
86 | /* translators: %s: Singular taxonomy name */
87 | 'add_new_item' => sprintf( __( 'Add New %s', 'mind/types' ), $name_singular ),
88 | /* translators: %s: Plural taxonomy name */
89 | 'add_or_remove_items' => sprintf( __( 'Add or remove %s', 'mind/types' ), $name_plural ),
90 | /* translators: %s: Plural taxonomy name */
91 | 'all_items' => sprintf( __( 'All %s', 'mind/types' ), $name_plural ),
92 | /* translators: %s: Singular post type name */
93 | 'archives' => sprintf( __( '%s Archives', 'mind/types' ), $name_singular ),
94 | /* translators: %s: Plural taxonomy name */
95 | 'back_to_items' => sprintf( __( '← Back to %s', 'mind/types' ), $name_plural ),
96 | /* translators: %s: Plural taxonomy name */
97 | 'choose_from_most_used' => sprintf( __( 'Choose from the most used %s', 'mind/types' ), $name_plural ),
98 | /* translators: %s: Singular taxonomy name */
99 | 'edit_item' => sprintf( __( 'Edit %s', 'mind/types' ), $name_singular ),
100 | /* translators: %s: Plural taxonomy name */
101 | 'items_list' => sprintf( __( '%s list', 'mind/types' ), $name_plural ),
102 | /* translators: %s: Plural taxonomy name */
103 | 'items_list_navigation' => sprintf( __( '%s list navigation', 'mind/types' ), $name_plural ),
104 | /* translators: %s: Singular taxonomy name */
105 | 'new_item_name' => sprintf( __( 'New %s Name', 'mind/types' ), $name_singular ),
106 | /* translators: %s: Plural taxonomy name */
107 | 'no_terms' => sprintf( __( 'No %s', 'mind/types' ), $name_plural ),
108 | /* translators: %s: Plural taxonomy name */
109 | 'not_found' => sprintf( __( 'No %s found.', 'mind/types' ), $name_plural ),
110 | /* translators: %s: Singular taxonomy name */
111 | 'parent_item' => sprintf( __( 'Parent %s', 'mind/types' ), $name_singular ),
112 | /* translators: %s: Singular taxonomy name */
113 | 'parent_item_colon' => sprintf( __( 'Parent %s:', 'mind/types' ), $name_singular ),
114 | /* translators: %s: Plural taxonomy name */
115 | 'popular_items' => sprintf( __( 'Popular %s', 'mind/types' ), $name_plural ),
116 | /* translators: %s: Plural taxonomy name */
117 | 'search_items' => sprintf( __( 'Search %s', 'mind/types' ), $name_plural ),
118 | /* translators: %s: Plural taxonomy name */
119 | 'separate_items_with_commas' => sprintf( __( 'Separate %s with commas', 'mind/types' ), $name_plural ),
120 | /* translators: %s: Singular taxonomy name */
121 | 'update_item' => sprintf( __( 'Update %s', 'mind/types' ), $name_singular ),
122 | /* translators: %s: Singular taxonomy name */
123 | 'view_item' => sprintf( __( 'View %s', 'mind/types' ), $name_singular ),
124 | 'name_admin_bar' => $name_singular,
125 | 'menu_name' => $name_plural,
126 | ];
127 |
128 | return $labels;
129 | }
130 |
131 | /**
132 | * Sets term updated messages for custom taxonomies.
133 | *
134 | * Check out the `term_updated_messages` in wp-admin/includes/edit-tag-messages.php.
135 | *
136 | * @param array $messages An associative array of taxonomies and their messages.
137 | *
138 | * @return array The filtered messages.
139 | */
140 | public function add_term_updated_messages( $messages ) {
141 | $messages[ $this->taxonomy ] = [
142 | 0 => '',
143 | /* translators: %s: Singular taxonomy name */
144 | 1 => sprintf( __( '%s added.', 'mind/types' ), $this->name_singular ),
145 | /* translators: %s: Singular taxonomy name */
146 | 2 => sprintf( __( '%s deleted.', 'mind/types' ), $this->name_singular ),
147 | /* translators: %s: Singular taxonomy name */
148 | 3 => sprintf( __( '%s updated.', 'mind/types' ), $this->name_singular ),
149 | /* translators: %s: Singular taxonomy name */
150 | 4 => sprintf( __( '%s not added.', 'mind/types' ), $this->name_singular ),
151 | /* translators: %s: Singular taxonomy name */
152 | 5 => sprintf( __( '%s not updated.', 'mind/types' ), $this->name_singular ),
153 | /* translators: %s: Plural taxonomy name */
154 | 6 => sprintf( __( '%s deleted.', 'mind/types' ), $this->name_plural ),
155 | ];
156 |
157 | return $messages;
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/languages/types.pot:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "Project-Id-Version: \n"
4 | "Report-Msgid-Bugs-To: \n"
5 | "Last-Translator: FULL NAME \n"
6 | "Language-Team: LANGUAGE \n"
7 | "MIME-Version: 1.0\n"
8 | "Content-Type: text/plain; charset=UTF-8\n"
9 | "Content-Transfer-Encoding: 8bit\n"
10 | "POT-Creation-Date: 2025-04-23T15:32:16+02:00\n"
11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 | "X-Generator: WP-CLI 2.11.0\n"
13 | "X-Domain: mind/types\n"
14 |
15 | #: lib/Post_Type_Columns.php:37
16 | msgid "Featured Image"
17 | msgstr ""
18 |
19 | #: lib/Post_Type_Labels.php:77
20 | msgid "Add New"
21 | msgstr ""
22 |
23 | #. translators: %s: Singular post type name
24 | #. translators: %s: Singular taxonomy name
25 | #: lib/Post_Type_Labels.php:80
26 | #: lib/Taxonomy_Labels.php:87
27 | msgid "Add New %s"
28 | msgstr ""
29 |
30 | #. translators: %s: Plural post type name
31 | #. translators: %s: Plural taxonomy name
32 | #: lib/Post_Type_Labels.php:85
33 | #: lib/Taxonomy_Labels.php:91
34 | msgid "All %s"
35 | msgstr ""
36 |
37 | #. translators: %s: Singular post type name
38 | #: lib/Post_Type_Labels.php:90
39 | #: lib/Taxonomy_Labels.php:93
40 | msgid "%s Archives"
41 | msgstr ""
42 |
43 | #. translators: %s: Singular post type name
44 | #: lib/Post_Type_Labels.php:95
45 | msgid "%s Attributes"
46 | msgstr ""
47 |
48 | #. translators: %s: Singular post type name
49 | #. translators: %s: Singular taxonomy name
50 | #: lib/Post_Type_Labels.php:100
51 | #: lib/Taxonomy_Labels.php:99
52 | msgid "Edit %s"
53 | msgstr ""
54 |
55 | #. translators: %s: Singular post type name
56 | #: lib/Post_Type_Labels.php:105
57 | msgid "Featured Image for %s"
58 | msgstr ""
59 |
60 | #. translators: %s: Plural post type name
61 | #: lib/Post_Type_Labels.php:110
62 | msgid "Filter %s list"
63 | msgstr ""
64 |
65 | #. translators: %s: Singular post type name
66 | #: lib/Post_Type_Labels.php:115
67 | msgid "Insert into %s"
68 | msgstr ""
69 |
70 | #. translators: %s: Plural post type name
71 | #. translators: %s: Plural taxonomy name
72 | #: lib/Post_Type_Labels.php:120
73 | #: lib/Taxonomy_Labels.php:101
74 | msgid "%s list"
75 | msgstr ""
76 |
77 | #. translators: %s: Plural post type name
78 | #. translators: %s: Plural taxonomy name
79 | #: lib/Post_Type_Labels.php:125
80 | #: lib/Taxonomy_Labels.php:103
81 | msgid "%s list navigation"
82 | msgstr ""
83 |
84 | #. translators: %s: Singular post type name
85 | #: lib/Post_Type_Labels.php:130
86 | #: lib/Post_Type_Labels.php:251
87 | msgid "%s published."
88 | msgstr ""
89 |
90 | #. translators: %s: Singular post type name
91 | #: lib/Post_Type_Labels.php:135
92 | msgid "%s published privately."
93 | msgstr ""
94 |
95 | #. translators: %s: Singular post type name
96 | #: lib/Post_Type_Labels.php:140
97 | msgid "%s reverted to draft."
98 | msgstr ""
99 |
100 | #. translators: %s: Singular post type name
101 | #: lib/Post_Type_Labels.php:145
102 | msgid "%s trashed."
103 | msgstr ""
104 |
105 | #. translators: %s: Singular post type name
106 | #: lib/Post_Type_Labels.php:150
107 | msgid "%s scheduled."
108 | msgstr ""
109 |
110 | #. translators: %s: Singular post type name
111 | #. translators: %s: Singular taxonomy name
112 | #: lib/Post_Type_Labels.php:155
113 | #: lib/Post_Type_Labels.php:247
114 | #: lib/Post_Type_Labels.php:249
115 | #: lib/Taxonomy_Labels.php:148
116 | msgid "%s updated."
117 | msgstr ""
118 |
119 | #. translators: %s: Singular post type name
120 | #: lib/Post_Type_Labels.php:160
121 | msgid "New %s"
122 | msgstr ""
123 |
124 | #. translators: %s: Plural post type name
125 | #. translators: %s: Plural taxonomy name
126 | #: lib/Post_Type_Labels.php:165
127 | #: lib/Taxonomy_Labels.php:109
128 | msgid "No %s found."
129 | msgstr ""
130 |
131 | #. translators: %s: Plural post type name
132 | #: lib/Post_Type_Labels.php:170
133 | msgid "No %s found in trash."
134 | msgstr ""
135 |
136 | #. translators: %s: Singular post type name
137 | #. translators: %s: Singular taxonomy name
138 | #: lib/Post_Type_Labels.php:175
139 | #: lib/Taxonomy_Labels.php:111
140 | msgid "Parent %s"
141 | msgstr ""
142 |
143 | #. translators: %s: Singular post type name
144 | #. translators: %s: Singular taxonomy name
145 | #: lib/Post_Type_Labels.php:180
146 | #: lib/Taxonomy_Labels.php:113
147 | msgid "Parent %s:"
148 | msgstr ""
149 |
150 | #. translators: %s: Plural post type name
151 | #. translators: %s: Plural taxonomy name
152 | #: lib/Post_Type_Labels.php:185
153 | #: lib/Taxonomy_Labels.php:117
154 | msgid "Search %s"
155 | msgstr ""
156 |
157 | #. translators: %s: Singular post type name
158 | #: lib/Post_Type_Labels.php:190
159 | msgid "Uploaded to this %s"
160 | msgstr ""
161 |
162 | #. translators: %s: Singular post type name
163 | #. translators: %s: Plural post type name
164 | #. translators: %s: Singular taxonomy name
165 | #: lib/Post_Type_Labels.php:195
166 | #: lib/Post_Type_Labels.php:200
167 | #: lib/Post_Type_Labels.php:237
168 | #: lib/Taxonomy_Labels.php:123
169 | msgid "View %s"
170 | msgstr ""
171 |
172 | #. translators: %s: Singular post type name
173 | #: lib/Post_Type_Labels.php:228
174 | msgid "Preview %s"
175 | msgstr ""
176 |
177 | #. translators: %s: Singular post type name
178 | #: lib/Post_Type_Labels.php:253
179 | msgid "%s saved."
180 | msgstr ""
181 |
182 | #. translators: %s: Singular post type name
183 | #: lib/Post_Type_Labels.php:255
184 | msgid "%s submitted."
185 | msgstr ""
186 |
187 | #. translators: %s: Singular post type name
188 | #: lib/Post_Type_Labels.php:257
189 | msgid "%s draft updated."
190 | msgstr ""
191 |
192 | #. translators: Plural name of the post type
193 | #: lib/Post_Type_Page.php:233
194 | msgid "Edit page for %s"
195 | msgstr ""
196 |
197 | #. translators: Post type label.
198 | #: lib/Post_Type_Page_Option.php:86
199 | #: lib/Post_Type_Page_State.php:60
200 | msgid "Page for %s"
201 | msgstr ""
202 |
203 | #. translators: %s: Plural taxonomy name
204 | #: lib/Taxonomy_Labels.php:89
205 | msgid "Add or remove %s"
206 | msgstr ""
207 |
208 | #. translators: %s: Plural taxonomy name
209 | #: lib/Taxonomy_Labels.php:95
210 | msgid "← Back to %s"
211 | msgstr ""
212 |
213 | #. translators: %s: Plural taxonomy name
214 | #: lib/Taxonomy_Labels.php:97
215 | msgid "Choose from the most used %s"
216 | msgstr ""
217 |
218 | #. translators: %s: Singular taxonomy name
219 | #: lib/Taxonomy_Labels.php:105
220 | msgid "New %s Name"
221 | msgstr ""
222 |
223 | #. translators: %s: Plural taxonomy name
224 | #: lib/Taxonomy_Labels.php:107
225 | msgid "No %s"
226 | msgstr ""
227 |
228 | #. translators: %s: Plural taxonomy name
229 | #: lib/Taxonomy_Labels.php:115
230 | msgid "Popular %s"
231 | msgstr ""
232 |
233 | #. translators: %s: Plural taxonomy name
234 | #: lib/Taxonomy_Labels.php:119
235 | msgid "Separate %s with commas"
236 | msgstr ""
237 |
238 | #. translators: %s: Singular taxonomy name
239 | #: lib/Taxonomy_Labels.php:121
240 | msgid "Update %s"
241 | msgstr ""
242 |
243 | #. translators: %s: Singular taxonomy name
244 | #: lib/Taxonomy_Labels.php:144
245 | msgid "%s added."
246 | msgstr ""
247 |
248 | #. translators: %s: Singular taxonomy name
249 | #. translators: %s: Plural taxonomy name
250 | #: lib/Taxonomy_Labels.php:146
251 | #: lib/Taxonomy_Labels.php:154
252 | msgid "%s deleted."
253 | msgstr ""
254 |
255 | #. translators: %s: Singular taxonomy name
256 | #: lib/Taxonomy_Labels.php:150
257 | msgid "%s not added."
258 | msgstr ""
259 |
260 | #. translators: %s: Singular taxonomy name
261 | #: lib/Taxonomy_Labels.php:152
262 | msgid "%s not updated."
263 | msgstr ""
264 |
--------------------------------------------------------------------------------
/lib/Post_Type_Page.php:
--------------------------------------------------------------------------------
1 | post_type = $post_type;
45 | $this->post_id = (int) $post_id;
46 |
47 | $this->args = wp_parse_args( $args, [
48 | 'is_singular_public' => true,
49 | ] );
50 | }
51 |
52 | /**
53 | * Inits hooks.
54 | */
55 | public function init() {
56 | /**
57 | * Bail out if no valid post ID is provided or post ID is 0, which happens when no page is
58 | * selected from dropdown-pages.
59 | */
60 | if ( ! $this->post_id ) {
61 | return;
62 | }
63 |
64 | add_filter( 'register_post_type_args', [ $this, 'update_archive_slug' ], 10, 2 );
65 | add_filter( 'post_type_archive_link', [ $this, 'update_archive_link' ], 10, 2 );
66 |
67 | add_filter( 'wp_nav_menu_objects', [ $this, 'filter_wp_nav_menu_objects' ], 1 );
68 | add_filter( 'post_type_archive_title', [ $this, 'set_post_type_archive_title' ], 10, 2 );
69 |
70 | if ( ! $this->args['is_singular_public'] ) {
71 | add_action( 'template_redirect', [ $this, 'template_redirect' ] );
72 | }
73 |
74 | if ( ! is_admin() ) {
75 | add_action( 'admin_bar_menu', [ $this, 'add_page_edit_link' ], 80 );
76 | }
77 | }
78 |
79 | /**
80 | * Update the archive slug to be the same as the page that should be used for the archive.
81 | *
82 | * Setting the `has_archive` property will set the proper rewrite rules so that the page URL
83 | * will be used as the archive page.
84 | *
85 | * @param array $args Post type registration arguments.
86 | * @param string $post_type Post type name.
87 | *
88 | * @return mixed
89 | */
90 | public function update_archive_slug( $args, $post_type ) {
91 | if ( $post_type !== $this->post_type ) {
92 | return $args;
93 | }
94 |
95 | $link = get_permalink( $this->post_id );
96 |
97 | /**
98 | * We need to strip away the current base URL from the link, so that we
99 | * get the relative link. It’s not enough to use wp_make_link_relative(),
100 | * because then WordPress websites in subfolders wouldn’t work. This is
101 | * often the case in multisite environments.
102 | */
103 | $link = str_replace( home_url(), '', $link );
104 |
105 | // Trim leading and trailing slashes.
106 | $link = trim( $link, '/' );
107 |
108 | $args['has_archive'] = $link;
109 |
110 | /**
111 | * Make sure with_front is set to false by default.
112 | *
113 | * If you set a custom permalink base in Settings → Permalink, then that permalink is
114 | * prepended to all the custom post types that have with_front set to true. For example:
115 | *
116 | * If you have a post type called book and set /blog/%postname%/ as your permalink
117 | * structure, then /blog/ will be prepended to your custom post type, which will result in
118 | * /blog/book/.
119 | *
120 | * Mostly, this is not what we want and why we set with_front to false by default.
121 | */
122 | $args['rewrite'] = wp_parse_args( $args['rewrite'] ?? [], [
123 | 'with_front' => false,
124 | ] );
125 |
126 | return $args;
127 | }
128 |
129 | /**
130 | * Filters the post type archive permalink.
131 | *
132 | * This filter is needed for links to be returned properly in multisite environments, when the
133 | * get_post_type_archive_link() function is called after switch_to_blog() was used.
134 | *
135 | * @since 2.4.3
136 | * @see \get_post_type_archive_link()
137 | *
138 | * @param string $link The post type archive permalink.
139 | * @param string $post_type Post type name.
140 | *
141 | * @return string
142 | */
143 | public function update_archive_link( $link, $post_type ) {
144 | if ( $post_type !== $this->post_type ) {
145 | return $link;
146 | }
147 |
148 | return get_permalink( $this->post_id );
149 | }
150 |
151 | /**
152 | * Redirects singular page views to the post type archive page.
153 | */
154 | public function template_redirect() {
155 | if ( is_singular( $this->post_type ) ) {
156 | wp_safe_redirect( get_post_type_archive_link( $this->post_type ), 301 );
157 | exit;
158 | }
159 | }
160 |
161 | /**
162 | * Make sure menu items for our pages get the correct classes assigned.
163 | *
164 | * @param array $menu_items Array of menu items.
165 | *
166 | * @return array
167 | */
168 | public function filter_wp_nav_menu_objects( $menu_items ) {
169 | foreach ( $menu_items as &$item ) {
170 | if ( 'page' !== $item->object || (int) $item->object_id !== $this->post_id ) {
171 | continue;
172 | }
173 |
174 | if ( is_singular( $this->post_type ) ) {
175 | $item->current_item_parent = true;
176 | $item->classes[] = 'current-menu-parent';
177 |
178 | $menu_items = \Types\menu_items_ancestors( $item, $menu_items );
179 | }
180 |
181 | if ( is_post_type_archive( $this->post_type ) ) {
182 | $item->classes[] = 'current-menu-item';
183 | $item->current = true;
184 |
185 | $menu_items = \Types\menu_items_ancestors( $item, $menu_items );
186 | }
187 | }
188 |
189 | return $menu_items;
190 | }
191 |
192 | /**
193 | * Filters the post type archive title to match the title of the post type archive page.
194 | *
195 | * @since 2.4.1
196 | * @see post_type_archive_title()
197 | *
198 | * @param string $title The archive title.
199 | * @param string $post_type The post type.
200 | *
201 | * @return string The title for the archive.
202 | */
203 | public function set_post_type_archive_title( $title, $post_type ) {
204 | if ( $this->post_type !== $post_type ) {
205 | return $title;
206 | }
207 |
208 | return get_the_title( $this->post_id );
209 | }
210 |
211 | /**
212 | * Adds a page edit link for the page that acts as the archive to the admin bar.
213 | *
214 | * @see wp_admin_bar_edit_menu()
215 | *
216 | * @since 2.3.2
217 | * @param \WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance.
218 | */
219 | public function add_page_edit_link( $wp_admin_bar ) {
220 | $object = get_queried_object();
221 |
222 | if ( empty( $object )
223 | || ! $object instanceof \WP_Post_Type
224 | || $object->name !== $this->post_type
225 | || ! $object->show_in_admin_bar
226 | || ! current_user_can( 'edit_pages', $this->post_id )
227 | ) {
228 | return;
229 | }
230 |
231 | $wp_admin_bar->add_menu( [
232 | 'id' => 'edit',
233 | /* translators: Plural name of the post type */
234 | 'title' => sprintf( __( 'Edit page for %s', 'mind/types' ), $object->labels->name ),
235 | 'href' => get_edit_post_link( $this->post_id ),
236 | ] );
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/languages/types-nl_NL.po:
--------------------------------------------------------------------------------
1 | msgid ""
2 | msgstr ""
3 | "Project-Id-Version: \n"
4 | "Report-Msgid-Bugs-To: \n"
5 | "POT-Creation-Date: 2019-06-28T09:32:42+02:00\n"
6 | "PO-Revision-Date: 2020-02-11 18:22+0100\n"
7 | "Language-Team: \n"
8 | "Language: nl_NL\n"
9 | "MIME-Version: 1.0\n"
10 | "Content-Type: text/plain; charset=UTF-8\n"
11 | "Content-Transfer-Encoding: 8bit\n"
12 | "X-Generator: Poedit 2.3\n"
13 | "X-Domain: mind/types\n"
14 | "Last-Translator: Roy van Toren\n"
15 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
16 |
17 | #. translators: Plural name of the post type
18 | #: lib/Post_Type_Page.php:153
19 | msgid "Edit page for %s"
20 | msgstr "Pagina voor %s bewerken"
21 |
22 | #. translators: Post type label.
23 | #: lib/Post_Type_Page_Option.php:107 lib/Post_Type_Page_Option.php:159
24 | msgid "Page for %s"
25 | msgstr "Pagina voor %s"
26 |
27 | #. translators: %s: Singular taxonomy name
28 | #. translators: %s: Singular post type name
29 | #: lib/Taxonomy_Labels.php:87 lib/Post_Type_Labels.php:90
30 | msgid "Add New %s"
31 | msgstr "Nieuwe %s toevoegen"
32 |
33 | #. translators: %s: Plural taxonomy name
34 | #: lib/Taxonomy_Labels.php:89
35 | msgid "Add or remove %s"
36 | msgstr "%s toevoegen of verwijderen"
37 |
38 | #. translators: %s: Plural taxonomy name
39 | #. translators: %s: Plural post type name
40 | #: lib/Taxonomy_Labels.php:91 lib/Post_Type_Labels.php:92
41 | msgid "All %s"
42 | msgstr "Alle %s"
43 |
44 | #. translators: %s: Singular post type name
45 | #: lib/Taxonomy_Labels.php:93 lib/Post_Type_Labels.php:94
46 | msgid "%s Archives"
47 | msgstr "%s archief"
48 |
49 | #. translators: %s: Plural taxonomy name
50 | #: lib/Taxonomy_Labels.php:95
51 | msgid "← Back to %s"
52 | msgstr "← Terug naar %s"
53 |
54 | #. translators: %s: Plural taxonomy name
55 | #: lib/Taxonomy_Labels.php:97
56 | msgid "Choose from the most used %s"
57 | msgstr "Kies uit de meest gebruikte %s"
58 |
59 | #. translators: %s: Singular taxonomy name
60 | #. translators: %s: Singular post type name
61 | #: lib/Taxonomy_Labels.php:99 lib/Post_Type_Labels.php:98
62 | msgid "Edit %s"
63 | msgstr "%s bewerken"
64 |
65 | #. translators: %s: Plural taxonomy name
66 | #. translators: %s: Plural post type name
67 | #: lib/Taxonomy_Labels.php:101 lib/Post_Type_Labels.php:106
68 | msgid "%s list"
69 | msgstr "%slijst"
70 |
71 | #. translators: %s: Plural taxonomy name
72 | #. translators: %s: Plural post type name
73 | #: lib/Taxonomy_Labels.php:103 lib/Post_Type_Labels.php:108
74 | msgid "%s list navigation"
75 | msgstr "Navigatie door %slijst"
76 |
77 | #. translators: %s: Singular taxonomy name
78 | #: lib/Taxonomy_Labels.php:105
79 | msgid "New %s Name"
80 | msgstr "Nieuwe %snaam"
81 |
82 | #. translators: %s: Plural taxonomy name
83 | #: lib/Taxonomy_Labels.php:107
84 | msgid "No %s"
85 | msgstr "Geen %s"
86 |
87 | #. translators: %s: Plural taxonomy name
88 | #. translators: %s: Plural post type name
89 | #: lib/Taxonomy_Labels.php:109 lib/Post_Type_Labels.php:122
90 | msgid "No %s found."
91 | msgstr "Geen %s gevonden."
92 |
93 | #. translators: %s: Singular taxonomy name
94 | #. translators: %s: Singular post type name
95 | #: lib/Taxonomy_Labels.php:111 lib/Post_Type_Labels.php:126
96 | msgid "Parent %s"
97 | msgstr "Hoofd %s"
98 |
99 | #. translators: %s: Singular taxonomy name
100 | #. translators: %s: Singular post type name
101 | #: lib/Taxonomy_Labels.php:113 lib/Post_Type_Labels.php:128
102 | msgid "Parent %s:"
103 | msgstr "Hoofd %s:"
104 |
105 | #. translators: %s: Plural taxonomy name
106 | #: lib/Taxonomy_Labels.php:115
107 | msgid "Popular %s"
108 | msgstr "Populaire %s"
109 |
110 | #. translators: %s: Plural taxonomy name
111 | #. translators: %s: Plural post type name
112 | #: lib/Taxonomy_Labels.php:117 lib/Post_Type_Labels.php:130
113 | msgid "Search %s"
114 | msgstr "%s zoeken"
115 |
116 | #. translators: %s: Plural taxonomy name
117 | #: lib/Taxonomy_Labels.php:119
118 | msgid "Separate %s with commas"
119 | msgstr "%s scheiden door komma’s"
120 |
121 | #. translators: %s: Singular taxonomy name
122 | #: lib/Taxonomy_Labels.php:121
123 | msgid "Update %s"
124 | msgstr "%s bijwerken"
125 |
126 | #. translators: %s: Singular taxonomy name
127 | #. translators: %s: Singular post type name
128 | #. translators: %s: Plural post type name
129 | #: lib/Taxonomy_Labels.php:123 lib/Post_Type_Labels.php:134
130 | #: lib/Post_Type_Labels.php:136 lib/Post_Type_Labels.php:173
131 | msgid "View %s"
132 | msgstr "%s bekijken"
133 |
134 | #. translators: %s: Singular taxonomy name
135 | #: lib/Taxonomy_Labels.php:144
136 | msgid "%s added."
137 | msgstr "%s toegevoegd."
138 |
139 | #. translators: %s: Singular taxonomy name
140 | #. translators: %s: Plural taxonomy name
141 | #: lib/Taxonomy_Labels.php:146 lib/Taxonomy_Labels.php:154
142 | msgid "%s deleted."
143 | msgstr "%s verwijderd."
144 |
145 | #. translators: %s: Singular taxonomy name
146 | #. translators: %s: Singular post type name
147 | #: lib/Taxonomy_Labels.php:148 lib/Post_Type_Labels.php:118
148 | #: lib/Post_Type_Labels.php:183 lib/Post_Type_Labels.php:185
149 | msgid "%s updated."
150 | msgstr "%s bijgewerkt."
151 |
152 | #. translators: %s: Singular taxonomy name
153 | #: lib/Taxonomy_Labels.php:150
154 | msgid "%s not added."
155 | msgstr "%s niet toegevoegd."
156 |
157 | #. translators: %s: Singular taxonomy name
158 | #: lib/Taxonomy_Labels.php:152
159 | msgid "%s not updated."
160 | msgstr "%s niet bijgewerkt."
161 |
162 | #: lib/Post_Type_Columns.php:37
163 | msgid "Featured Image"
164 | msgstr "Uitgelichte afbeelding"
165 |
166 | #: lib/Post_Type_Labels.php:88
167 | msgid "Add New"
168 | msgstr "Nieuwe toevoegen"
169 |
170 | #. translators: %s: Singular post type name
171 | #: lib/Post_Type_Labels.php:96
172 | msgid "%s Attributes"
173 | msgstr "%s-attributen"
174 |
175 | #. translators: %s: Singular post type name
176 | #: lib/Post_Type_Labels.php:100
177 | msgid "Featured Image for %s"
178 | msgstr "Uitgelichte afbeelding voor %s"
179 |
180 | #. translators: %s: Plural post type name
181 | #: lib/Post_Type_Labels.php:102
182 | msgid "Filter %s list"
183 | msgstr "%s filteren"
184 |
185 | #. translators: %s: Singular post type name
186 | #: lib/Post_Type_Labels.php:104
187 | msgid "Insert into %s"
188 | msgstr "In %s invoegen"
189 |
190 | #. translators: %s: Singular post type name
191 | #: lib/Post_Type_Labels.php:110 lib/Post_Type_Labels.php:187
192 | msgid "%s published."
193 | msgstr "%s gepubliceerd."
194 |
195 | #. translators: %s: Singular post type name
196 | #: lib/Post_Type_Labels.php:112
197 | msgid "%s published privately."
198 | msgstr "%s privé gepubliceerd."
199 |
200 | #. translators: %s: Singular post type name
201 | #: lib/Post_Type_Labels.php:114
202 | msgid "%s reverted to draft."
203 | msgstr "%s teruggezet naar concept."
204 |
205 | #. translators: %s: Singular post type name
206 | #: lib/Post_Type_Labels.php:116
207 | msgid "%s scheduled."
208 | msgstr "%s gepland."
209 |
210 | #. translators: %s: Singular post type name
211 | #: lib/Post_Type_Labels.php:120
212 | msgid "New %s"
213 | msgstr "Nieuwe %s"
214 |
215 | #. translators: %s: Plural post type name
216 | #: lib/Post_Type_Labels.php:124
217 | msgid "No %s found in Trash."
218 | msgstr "Geen %s gevonden in de prullenbak."
219 |
220 | #. translators: %s: Singular post type name
221 | #: lib/Post_Type_Labels.php:132
222 | msgid "Uploaded to this %s"
223 | msgstr "Geüpload naar deze %s"
224 |
225 | #. translators: %s: Singular post type name
226 | #: lib/Post_Type_Labels.php:164
227 | msgid "Preview %s"
228 | msgstr "Voorbeeld %s"
229 |
230 | #. translators: %s: Singular post type name
231 | #: lib/Post_Type_Labels.php:189
232 | msgid "%s saved."
233 | msgstr "%s opgeslagen."
234 |
235 | #. translators: %s: Singular post type name
236 | #: lib/Post_Type_Labels.php:191
237 | msgid "%s submitted."
238 | msgstr "%s ingediend."
239 |
240 | #. translators: %s: Singular post type name
241 | #: lib/Post_Type_Labels.php:193
242 | msgid "%s draft updated."
243 | msgstr "%s concept bijgewerkt."
244 |
--------------------------------------------------------------------------------
/languages/types-de_DE.po:
--------------------------------------------------------------------------------
1 | #
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: \n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2025-04-23T15:32:16+02:00\n"
7 | "PO-Revision-Date: 2025-04-23 15:32+0200\n"
8 | "Last-Translator: Lukas Gächter \n"
9 | "Language-Team: \n"
10 | "Language: de\n"
11 | "MIME-Version: 1.0\n"
12 | "Content-Type: text/plain; charset=UTF-8\n"
13 | "Content-Transfer-Encoding: 8bit\n"
14 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15 | "X-Generator: Poedit 3.6\n"
16 | "X-Domain: mind/types\n"
17 |
18 | #: lib/Post_Type_Columns.php:37
19 | msgid "Featured Image"
20 | msgstr "Beitragsbild"
21 |
22 | #: lib/Post_Type_Labels.php:77
23 | msgid "Add New"
24 | msgstr "Hinzufügen"
25 |
26 | #. translators: %s: Singular post type name
27 | #. translators: %s: Singular taxonomy name
28 | #: lib/Post_Type_Labels.php:80 lib/Taxonomy_Labels.php:87
29 | msgid "Add New %s"
30 | msgstr "%s hinzufügen"
31 |
32 | #. translators: %s: Plural post type name
33 | #. translators: %s: Plural taxonomy name
34 | #: lib/Post_Type_Labels.php:85 lib/Taxonomy_Labels.php:91
35 | msgid "All %s"
36 | msgstr "Alle %s"
37 |
38 | #. translators: %s: Singular post type name
39 | #: lib/Post_Type_Labels.php:90 lib/Taxonomy_Labels.php:93
40 | msgid "%s Archives"
41 | msgstr "Archive für %s"
42 |
43 | #. translators: %s: Singular post type name
44 | #: lib/Post_Type_Labels.php:95
45 | msgid "%s Attributes"
46 | msgstr "Attribute für %s"
47 |
48 | #. translators: %s: Singular post type name
49 | #. translators: %s: Singular taxonomy name
50 | #: lib/Post_Type_Labels.php:100 lib/Taxonomy_Labels.php:99
51 | msgid "Edit %s"
52 | msgstr "%s bearbeiten"
53 |
54 | #. translators: %s: Singular post type name
55 | #: lib/Post_Type_Labels.php:105
56 | msgid "Featured Image for %s"
57 | msgstr "Beitragsbild für %s"
58 |
59 | #. translators: %s: Plural post type name
60 | #: lib/Post_Type_Labels.php:110
61 | msgid "Filter %s list"
62 | msgstr "% filtern"
63 |
64 | #. translators: %s: Singular post type name
65 | #: lib/Post_Type_Labels.php:115
66 | msgid "Insert into %s"
67 | msgstr "In %s einfügen"
68 |
69 | #. translators: %s: Plural post type name
70 | #. translators: %s: Plural taxonomy name
71 | #: lib/Post_Type_Labels.php:120 lib/Taxonomy_Labels.php:101
72 | msgid "%s list"
73 | msgstr "%s"
74 |
75 | #. translators: %s: Plural post type name
76 | #. translators: %s: Plural taxonomy name
77 | #: lib/Post_Type_Labels.php:125 lib/Taxonomy_Labels.php:103
78 | msgid "%s list navigation"
79 | msgstr "Navigation für %s"
80 |
81 | #. translators: %s: Singular post type name
82 | #: lib/Post_Type_Labels.php:130 lib/Post_Type_Labels.php:251
83 | msgid "%s published."
84 | msgstr "%s veröffentlicht."
85 |
86 | #. translators: %s: Singular post type name
87 | #: lib/Post_Type_Labels.php:135
88 | msgid "%s published privately."
89 | msgstr "%s privat veröffentlicht."
90 |
91 | #. translators: %s: Singular post type name
92 | #: lib/Post_Type_Labels.php:140
93 | msgid "%s reverted to draft."
94 | msgstr "%s auf Entwurf zurückgesetzt."
95 |
96 | #. translators: %s: Singular post type name
97 | #: lib/Post_Type_Labels.php:145
98 | msgid "%s trashed."
99 | msgstr "%s in den Papierkorb verschoben."
100 |
101 | #. translators: %s: Singular post type name
102 | #: lib/Post_Type_Labels.php:150
103 | msgid "%s scheduled."
104 | msgstr "%s geplant."
105 |
106 | #. translators: %s: Singular post type name
107 | #. translators: %s: Singular taxonomy name
108 | #: lib/Post_Type_Labels.php:155 lib/Post_Type_Labels.php:247
109 | #: lib/Post_Type_Labels.php:249 lib/Taxonomy_Labels.php:148
110 | msgid "%s updated."
111 | msgstr "%s aktualisiert."
112 |
113 | #. translators: %s: Singular post type name
114 | #: lib/Post_Type_Labels.php:160
115 | msgid "New %s"
116 | msgstr "%s hinzufügen"
117 |
118 | #. translators: %s: Plural post type name
119 | #. translators: %s: Plural taxonomy name
120 | #: lib/Post_Type_Labels.php:165 lib/Taxonomy_Labels.php:109
121 | msgid "No %s found."
122 | msgstr "Keine %s gefunden."
123 |
124 | #. translators: %s: Plural post type name
125 | #: lib/Post_Type_Labels.php:170
126 | msgid "No %s found in trash."
127 | msgstr "Keine %s im Papierkorb gefunden."
128 |
129 | #. translators: %s: Singular post type name
130 | #. translators: %s: Singular taxonomy name
131 | #: lib/Post_Type_Labels.php:175 lib/Taxonomy_Labels.php:111
132 | msgid "Parent %s"
133 | msgstr "Eltern-%s"
134 |
135 | #. translators: %s: Singular post type name
136 | #. translators: %s: Singular taxonomy name
137 | #: lib/Post_Type_Labels.php:180 lib/Taxonomy_Labels.php:113
138 | msgid "Parent %s:"
139 | msgstr "Eltern-%s:"
140 |
141 | #. translators: %s: Plural post type name
142 | #. translators: %s: Plural taxonomy name
143 | #: lib/Post_Type_Labels.php:185 lib/Taxonomy_Labels.php:117
144 | msgid "Search %s"
145 | msgstr "%s suchen"
146 |
147 | #. translators: %s: Singular post type name
148 | #: lib/Post_Type_Labels.php:190
149 | msgid "Uploaded to this %s"
150 | msgstr "Zu diesem %s hochgeladen"
151 |
152 | #. translators: %s: Singular post type name
153 | #. translators: %s: Plural post type name
154 | #. translators: %s: Singular taxonomy name
155 | #: lib/Post_Type_Labels.php:195 lib/Post_Type_Labels.php:200
156 | #: lib/Post_Type_Labels.php:237 lib/Taxonomy_Labels.php:123
157 | msgid "View %s"
158 | msgstr "%s anschauen"
159 |
160 | #. translators: %s: Singular post type name
161 | #: lib/Post_Type_Labels.php:228
162 | msgid "Preview %s"
163 | msgstr "%s-Vorschau ansehen"
164 |
165 | #. translators: %s: Singular post type name
166 | #: lib/Post_Type_Labels.php:253
167 | msgid "%s saved."
168 | msgstr "%s gespeichert."
169 |
170 | #. translators: %s: Singular post type name
171 | #: lib/Post_Type_Labels.php:255
172 | msgid "%s submitted."
173 | msgstr "%s übertragen."
174 |
175 | #. translators: %s: Singular post type name
176 | #: lib/Post_Type_Labels.php:257
177 | msgid "%s draft updated."
178 | msgstr "%s-Entwurf aktualisiert."
179 |
180 | #. translators: Plural name of the post type
181 | #: lib/Post_Type_Page.php:233
182 | msgid "Edit page for %s"
183 | msgstr "Seite für %s bearbeiten"
184 |
185 | #. translators: Post type label.
186 | #: lib/Post_Type_Page_Option.php:86 lib/Post_Type_Page_State.php:60
187 | msgid "Page for %s"
188 | msgstr "Seite für %s"
189 |
190 | #. translators: %s: Plural taxonomy name
191 | #: lib/Taxonomy_Labels.php:89
192 | msgid "Add or remove %s"
193 | msgstr "%s hinzufügen oder entfernen"
194 |
195 | #. translators: %s: Plural taxonomy name
196 | #: lib/Taxonomy_Labels.php:95
197 | msgid "← Back to %s"
198 | msgstr "← Zurück zu %s"
199 |
200 | #. translators: %s: Plural taxonomy name
201 | #: lib/Taxonomy_Labels.php:97
202 | msgid "Choose from the most used %s"
203 | msgstr "Wähle aus den am häufigsten verwendeten %s"
204 |
205 | #. translators: %s: Singular taxonomy name
206 | #: lib/Taxonomy_Labels.php:105
207 | msgid "New %s Name"
208 | msgstr "Neuer Name für %s"
209 |
210 | #. translators: %s: Plural taxonomy name
211 | #: lib/Taxonomy_Labels.php:107
212 | msgid "No %s"
213 | msgstr "Keine %s"
214 |
215 | #. translators: %s: Plural taxonomy name
216 | #: lib/Taxonomy_Labels.php:115
217 | msgid "Popular %s"
218 | msgstr "Beliebte %s"
219 |
220 | #. translators: %s: Plural taxonomy name
221 | #: lib/Taxonomy_Labels.php:119
222 | msgid "Separate %s with commas"
223 | msgstr "%s mit Komma trennen"
224 |
225 | #. translators: %s: Singular taxonomy name
226 | #: lib/Taxonomy_Labels.php:121
227 | msgid "Update %s"
228 | msgstr "%s aktualisieren"
229 |
230 | #. translators: %s: Singular taxonomy name
231 | #: lib/Taxonomy_Labels.php:144
232 | msgid "%s added."
233 | msgstr "%s hinzugefügt."
234 |
235 | #. translators: %s: Singular taxonomy name
236 | #. translators: %s: Plural taxonomy name
237 | #: lib/Taxonomy_Labels.php:146 lib/Taxonomy_Labels.php:154
238 | msgid "%s deleted."
239 | msgstr "%s gelöscht."
240 |
241 | #. translators: %s: Singular taxonomy name
242 | #: lib/Taxonomy_Labels.php:150
243 | msgid "%s not added."
244 | msgstr "%s nicht hinzugefügt."
245 |
246 | #. translators: %s: Singular taxonomy name
247 | #: lib/Taxonomy_Labels.php:152
248 | msgid "%s not updated."
249 | msgstr "%s nicht aktualisiert."
250 |
251 | #~ msgid "%s page"
252 | #~ msgstr "%s-Seite"
253 |
254 | #, fuzzy
255 | #~| msgid "All %s"
256 | #~ msgid "All %"
257 | #~ msgstr "Alle %s"
258 |
259 | #~ msgid "View %"
260 | #~ msgstr "%s ansehen"
261 |
--------------------------------------------------------------------------------
/lib/Post_Type_Labels.php:
--------------------------------------------------------------------------------
1 | post_type = $post_type;
45 | $this->name_singular = $name_singular;
46 | $this->name_plural = $name_plural;
47 | }
48 |
49 | /**
50 | * Inits hooks.
51 | */
52 | public function init() {
53 | add_filter( "post_type_labels_{$this->post_type}", function() {
54 | return (object) $this->get_labels();
55 | } );
56 |
57 | if ( is_admin() ) {
58 | // Update messages in backend.
59 | add_filter( 'post_updated_messages', [ $this, 'add_post_updated_messages' ] );
60 | }
61 | }
62 |
63 | /**
64 | * Gets labels for a post type based on singular and plural name.
65 | *
66 | * The following labels are not translated, because they don’t contain the post type name:
67 | * set_feature_image, remove_featured_image
68 | *
69 | * @link https://developer.wordpress.org/reference/functions/get_post_type_labels/
70 | *
71 | * @return array The translated labels.
72 | */
73 | public function get_labels() {
74 | return [
75 | 'name' => $this->name_plural,
76 | 'singular_name' => $this->name_singular,
77 | 'add_new' => __( 'Add New', 'mind/types' ),
78 | 'add_new_item' => sprintf(
79 | /* translators: %s: Singular post type name */
80 | __( 'Add New %s', 'mind/types' ),
81 | $this->name_singular
82 | ),
83 | 'all_items' => sprintf(
84 | /* translators: %s: Plural post type name */
85 | __( 'All %s', 'mind/types' ),
86 | $this->name_plural
87 | ),
88 | 'archives' => sprintf(
89 | /* translators: %s: Singular post type name */
90 | __( '%s Archives', 'mind/types' ),
91 | $this->name_singular
92 | ),
93 | 'attributes' => sprintf(
94 | /* translators: %s: Singular post type name */
95 | __( '%s Attributes', 'mind/types' ),
96 | $this->name_singular
97 | ),
98 | 'edit_item' => sprintf(
99 | /* translators: %s: Singular post type name */
100 | __( 'Edit %s', 'mind/types' ),
101 | $this->name_singular
102 | ),
103 | 'featured_image' => sprintf(
104 | /* translators: %s: Singular post type name */
105 | __( 'Featured Image for %s', 'mind/types' ),
106 | $this->name_singular
107 | ),
108 | 'filter_items_list' => sprintf(
109 | /* translators: %s: Plural post type name */
110 | __( 'Filter %s list', 'mind/types' ),
111 | $this->name_plural
112 | ),
113 | 'insert_into_item' => sprintf(
114 | /* translators: %s: Singular post type name */
115 | __( 'Insert into %s', 'mind/types' ),
116 | $this->name_singular
117 | ),
118 | 'items_list' => sprintf(
119 | /* translators: %s: Plural post type name */
120 | __( '%s list', 'mind/types' ),
121 | $this->name_plural
122 | ),
123 | 'items_list_navigation' => sprintf(
124 | /* translators: %s: Plural post type name */
125 | __( '%s list navigation', 'mind/types' ),
126 | $this->name_plural
127 | ),
128 | 'item_published' => sprintf(
129 | /* translators: %s: Singular post type name */
130 | __( '%s published.', 'mind/types' ),
131 | $this->name_singular
132 | ),
133 | 'item_published_privately' => sprintf(
134 | /* translators: %s: Singular post type name */
135 | __( '%s published privately.', 'mind/types' ),
136 | $this->name_singular
137 | ),
138 | 'item_reverted_to_draft' => sprintf(
139 | /* translators: %s: Singular post type name */
140 | __( '%s reverted to draft.', 'mind/types' ),
141 | $this->name_singular
142 | ),
143 | 'item_trashed' => sprintf(
144 | /* translators: %s: Singular post type name */
145 | __( '%s trashed.', 'mind/types' ),
146 | $this->name_singular
147 | ),
148 | 'item_scheduled' => sprintf(
149 | /* translators: %s: Singular post type name */
150 | __( '%s scheduled.', 'mind/types' ),
151 | $this->name_singular
152 | ),
153 | 'item_updated' => sprintf(
154 | /* translators: %s: Singular post type name */
155 | __( '%s updated.', 'mind/types' ),
156 | $this->name_singular
157 | ),
158 | 'new_item' => sprintf(
159 | /* translators: %s: Singular post type name */
160 | __( 'New %s', 'mind/types' ),
161 | $this->name_singular
162 | ),
163 | 'not_found' => sprintf(
164 | /* translators: %s: Plural post type name */
165 | __( 'No %s found.', 'mind/types' ),
166 | $this->name_plural
167 | ),
168 | 'not_found_in_trash' => sprintf(
169 | /* translators: %s: Plural post type name */
170 | __( 'No %s found in trash.', 'mind/types' ),
171 | $this->name_plural
172 | ),
173 | 'parent_item' => sprintf(
174 | /* translators: %s: Singular post type name */
175 | __( 'Parent %s', 'mind/types' ),
176 | $this->name_singular
177 | ),
178 | 'parent_item_colon' => sprintf(
179 | /* translators: %s: Singular post type name */
180 | __( 'Parent %s:', 'mind/types' ),
181 | $this->name_singular
182 | ),
183 | 'search_items' => sprintf(
184 | /* translators: %s: Plural post type name */
185 | __( 'Search %s', 'mind/types' ),
186 | $this->name_plural
187 | ),
188 | 'uploaded_to_this_item' => sprintf(
189 | /* translators: %s: Singular post type name */
190 | __( 'Uploaded to this %s', 'mind/types' ),
191 | $this->name_singular
192 | ),
193 | 'view_item' => sprintf(
194 | /* translators: %s: Singular post type name */
195 | __( 'View %s', 'mind/types' ),
196 | $this->name_singular
197 | ),
198 | 'view_items' => sprintf(
199 | /* translators: %s: Plural post type name */
200 | __( 'View %s', 'mind/types' ),
201 | $this->name_plural
202 | ),
203 | 'menu_name' => $this->name_plural,
204 | 'name_admin_bar' => $this->name_singular,
205 | ];
206 | }
207 |
208 | /**
209 | * Sets post updated messages for custom post types.
210 | *
211 | * Check out the `post_updated_messages` in wp-admin/edit-form-advanced.php.
212 | *
213 | * @param array $messages An associative array of post types and their messages.
214 | *
215 | * @return array The filtered messages.
216 | */
217 | public function add_post_updated_messages( $messages ) {
218 | if (!post_type_exists($this->post_type)) {
219 | return $messages;
220 | }
221 |
222 | global $post_id;
223 |
224 | $preview_url = get_preview_post_link( $post_id );
225 | $permalink = get_permalink( $post_id );
226 |
227 | // Preview post link.
228 | $preview_post_link_html = is_post_type_viewable( $this->post_type )
229 | ? sprintf( ' %2$s',
230 | esc_url( $preview_url ),
231 | /* translators: %s: Singular post type name */
232 | sprintf( __( 'Preview %s', 'mind/types' ), $this->name_singular )
233 | )
234 | : '';
235 |
236 | // View post link.
237 | $view_post_link_html = is_post_type_viewable( $this->post_type )
238 | ? sprintf( ' %2$s',
239 | esc_url( $permalink ),
240 | /* translators: %s: Singular post type name */
241 | sprintf( __( 'View %s', 'mind/types' ), $this->name_singular )
242 | )
243 | : '';
244 |
245 | /**
246 | * Message indices 2, 3, 5 and 9 are not handled, because they are edge cases or they would be too difficult
247 | * to reproduce.
248 | */
249 | $messages[ $this->post_type ] = [
250 | /* translators: %s: Singular post type name */
251 | 1 => sprintf( __( '%s updated.', 'mind/types' ), $this->name_singular ) . $view_post_link_html,
252 | /* translators: %s: Singular post type name */
253 | 4 => sprintf( __( '%s updated.', 'mind/types' ), $this->name_singular ),
254 | /* translators: %s: Singular post type name */
255 | 6 => sprintf( __( '%s published.', 'mind/types' ), $this->name_singular ) . $view_post_link_html,
256 | /* translators: %s: Singular post type name */
257 | 7 => sprintf( __( '%s saved.', 'mind/types' ), $this->name_singular ),
258 | /* translators: %s: Singular post type name */
259 | 8 => sprintf( __( '%s submitted.', 'mind/types' ), $this->name_singular ) . $preview_post_link_html,
260 | /* translators: %s: Singular post type name */
261 | 10 => sprintf( __( '%s draft updated.', 'mind/types' ), $this->name_singular ) . $preview_post_link_html,
262 | ];
263 |
264 | return $messages;
265 | }
266 | }
267 |
--------------------------------------------------------------------------------
/lib/Post_Type_Columns.php:
--------------------------------------------------------------------------------
1 | post_type = $post_type;
31 |
32 | foreach ( $columns as $slug => $column ) {
33 | if ( false !== $column ) {
34 | // Set defaults for thumbnail.
35 | if ( 'thumbnail' === $slug ) {
36 | $column = wp_parse_args( $column, [
37 | 'title' => __( 'Featured Image', 'mind/types' ),
38 | 'width' => 80,
39 | 'height' => 80,
40 | 'sortable' => false,
41 | ] );
42 | }
43 |
44 | // Set defaults for each field.
45 | $column = wp_parse_args( $column, [
46 | 'title' => '',
47 | 'type' => 'meta',
48 | 'transform' => null,
49 | 'sortable' => false,
50 | 'orderby' => 'meta_value',
51 | 'column_order' => 10,
52 | 'searchable' => false,
53 | ] );
54 | }
55 |
56 | $this->columns[ $slug ] = $column;
57 | }
58 | }
59 |
60 | /**
61 | * Inits hooks.
62 | */
63 | public function init() {
64 | add_filter( 'manage_edit-' . $this->post_type . '_columns', [ $this, 'columns' ] );
65 | add_filter( 'manage_edit-' . $this->post_type . '_sortable_columns', [
66 | $this,
67 | 'columns_sortable',
68 | ] );
69 | add_action( 'manage_' . $this->post_type . '_posts_custom_column', [
70 | $this,
71 | 'column_content',
72 | ], 10, 2 );
73 |
74 | if ( is_admin() ) {
75 | add_action( 'pre_get_posts', [ $this, 'search_meta_or_title' ] );
76 | add_action( 'pre_get_posts', [ $this, 'sort_by_meta' ] );
77 | }
78 | }
79 |
80 | /**
81 | * Filters columns for post list view.
82 | *
83 | * @param array $columns An array of existing columns.
84 | *
85 | * @return array Filtered array.
86 | */
87 | public function columns( $columns ) {
88 | $sorted = [];
89 | $return = [];
90 |
91 | // Move existing columns into sort array.
92 | foreach ( $columns as $key => $column ) {
93 | $sorted[ $key ] = [
94 | 'title' => $column,
95 | // The checkbox should always be first, hence the order key '-1'.
96 | 'column_order' => 'cb' === $key ? - 1 : 10,
97 | ];
98 | }
99 |
100 | // Merge in user-defined columns and settings for existing columns.
101 | foreach ( $this->columns as $key => $column ) {
102 | if ( isset( $sorted[ $key ] ) ) {
103 | // Columns can be removed when they are set to 'false'
104 | if ( false === $column ) {
105 | unset( $sorted[ $key ] );
106 | continue;
107 | }
108 |
109 | if ( ! empty( $column['title'] ) ) {
110 | $sorted[ $key ]['title'] = $column['title'];
111 | }
112 |
113 | if ( 10 !== $column['column_order'] ) {
114 | $sorted[ $key ]['column_order'] = $column['column_order'];
115 | }
116 | } else {
117 | $sorted[ $key ] = $column;
118 | }
119 | }
120 |
121 | $sorted = wp_list_sort( $sorted, 'column_order', 'ASC', true );
122 |
123 | foreach ( $sorted as $slug => $column ) {
124 | $return[ $slug ] = $column['title'];
125 | }
126 |
127 | return $return;
128 | }
129 |
130 | /**
131 | * Filters sortable columns.
132 | *
133 | * @param array $columns An array of existing columns.
134 | *
135 | * @return array Filtered array.
136 | */
137 | public function columns_sortable( $columns ) {
138 | foreach ( $this->columns as $slug => $column ) {
139 | // Remove column when it’s not sortable.
140 | if ( isset( $column['sortable'] ) && ! $column['sortable'] ) {
141 | unset( $columns[ $slug ] );
142 | continue;
143 | } elseif ( ! isset( $columns[ $slug ] ) ) {
144 | if ( ! empty( $column['type'] ) && 'meta' === $column['type'] ) {
145 | $columns[ $slug ] = $slug;
146 | }
147 | }
148 | }
149 |
150 | return $columns;
151 | }
152 |
153 | /**
154 | * Includes searchable custom fields in the search.
155 | *
156 | * @param \WP_Query $query WordPress query object.
157 | */
158 | public function sort_by_meta( \WP_Query $query ) {
159 | global $typenow;
160 | $orderby = $query->get( 'orderby' );
161 |
162 | if ( ! $query->is_main_query()
163 | || $typenow !== $this->post_type
164 | || empty( $orderby )
165 | || ! is_string( $orderby )
166 | || ! isset( $this->columns[ $orderby ] )
167 | || 'meta' !== $this->columns[ $orderby ]['type']
168 | ) {
169 | return;
170 | }
171 |
172 | $new_orderby = $this->columns[ $orderby ]['orderby'];
173 |
174 | $query->set( 'orderby', $new_orderby );
175 | $query->set( 'meta_key', $orderby );
176 | }
177 |
178 | /**
179 | * Update column contents for post list view.
180 | *
181 | * @param string $column_name The column slug.
182 | * @param int $post_id The post ID.
183 | */
184 | public function column_content( $column_name, $post_id ) {
185 | // Bail out.
186 | if ( ! array_key_exists( $column_name, $this->columns ) ) {
187 | return;
188 | }
189 |
190 | $column = $this->columns[ $column_name ];
191 |
192 | if ( 'thumbnail' === $column_name ) {
193 | $src = get_the_post_thumbnail_url( $post_id, 'thumbnail' );
194 |
195 | if ( empty( $src ) ) {
196 | return;
197 | }
198 |
199 | $styles = '';
200 |
201 | foreach ( [ 'width', 'height' ] as $attr ) {
202 | if ( isset( $column[ $attr ] ) ) {
203 | $styles .= $attr . ':' . $column[ $attr ] . 'px;';
204 | }
205 | }
206 |
207 | if ( ! empty( $styles ) ) {
208 | $styles = ' style="' . $styles . '"';
209 | }
210 |
211 | echo '
';
212 |
213 | return;
214 | }
215 |
216 | $value = '';
217 | if ( 'acf' === $column['type'] ) {
218 | $value = get_field( $column_name, $post_id );
219 | } elseif ( 'meta' === $column['type'] ) {
220 | $value = get_post_meta( $post_id, $column_name, true );
221 | } elseif ( 'image' === $column['type'] ) {
222 | $value = get_post_meta( $post_id, $column_name, true );
223 |
224 | if ( is_numeric( $value ) ) {
225 | $src = wp_get_attachment_image_src(
226 | $value,
227 | $column['image_size'] ?? 'thumbnail'
228 | );
229 |
230 | if ( $src ) {
231 | echo $this->column_content_image( $src[0], $column );
232 |
233 | return;
234 | }
235 | }
236 | } elseif ( 'custom' === $column['type'] && is_callable( $column['value'] ) ) {
237 | $value = call_user_func( $column['value'], $post_id );
238 | }
239 |
240 | if ( in_array( $column['type'], [ 'meta', 'acf' ], true )
241 | && is_callable( $column['transform'] )
242 | ) {
243 | $value = call_user_func( $column['transform'], $value, $post_id );
244 | }
245 |
246 | echo $value;
247 | }
248 |
249 | /**
250 | * Gets the HTML for the 'image' type.
251 | *
252 | * @param string $src An image source.
253 | * @param array $args An array of column arguments.
254 | *
255 | * @return string
256 | */
257 | protected function column_content_image( $src, $args ) {
258 | if ( empty( $src ) ) {
259 | return '';
260 | }
261 |
262 | $styles = 'max-width: 100%;';
263 |
264 | foreach ( [ 'width', 'height' ] as $attr ) {
265 | if ( isset( $args[ $attr ] ) ) {
266 | $styles .= $attr . ':' . esc_attr( $args[ $attr ] ) . 'px;';
267 | }
268 | }
269 |
270 | $styles = ' style="' . $styles . '"';
271 |
272 | return '
';
273 | }
274 |
275 | /**
276 | * Includes searchable custom fields in the search.
277 | *
278 | * @param \WP_Query $query WordPress query object.
279 | */
280 | public function search_meta_or_title( \WP_Query $query ) {
281 | global $typenow;
282 | $searchterm = $query->query_vars['s'];
283 |
284 | if (
285 | ! $query->is_main_query()
286 | || $typenow !== $this->post_type
287 | || empty( $searchterm )
288 | ) {
289 | return;
290 | }
291 |
292 | $meta_columns = array_filter( $this->columns, function( $column ) {
293 | return ! empty( $column ) && 'meta' === $column['type'] && $column['searchable'];
294 | } );
295 |
296 | // Bail out and use default search if no searchable meta columns are defined.
297 | if ( empty( $meta_columns ) ) {
298 | return;
299 | }
300 |
301 | $meta_query = [ 'relation' => 'OR' ];
302 |
303 | foreach ( $meta_columns as $key => $column ) {
304 | $meta_query[] = [
305 | 'key' => $key,
306 | 'value' => $searchterm,
307 | 'compare' => 'LIKE',
308 | ];
309 | }
310 |
311 | $query->set( 'meta_query', $meta_query );
312 |
313 | /**
314 | * Remove search parameter.
315 | *
316 | * The search parameter needs to be removed from the query, otherwise posts can’t be found.
317 | * A disadvantage of this is that all the logic in \WP_Query::parse_search() is lost.
318 | *
319 | * @see \WP_Query::parse_search()
320 | */
321 | $query->set( 's', '' );
322 |
323 | // Fixes the "Search results for …" label in the post list table.
324 | add_filter( 'get_search_query', function( $query ) use ( $searchterm ) {
325 | return $searchterm;
326 | } );
327 |
328 | /**
329 | * Update meta query to include search for title.
330 | *
331 | * This logic is taken from a StackOverflow answer:
332 | *
333 | * @link https://wordpress.stackexchange.com/a/178492/22506
334 | */
335 | add_filter( 'get_meta_sql', function( $sql ) use ( $searchterm ) {
336 | global $wpdb;
337 |
338 | // Run only once.
339 | static $nr = 0;
340 |
341 | if ( 0 != $nr ++ ) {
342 | return $sql;
343 | }
344 |
345 | // Modify the WHERE part.
346 | $sql['where'] = sprintf(
347 | " AND ( %s OR %s ) ",
348 | $wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $searchterm ),
349 | mb_substr( $sql['where'], 5 )
350 | );
351 |
352 | return $sql;
353 | } );
354 | }
355 | }
356 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Types
2 |
3 | Custom Post Types and Taxonomy helper classes for WordPress projects.
4 |
5 | - Register Custom Post Types and Taxonomies through an array notation. Labels will be set accordingly. Currently, English, German and Dutch are supported.
6 | - Change the query arguments for posts in the front- and backend via a list of arguments, e.g. to set a custom post order wit the [`query`](#query) option.
7 | - Change the admin columns for posts in the backend via a list of arguments.
8 | - Set a specific page as the archive page for a custom post type with the [`page_for_archive`](#page_for_archive) option.
9 | - Set post slugs dynamically when posts are saved.
10 |
11 | ## Table of Contents
12 |
13 |
14 |
15 | - [Table of Contents](#table-of-contents)
16 | - [Installation](#installation)
17 | - [Register post types](#register-post-types)
18 | - [query](#query)
19 | - [admin_columns](#admin_columns)
20 | - [Type](#type)
21 | - [The `meta` and `acf` types](#the-meta-and-acf-types)
22 | - [The `thumbnail` type](#the-thumbnail-type)
23 | - [The `image` type](#the-image-type)
24 | - [Existing columns and column order](#existing-columns-and-column-order)
25 | - [page_for_archive](#page_for_archive)
26 | - [is_singular_public](#is_singular_public)
27 | - [customizer_section](#customizer_section)
28 | - [show_post_state](#show_post_state)
29 | - [Use page in template](#use-page-in-template)
30 | - [Update existing post types](#update-existing-post-types)
31 | - [Change settings for a post type](#change-settings-for-a-post-type)
32 | - [Change post type support](#change-post-type-support)
33 | - [Rename a post type](#rename-a-post-type)
34 | - [Change admin column settings for existing post type](#change-admin-column-settings-for-existing-post-type)
35 | - [Register taxonomies](#register-taxonomies)
36 | - [Update existing taxonomies](#update-existing-taxonomies)
37 | - [Change settings for a taxonomy](#change-settings-for-a-taxonomy)
38 | - [Rename a taxonomy](#rename-a-taxonomy)
39 | - [Unregister taxonomies](#unregister-taxonomies)
40 | - [Customize a post slug](#customize-a-post-slug)
41 | - [Support](#support)
42 |
43 |
44 |
45 | ## Installation
46 |
47 | You can install the package via Composer:
48 |
49 | ```bash
50 | composer require mindkomm/types
51 | ```
52 |
53 | ## Register post types
54 |
55 | ```php
56 | [
67 | 'name_singular' => 'Example',
68 | 'name_plural' => 'Examples',
69 | 'args' => [
70 | /**
71 | * For a list of possible menu-icons see
72 | * https://developer.wordpress.org/resource/dashicons/
73 | */
74 | 'menu_icon' => 'dashicons-building',
75 | 'hierarchical' => false,
76 | 'has_archive' => false,
77 | 'supports' => [
78 | 'title',
79 | 'editor',
80 | ],
81 | // Whether post is accessible in the frontend
82 | 'public' => false,
83 | ],
84 | 'admin_columns' => [
85 | 'date' => false,
86 | ],
87 | ],
88 | ] );
89 | } );
90 | ```
91 |
92 | The `args` parameter is used for the arguments that are passed to `register_post_type`. The `name_singular` and `name_plural` parameters are used for the generating the labels in the backend.
93 |
94 | You can use more options:
95 |
96 | ### query
97 |
98 | Arguments that are used for querying this post type in the back- and frontend. You can use this to define the sort order. Here’s an example for a post type `event`, where we want to order the posts by the value of a custom field named `date_start`.
99 |
100 | ```php
101 | 'query' => [
102 | 'meta_key' => 'date_start',
103 | 'orderby' => 'meta_value_num',
104 | 'order' => 'DESC',
105 | ],
106 | ```
107 |
108 | If you want to have different queries for the front- and the backend, you can use separate `frontend` and `backend` keys:
109 |
110 | ```php
111 | 'query' => [
112 | 'frontend' => [
113 | 'meta_key' => 'date_start',
114 | 'orderby' => 'meta_value_num',
115 | 'order' => 'ASC',
116 | ],
117 | 'backend' => [
118 | 'meta_key' => 'date_start',
119 | 'orderby' => 'meta_value_num',
120 | 'order' => 'DESC',
121 | ],
122 | ],
123 | ```
124 |
125 | If you only use one key and omit the other, then the query will only be applied to your choice.
126 |
127 | ### admin_columns
128 |
129 | Arguments that are used to add and remove admin columns in the backend. Pass an associative array of column names with arguments.
130 |
131 | Here’s an example for a Custom Post Type `event`.
132 |
133 | ```php
134 | 'admin_columns' => [
135 | 'date' => false,
136 | 'date_start' => [
137 | 'title' => 'Start Date',
138 | 'transform' => function( $value ) {
139 | return date_i18n(
140 | get_option( 'date_format' ),
141 | DateTime::createFromFormat( 'Ymd', $value )->getTimeStamp()
142 | );
143 | },
144 | ],
145 | 'location' => [
146 | 'title' => 'Location',
147 | 'sortable' => true,
148 | 'searchable' => true,
149 | 'transform' => function( $post_id ) {
150 | return get_the_title( $post_id );
151 | },
152 | ],
153 | 'width' => [
154 | 'title' => 'Width',
155 | 'sortable' => true,
156 | 'orderby' => 'meta_value_num',
157 | ],
158 | ],
159 | ```
160 |
161 | These are the possible arguments:
162 |
163 | - **title** – *(string)* The title to use for the column. Default empty.
164 | - **transform** – *(callable)* The function to use on the value that is displayed. The function defined here will get a `$value` parameter that you can transform. E.g., if you have a post ID saved in post meta, you could display the post’s title. Default `null`.
165 | - **type** – *(string)* The type for the column. One of `meta`, `acf`, `thumbnail`, `image` or `custom`. Default `meta`.
166 | - **sortable** – *(bool)* Whether the column is sortable. Default `false`.
167 | - **orderby** – *(string)* What to order by when the `sortable` argument is used. You don’t need to provide a `meta_key` parameter, because it is automatically set. Default `meta_value`.
168 | - **searchable** – *(bool)* Whether the column is searchable. Will include the meta values when searching the post list. Only applied if using the default type `meta`. Default `false`.
169 | - **column_order** – *(int)* An order number to sort by. You can use this to change the order of your columns. Default `10`.
170 |
171 | If you need more possibilities for defining admin columns you could use the fantastic [Admin Columns](https://www.admincolumns.com/) plugin.
172 |
173 | #### Type
174 |
175 | The `type` argument defines how your column is interpreted. The following types exist:
176 |
177 | - `meta`
178 | - `acf`
179 | - `thumbnail`
180 | - `image`
181 | - `custom`
182 |
183 | #### The `meta` and `acf` types
184 |
185 | With the `meta` type, the column name is the name of the meta field you want to display.
186 |
187 | You can also use `acf` as a type you use Advanced Custom Fields and want to apply its filters to the value.
188 |
189 | #### The `thumbnail` type
190 |
191 | Use this key to display the featured image thumbnail for a post.
192 |
193 | ```php
194 | 'location' => [
195 | 'thumbnail' => true,
196 | ],
197 | ```
198 |
199 | You can also set the width and height. The defaults are `80` × `80` pixels.
200 |
201 | ```php
202 | 'location' => [
203 | 'thumbnail' => [
204 | 'width' => 100,
205 | 'height' => 100,
206 | ],
207 | ],
208 | ```
209 |
210 | #### The `image` type
211 |
212 | The `type` allows you to display an image other than the featured image. This type will also use the key of the column to get an **attachment ID** from the post’s meta values.
213 |
214 | ```php
215 | 'admin_columns' => [
216 | 'profile_image' => [
217 | 'title' => 'Profile image',
218 | 'type' => 'image',
219 | ],
220 | ],
221 | ```
222 |
223 | By default, it will display the `thumbnail` size. If you want to request a different size, use the `image_size` parameter.
224 |
225 | ```php
226 | 'admin_columns' => [
227 | 'profile_image' => [
228 | 'title' => 'Profile image',
229 | 'type' => 'image',
230 | 'image_size' => 'medium',
231 | ],
232 | ],
233 | ```
234 |
235 | And if you want to restrict the width and the height of the image, you can provide pixel values for `width` and `height`.
236 |
237 | ```php
238 | 'admin_columns' => [
239 | 'profile_image' => [
240 | 'title' => 'Profile image',
241 | 'type' => 'image',
242 | 'width' => 100,
243 | 'height' => 100,
244 | ],
245 | ],
246 | ```
247 |
248 | #### The `custom` type
249 |
250 | If you want to do something custom, you can use the `custom` type. If you use the `custom` type, you need to provide a `value`, which is a callback function that receives the post’s ID as a single parameter.
251 |
252 | In this example, we call a function that extracts an attribute value from a certain block of the post.
253 |
254 | ```php
255 | 'email' => [
256 | 'title' => __( 'Email', 'theme-module-teammember' ),
257 | 'type' => 'custom',
258 | 'value' => function( $post_id ) {
259 | return $this->get_block_attribute( $post_id, 'email' );
260 | },
261 | ],
262 | ```
263 |
264 | #### Existing columns and column order
265 |
266 | You can also update or hide existing columns. Existing columns can be updated with the `title` and the `column_order` argument.
267 |
268 | If you want to the change the title of an existing column, use the `title` attribute.
269 |
270 | ```php
271 | 'admin_columns' => [
272 | 'title' => [
273 | 'title' => 'Event title',
274 | ],
275 | ],
276 | ```
277 |
278 | If you want to move the column, you can use the `column_order` argument. In this example, we would move the `date` column to the end.
279 |
280 | ```php
281 | 'admin_columns' => [
282 | 'date' => [
283 | 'column_order' => 100,
284 | ],
285 | ],
286 | ```
287 |
288 | The default order is `10`. So if you wanted to move a column like the thumbnail to the start, you could use `5`.
289 |
290 | ```php
291 | 'admin_columns' => [
292 | 'thumbnail' => [
293 | 'column_order' => 5,
294 | ],
295 | ],
296 | ```
297 |
298 | To hide an existing column, you can use `false`.
299 |
300 | ```php
301 | 'admin_columns' => [
302 | 'date' => false,
303 | ],
304 | ```
305 |
306 | ### page_for_archive
307 |
308 | The `page_for_archive` option allows you to set a specific page as the archive page for a custom post type:
309 |
310 | ```php
311 | 'event' => [
312 | 'args' => [
313 | 'public' => true,
314 | ],
315 | 'page_for_archive' => [
316 | 'post_id' => get_option( 'page_for_event' ),
317 | 'is_singular_public' => false,
318 | ],
319 | ],
320 | ```
321 |
322 | In this example, the ID for the page that’s saved in the `page_for_event` option will act as the archive page for the `event` post type.
323 |
324 | You need to **flush your permalinks** whenever you make changes to this option.
325 |
326 | Behind the curtains, Types uses the `has_archive` option when registering a post type and sets the slug of the page you passed in the `page_for_archive` option.
327 |
328 | #### is_singular_public
329 |
330 | The `is_singular_public` option allows you to set, whether singular templates for this post type should be accessible in the frontend. Singular template requests will then be redirected to the archive page. We can’t use the `public` or `publicly_queryable` option for this, because then the archive page wouldn’t work either.
331 |
332 | #### customizer_section
333 |
334 | If you want Types to register an option to select the page you want to use as your archive in the Customizer, you can use the `customizer_section` argument:
335 |
336 | ```php
337 | 'event' => [
338 | 'page_for_archive' => [
339 | 'post_id' => get_option( 'page_for_event' ),
340 | 'customizer_section' => 'event',
341 | ],
342 | ],
343 | ```
344 |
345 | With `customizer_section`, you can define in which Customizer section the option should be displayed. This needs to be an existing section. This way, you can decide yourself whether you want to have a separate Customizer section for each custom post type, or whether you want to list all of your custom post type pages in the same section.
346 |
347 | #### show_post_state
348 |
349 | Types will display a post state in the pages overview for the page that you selected. If you want to disable this functionality, use the `show_post_state` option.
350 |
351 | ```php
352 | 'event' => [
353 | 'page_for_archive' => [
354 | 'post_id' => get_option( 'page_for_event' ),
355 | 'show_post_state' => false,
356 | ],
357 | ],
358 | ```
359 |
360 | #### Use page in template
361 |
362 | To make use of that page, you will use it in your archive page where you can now use your page as the main post.
363 |
364 | **archive-event.php**
365 |
366 | ```php
367 | $post = get_post( get_option( 'page_for_event' ) );
368 | ```
369 |
370 | ## Update existing post types
371 |
372 | ### Change settings for a post type
373 |
374 | Use the `update()` function to change the settings for an existing post type. Here’s an example for changing the settings for posts to make them not directly accessible in the frontend.
375 |
376 | **functions.php**
377 |
378 | ```php
379 | Types\Post_Type::update( [
380 | 'post' => [
381 | 'args' => [
382 | 'public' => false,
383 | 'show_ui' => true,
384 | 'show_in_nav_menus' => true,
385 | ],
386 | 'admin_columns' => [
387 | 'date' => false,
388 | ],
389 | ],
390 | ] );
391 | ```
392 |
393 | The `update()` function accepts an associative array of post types and their arguments. Make sure you use this function before the `init` hook.
394 |
395 | ### Change post type support
396 |
397 | Please be aware that it’s not possible to change post type support features through the `update()` function. To remove support for an existing feature, you will have to use the `remove_post_type_support` function.
398 |
399 | ```php
400 | add_action( 'init', function() {
401 | remove_post_type_support( 'post', 'thumbnail' );
402 | } );
403 | ```
404 |
405 | In the same manner, if you want to add features, you should do it through the `add_post_type_support` function:
406 |
407 | ```php
408 | add_post_type_support( 'page', 'excerpt' );
409 | ```
410 |
411 | ### Rename a post type
412 |
413 | Sometimes you might want to rename an existing post type to better reflect what it’s used for.
414 |
415 | **functions.php**
416 |
417 | ```php
418 | Types\Post_Type::rename( 'post', 'Beispiel', 'Beispiele' );
419 | ```
420 |
421 | The `rename()` function accepts a post type as the first parameter, the new singular name of the post type as a second parameter and the plural name of the post type as a third parameter. If you omit the third parameter, the second parameter will be used as the plural form instead. Make sure you use this function before the `init` hook.
422 |
423 | This is practically a shorthand function for:
424 |
425 | ```php
426 | Types\Post_Type::update( [
427 | 'post' => [
428 | 'name_singular' => 'Beispiel',
429 | 'name_plural' => 'Beispiele',
430 | ],
431 | ] );
432 | ```
433 |
434 | If you only want to rename one of the labels, e.g. the menu label, you can use the `post_type_labels_{$post_type}` filter. Here’s an example for changing the menu name for posts:
435 |
436 | ```php
437 | add_filter( 'post_type_labels_post', function( $labels ) {
438 | $labels->menu_name = 'Aktuelles';
439 |
440 | return $labels;
441 | }, 11 );
442 | ```
443 |
444 | ## Change admin column settings for existing post type
445 |
446 | To change the admin column settings for existing post types like `post` or `page`, you can use the `admin_columns()` function, which accepts an associative array of post types and their admin column settings.
447 |
448 | Here’s an example that disables the date, comments and author columns and adds a thumbnail instead:
449 |
450 | ```php
451 | Types\Post_Type::admin_columns( [
452 | 'page' => [
453 | 'date' => false,
454 | 'comments' => false,
455 | 'author' => false,
456 | 'thumbnail' => [
457 | 'width' => 80,
458 | 'height' => 80,
459 | ],
460 | ],
461 | ] );
462 | ```
463 |
464 | ## Register taxonomies
465 |
466 | ```php
467 | [
480 | 'name_singular' => 'Example Category',
481 | 'name_plural' => 'Example Categories',
482 | // For which post types do you want to register this taxonomy?
483 | 'for_post_types' => [ 'example' ],
484 | 'args' => [
485 | // Hide the meta box from the edit view
486 | // 'meta_box_cb' => false,
487 | //
488 | // Make it selectable in the navigation menus
489 | // 'show_in_nav_menus' => true,
490 | ],
491 | ],
492 | ] );
493 | } );
494 | ```
495 |
496 | The `args` parameter is used for the arguments that are passed to `register_taxonomy`. Use the `for_post_types` parameter to assign taxonomies to certain post types. The `name_singular` and `name_plural` parameters are used for the generating the labels in the backend.
497 |
498 | ## Update existing taxonomies
499 |
500 | ### Change settings for a taxonomy
501 |
502 | Use the `update()` function to change the settings for an existing taxonomy. Here’s an example for changing the settings for categories to make them not directly accessible in the frontend.
503 |
504 | **functions.php**
505 |
506 | ```php
507 |
508 | Types\Taxonomy::update( [
509 | 'category' => [
510 | 'args' => [
511 | 'public' => false,
512 | 'show_ui' => true,
513 | 'show_in_nav_menus' => true,
514 | ],
515 | ],
516 | ] );
517 | ```
518 |
519 | The `update()` function accepts an associative array of taxonomies and their arguments. Make sure you use this function before the `init` hook.
520 |
521 | ### Rename a taxonomy
522 |
523 | Sometimes you might want to rename an existing taxonomy to better reflect what it’s used for.
524 |
525 | **functions.php**
526 |
527 | ```php
528 | Types\Taxonomy::rename( 'category', 'Topic', 'Topics' );
529 | ```
530 |
531 | The `rename()` function accepts a taxonomy as the first parameter, the new singular name of the taxonomy as a second parameter and the plural name of the taxonomy as a third parameter. If you omit the third parameter, the second parameter will be used as the plural form instead. Make sure you use this function before the `init` hook.
532 |
533 | This is practically a shorthand function for:
534 |
535 | ```php
536 | Types\Taxonomy::update( [
537 | 'category' => [
538 | 'name_singular' => 'Topic',
539 | 'name_plural' => 'Topics,
540 | ],
541 | ] );
542 | ```
543 |
544 | If you only want to rename one of the labels, e.g. the menu label, you can use the `taxonomy_labels_{$post_type}` filter. Here’s an example for changing the menu name for posts:
545 |
546 | ```php
547 | add_filter( 'taxonomy_labels_category', function( $labels ) {
548 | $labels->menu_name = 'Topics';
549 |
550 | return $labels;
551 | }, 11 );
552 | ```
553 |
554 | ### Unregister taxonomies
555 |
556 | If you want to unregister taxonomies for certain post types, it’s best to do it through the `unregister_taxonomy_for_object_type()` function.
557 |
558 | ```php
559 | /**
560 | * Unregister post categories and post tags.
561 | */
562 | add_action( 'init', function() {
563 | unregister_taxonomy_for_object_type( 'category', 'post' );
564 | unregister_taxonomy_for_object_type( 'post_tag', 'post' );
565 | } );
566 | ```
567 |
568 | ## Customize a post slug
569 |
570 | Sometimes you want to overwrite the post slug when a post is saved. Possible use cases:
571 |
572 | - Common post duplication plugin often only add `-copy` or `-2` as a suffix to the post slug. You want to use your own pattern.
573 | - Multiple posts have the same name, but differ in the meta data they display. For example, event posts could have a different date. You want to add the date of the event to the post slug automatically.
574 |
575 | To initalize, you’ll need to create an instance of `Post_Slug` and call the `init()` function:
576 |
577 | ```php
578 | $post_slugs = new Types\Post_Slug();
579 | $post_slugs->init();
580 | ```
581 |
582 | Here’s an example for a custom post slug for a post type `course`, where you want the permalink to be built from the post title. In this scenario, the post title would be a course number.
583 |
584 | ```php
585 | $post_slugs = new Types\Post_Slug();
586 | $post_slugs->init();
587 |
588 | $post_slugs->register( [
589 | 'course' => function( $post_slug, $post_data, $post_id ) {
590 | return $post_data['post_title'];
591 | },
592 | ] );
593 | ```
594 |
595 | You don’t have to use `sanitize_title` in the callback, because the class uses that function internally.
596 |
597 | Here’s another example for the event post mentioned earlier:
598 |
599 | ```php
600 | $post_slugs->register_suffix_date( [
601 | 'event' => [
602 | 'meta_key' => 'date_start',
603 | ],
604 | ] );
605 | ```
606 |
607 | The `register_suffix_date` function is a special function that makes it easier to append a date taken from a post’s meta data and append it to the slug. The function takes an associative array of post types and their args for the function:
608 |
609 | - **meta_key** – Used to define the name of the meta key that is used. Default `date_start`.
610 | - **input_format** – Defines the date format of the meta value. Default `Ymd`.
611 | - **output_format** – Defines the output date format that should be used for the suffix. Default `Y-m-d`.
612 |
613 | ## Support
614 |
615 | This is a library that we use at MIND to develop WordPress themes. You’re free to use it, but currently, we don’t provide any support.
616 |
--------------------------------------------------------------------------------