├── .gitattributes
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── composer.json
└── src
└── CPT.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | /examples export-ignore
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.phar
3 | composer.lock
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ##### v1.4
4 | * fix error with taxonomy arrays when generating columns
5 | * run `custom_populate_columns` callbacks using `call_user_func_array()`
6 | * add post updated messages
7 | * add flush method
8 |
9 | ##### v1.3.3
10 | * add check if exisiting_taxonomies is an array
11 |
12 | ##### v1.3.2
13 | * fix register taxonomies exisiting taxonomies after post type is regitered
14 | * fix `add_admin_columns` to work with 3rd party plugins
15 | * capital P dangit
16 |
17 | ##### v1.3.1
18 | * register taxonomies before post type to fix issues with taxonomy permalinks
19 |
20 | ##### v1.3.0
21 | * fix translation issues
22 | * new method to set custom textdomain with `set_textdomain()`
23 |
24 | ##### v1.2.4
25 | * add check if `$filter` array is empty
26 |
27 | ##### v1.2.3
28 | * add array check for `$this->taxonomy_settings`
29 |
30 | ##### v1.2.2
31 | * fix issues when registering taxonomy across multiple post type
32 | * remove wrapper function `options_merge`
33 |
34 | ##### v1.2.1
35 | * reduce the defaults within the class
36 | * replace contents of `options_merge` function with `array_replace_recursive`
37 |
38 | ##### v1.2.0
39 | * allow taxonomies to be sorted with the `sortable()` method
40 | * use of `.gitattributes` to make package lighter when deploying for production.
41 |
42 | ##### v1.1.0
43 | * make repository a composer package
44 |
45 | ##### v1.0.2
46 | * ability to use dashicons with `menu_icon()` method
47 | * removed old custom icon functions
48 |
49 | ##### v1.0.1
50 | * fixed issue with registering taxonomies
51 | * fixed issue with options merge, now accepts boolean
52 | * register_taxonomy method can now register exisiting taxonomies to post type
53 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 jjgrainger
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **N.B** I've released an updated version of the project to a new repository, [PostTypes](https://github.com/jjgrainger/PostTypes).
2 |
3 | # WP Custom Post Type Class v1.4
4 |
5 | [](https://packagist.org/packages/jjgrainger/wp-custom-post-type-class) [](https://packagist.org/packages/jjgrainger/wp-custom-post-type-class) [](https://packagist.org/packages/jjgrainger/wp-custom-post-type-class)
6 |
7 | > A single class to help you build more advanced custom post types quickly.
8 |
9 | ## Installation
10 |
11 | #### Install with Composer
12 |
13 | Add the package to your projects `composer.json` file. Visit [getcomposer.org](http://getcomposer.org/) more information.
14 |
15 | ```json
16 | {
17 | "require": {
18 | "jjgrainger/wp-custom-post-type-class": "dev-master"
19 | }
20 | }
21 | ```
22 |
23 | #### Install Manually
24 |
25 | Download and include the class file into your themes `functions.php` like so:
26 |
27 | ```php
28 | include_once('CPT.php');
29 | ```
30 |
31 | and your ready to roll!
32 |
33 | ## Creating a new Custom Post type
34 |
35 | To create the post type simply create a new object
36 |
37 | ```php
38 | $books = new CPT('book');
39 | ```
40 |
41 | The first parameter is the post type name and is required. ideally the post type name is all lowercase and words separated with an underscore `_`.
42 |
43 | to be specific about other post types names you can pass an associative array:
44 |
45 | `post_type_name` - the name of post type (singular, lowercase, underscores)
46 |
47 | `singular` - the singular label of the post type (Book, Person)
48 |
49 | `plural` - the plural of the post type (Books, People)
50 |
51 | `slug` - the permalink slug for the post type (plural, lowercase, hyphens)
52 |
53 | you pass these names through the first parameter as an array like so:
54 |
55 | ```php
56 | $people = new CPT(array(
57 | 'post_type_name' => 'person',
58 | 'singular' => 'Person',
59 | 'plural' => 'People',
60 | 'slug' => 'people'
61 | ));
62 | ```
63 |
64 | The optional second parameter is the arguments for the post_type.
65 | see [WordPress codex](http://codex.wordpress.org/Function_Reference/register_post_type#Parameters) for available options.
66 |
67 | The Class uses the WordPress defaults where possible.
68 |
69 | To override the default options simply pass an array of options as the second parameter. Not all options have to be passed just the ones you want to add/override like so:
70 |
71 | ```php
72 | $books = new CPT('book', array(
73 | 'supports' => array('title', 'editor', 'thumbnail', 'comments')
74 | ));
75 | ```
76 |
77 | See the [WordPress codex](http://codex.wordpress.org/Function_Reference/register_post_type#Parameters) for all available options.
78 |
79 | ## Existing Post Types
80 |
81 | To work with exisiting post types, simply pass the post type name into the class constructor
82 |
83 | ```php
84 | $blog = new CPT('post');
85 | ```
86 |
87 | ## Adding Taxonomies
88 |
89 | You can add taxonomies easily using the `register_taxonomy()` method like so:
90 |
91 | ```php
92 | $books->register_taxonomy('genres');
93 | ```
94 |
95 | this method accepts two arguments, names and options. The taxonomy name is required and can be string (the taxonomy name), or an array of names following same format as post types:
96 |
97 | ```php
98 | $books->register_taxonomy(array(
99 | 'taxonomy_name' => 'genre',
100 | 'singular' => 'Genre',
101 | 'plural' => 'Genres',
102 | 'slug' => 'genre'
103 | ));
104 | ```
105 |
106 | Again options can be passed optionally as an array. see the [WordPress codex](http://codex.wordpress.org/Function_Reference/register_taxonomy#Parameters) for all possible options.
107 |
108 | ### Existing Taxonomies
109 |
110 | You can add exisiting taxonomies to the post type by passing the taxonomy name through the `register_taxonomy` method. You will only need to specify the options for the custom taxonomy **once**, when its first registered.
111 |
112 | ## Admin Edit Screen
113 |
114 | ### Filters
115 |
116 | When you register a taxonomy it is *automagically* added to the admin edit screen as a filter and a column.
117 |
118 | You can define what filters you want to appear by using the `filters()` method:
119 |
120 | ```php
121 | $books->filters(array('genre'));
122 | ```
123 |
124 | By passing an array of taxonomy names you can choose the filters that appear and the order they appear in. If you pass an empty array, no drop down filters will appear on the admin edit screen.
125 |
126 | ### Columns
127 |
128 | The Class has a number of methods to help you modify the admin columns.
129 | Taxonomies registered with this class are automagically added to the admin edit screen as columns.
130 |
131 | You can add your own custom columns to include what ever value you want, for example with our books post type we will add custom fields for a price and rating.
132 |
133 | This class doesn't have any methods for adding custom fields as [Advanced Custom Fields (ACF)](http://advancedcustomfields.com) is way more awesome than anything this class could do!
134 |
135 | You can define what columns you want to appear on the admin edit screen with the `columns()` method by passing an array like so:
136 |
137 | ```php
138 | $books->columns(array(
139 | 'cb' => '',
140 | 'title' => __('Title'),
141 | 'genre' => __('Genres'),
142 | 'price' => __('Price'),
143 | 'rating' => __('Rating'),
144 | 'date' => __('Date')
145 | ));
146 | ```
147 |
148 | The key defines the name of the column, the value is the label that appears for that column. The following column names are *automagically* populated by the class:
149 |
150 | - any taxonomy registered through the object
151 | - `cb` the checkbox for bulk editing
152 | - `title` the post title with the edit link
153 | - `author` the post author
154 | - `post_id` the posts id
155 | - `icon` the posts thumbnail
156 |
157 |
158 | #### Populating Columns
159 |
160 | You will need to create a function to populate a column that isn't *automagically* populated.
161 |
162 | You do so with the `populate_column()` method like so:
163 |
164 | ```php
165 | $books->populate_column('column_name', function($column, $post) {
166 |
167 | // your code goes here…
168 |
169 | });
170 | ```
171 |
172 | so we can populate our price column like so:
173 |
174 | ```php
175 | $books->populate_column('price', function($column, $post) {
176 |
177 | echo "£" . get_field('price'); // ACF get_field() function
178 |
179 | });
180 | ```
181 |
182 | The method will pass two variables into the function:
183 |
184 | * `$column` - The column name (not the label)
185 | * `$post` - The current post object
186 |
187 | These are passed to help you populate the column appropriately.
188 |
189 | #### Sorting Columns
190 |
191 | If it makes sense that column should be sortable by ascending/descending you can define custom sortable columns like so:
192 |
193 | ```php
194 | $books->sortable(array(
195 | 'column_name' => array('meta_key', true)
196 | ));
197 | ```
198 |
199 | The `true/false` is used to define whether the meta value is a string or integer,
200 | reason being is that if numbers are ordered as a string, numbers such as:
201 |
202 | 1, 3, 5, 11, 14, 21, 33
203 |
204 | Would be ordered as:
205 |
206 | 1, 11, 14, 21, 3, 33, 5
207 |
208 | By adding the option true value the values will be sorted as integers, if false or undefined, the class will sort columns as string.
209 |
210 | so for our books example you will use:
211 |
212 | ```php
213 | $books->sortable(array(
214 | 'price' => array('price', true),
215 | 'rating' => array('rating', true)
216 | ));
217 | ```
218 |
219 | ### Menu Icons
220 |
221 | #### Dashicons
222 |
223 | With WordPress 3.8 comes [dashicons](https://developer.wordpress.org/resource/dashicons/) an icon font you can use with your custom post types. To use simply pass the icon name through the `menu_icon()` method like so:
224 |
225 | ```php
226 | $books->menu_icon("dashicons-book-alt");
227 | ```
228 |
229 | For a full list of icons and the class names to use visit [https://developer.wordpress.org/resource/dashicons/](https://developer.wordpress.org/resource/dashicons/)
230 |
231 | ### Translation
232 |
233 | The class is setup for translation, but if you need to set your own textdomain to work with your theme or plugin use the `set_textdomain()` method:
234 |
235 | ```php
236 | $books->set_textdomain('your-textdomain');
237 | ```
238 |
239 | ### Flush Rewrite Rules
240 |
241 | You can programmatically recreate the sites rewrite rules with the `flush()` method.
242 | This is an expensive operation and should be used with caution, see [codex](https://codex.wordpress.org/Function_Reference/flush_rewrite_rules) for more.
243 |
244 | ```php
245 | $books->flush();
246 | ```
247 |
248 | ## Notes
249 |
250 | * The class has no methods for making custom fields for post types, use [Advanced Custom Fields](http://advancedcustomfields.com)
251 | * The books example used in the README.md can be found in the [books-post-type.php](examples/books-post-type.php)
252 | * Licensed under the [MIT License](https://github.com/jjgrainger/wp-custom-post-type-class/blob/master/LICENSE)
253 | * Maintained under the [Semantic Versioning Guide](http://semver.org)
254 |
255 | ## Author
256 |
257 | **Joe Grainger**
258 | * [http://jjgrainger.co.uk](http://jjgrainger.co.uk)
259 | * [http://twitter.com/jjgrainger](http://twitter.com/jjgrainger)
260 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jjgrainger/wp-custom-post-type-class",
3 | "description": "A single class to help you build more advanced custom post types quickly.",
4 | "homepage": "https://github.com/jjgrainger/wp-custom-post-type-class",
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Joe Grainger",
9 | "email": "hello@joegrainger.co.uk",
10 | "homepage": "http://jjgrainger.co.uk"
11 | }
12 | ],
13 | "minimum-stability": "dev",
14 | "require": {
15 | "php": ">=5.3.0"
16 | },
17 | "autoload": {
18 | "psr-0": { "CPT": "src/" }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/CPT.php:
--------------------------------------------------------------------------------
1 | post_type_name = $post_type_names['post_type_name'];
134 |
135 | // Cycle through possible names.
136 | foreach ( $names as $name ) {
137 |
138 | // If the name has been set by user.
139 | if ( isset( $post_type_names[ $name ] ) ) {
140 |
141 | // Use the user setting
142 | $this->$name = $post_type_names[ $name ];
143 |
144 | // Else generate the name.
145 | } else {
146 |
147 | // define the method to be used
148 | $method = 'get_' . $name;
149 |
150 | // Generate the name
151 | $this->$name = $this->$method();
152 | }
153 | }
154 |
155 | // Else the post type name is only supplied.
156 | } else {
157 |
158 | // Apply to post type name.
159 | $this->post_type_name = $post_type_names;
160 |
161 | // Set the slug name.
162 | $this->slug = $this->get_slug();
163 |
164 | // Set the plural name label.
165 | $this->plural = $this->get_plural();
166 |
167 | // Set the singular name label.
168 | $this->singular = $this->get_singular();
169 | }
170 |
171 | // Set the user submitted options to the object.
172 | $this->options = $options;
173 |
174 | // Register taxonomies.
175 | $this->add_action( 'init', array( &$this, 'register_taxonomies' ) );
176 |
177 | // Register the post type.
178 | $this->add_action( 'init', array( &$this, 'register_post_type' ) );
179 |
180 | // Register exisiting taxonomies.
181 | $this->add_action( 'init', array( &$this, 'register_exisiting_taxonomies' ) );
182 |
183 | // Add taxonomy to admin edit columns.
184 | $this->add_filter( 'manage_edit-' . $this->post_type_name . '_columns', array( &$this, 'add_admin_columns' ) );
185 |
186 | // Populate the taxonomy columns with the posts terms.
187 | $this->add_action( 'manage_' . $this->post_type_name . '_posts_custom_column', array( &$this, 'populate_admin_columns' ), 10, 2 );
188 |
189 | // Add filter select option to admin edit.
190 | $this->add_action( 'restrict_manage_posts', array( &$this, 'add_taxonomy_filters' ) );
191 |
192 | // rewrite post update messages
193 | $this->add_filter( 'post_updated_messages', array( &$this, 'updated_messages' ) );
194 | $this->add_filter( 'bulk_post_updated_messages', array( &$this, 'bulk_updated_messages' ), 10, 2 );
195 | }
196 |
197 | /**
198 | * Get
199 | *
200 | * Helper function to get an object variable.
201 | *
202 | * @param string $var The variable you would like to retrieve.
203 | * @return mixed Returns the value on success, boolean false whe it fails.
204 | */
205 | function get( $var ) {
206 |
207 | // If the variable exists.
208 | if ( $this->$var ) {
209 |
210 | // On success return the value.
211 | return $this->$var;
212 |
213 | } else {
214 |
215 | // on fail return false
216 | return false;
217 | }
218 | }
219 |
220 | /**
221 | * Set
222 | *
223 | * Helper function used to set an object variable. Can overwrite existsing
224 | * variables or create new ones. Cannot overwrite reserved variables.
225 | *
226 | * @param mixed $var The variable you would like to create/overwrite.
227 | * @param mixed $value The value you would like to set to the variable.
228 | */
229 | function set( $var, $value ) {
230 |
231 | // An array of reserved variables that cannot be overwritten.
232 | $reserved = array(
233 | 'config',
234 | 'post_type_name',
235 | 'singular',
236 | 'plural',
237 | 'slug',
238 | 'options',
239 | 'taxonomies'
240 | );
241 |
242 | // If the variable is not a reserved variable
243 | if ( ! in_array( $var, $reserved ) ) {
244 |
245 | // Write variable and value
246 | $this->$var = $value;
247 | }
248 | }
249 |
250 | /**
251 | * Add Action
252 | *
253 | * Helper function to add add_action WordPress filters.
254 | *
255 | * @param string $action Name of the action.
256 | * @param string $function Function to hook that will run on action.
257 | * @param integet $priority Order in which to execute the function, relation to other functions hooked to this action.
258 | * @param integer $accepted_args The number of arguments the function accepts.
259 | */
260 | function add_action( $action, $function, $priority = 10, $accepted_args = 1 ) {
261 |
262 | // Pass variables into WordPress add_action function
263 | add_action( $action, $function, $priority, $accepted_args );
264 | }
265 |
266 | /**
267 | * Add Filter
268 | *
269 | * Create add_filter WordPress filter.
270 | *
271 | * @see http://codex.wordpress.org/Function_Reference/add_filter
272 | *
273 | * @param string $action Name of the action to hook to, e.g 'init'.
274 | * @param string $function Function to hook that will run on @action.
275 | * @param int $priority Order in which to execute the function, relation to other function hooked to this action.
276 | * @param int $accepted_args The number of arguements the function accepts.
277 | */
278 | function add_filter( $action, $function, $priority = 10, $accepted_args = 1 ) {
279 |
280 | // Pass variables into Wordpress add_action function
281 | add_filter( $action, $function, $priority, $accepted_args );
282 | }
283 |
284 | /**
285 | * Get slug
286 | *
287 | * Creates an url friendly slug.
288 | *
289 | * @param string $name Name to slugify.
290 | * @return string $name Returns the slug.
291 | */
292 | function get_slug( $name = null ) {
293 |
294 | // If no name set use the post type name.
295 | if ( ! isset( $name ) ) {
296 |
297 | $name = $this->post_type_name;
298 | }
299 |
300 | // Name to lower case.
301 | $name = strtolower( $name );
302 |
303 | // Replace spaces with hyphen.
304 | $name = str_replace( " ", "-", $name );
305 |
306 | // Replace underscore with hyphen.
307 | $name = str_replace( "_", "-", $name );
308 |
309 | return $name;
310 | }
311 |
312 | /**
313 | * Get plural
314 | *
315 | * Returns the friendly plural name.
316 | *
317 | * ucwords capitalize words
318 | * strtolower makes string lowercase before capitalizing
319 | * str_replace replace all instances of _ to space
320 | *
321 | * @param string $name The slug name you want to pluralize.
322 | * @return string the friendly pluralized name.
323 | */
324 | function get_plural( $name = null ) {
325 |
326 | // If no name is passed the post_type_name is used.
327 | if ( ! isset( $name ) ) {
328 |
329 | $name = $this->post_type_name;
330 | }
331 |
332 | // Return the plural name. Add 's' to the end.
333 | return $this->get_human_friendly( $name ) . 's';
334 | }
335 |
336 | /**
337 | * Get singular
338 | *
339 | * Returns the friendly singular name.
340 | *
341 | * ucwords capitalize words
342 | * strtolower makes string lowercase before capitalizing
343 | * str_replace replace all instances of _ to space
344 | *
345 | * @param string $name The slug name you want to unpluralize.
346 | * @return string The friendly singular name.
347 | */
348 | function get_singular( $name = null ) {
349 |
350 | // If no name is passed the post_type_name is used.
351 | if ( ! isset( $name ) ) {
352 |
353 | $name = $this->post_type_name;
354 |
355 | }
356 |
357 | // Return the string.
358 | return $this->get_human_friendly( $name );
359 | }
360 |
361 | /**
362 | * Get human friendly
363 | *
364 | * Returns the human friendly name.
365 | *
366 | * ucwords capitalize words
367 | * strtolower makes string lowercase before capitalizing
368 | * str_replace replace all instances of hyphens and underscores to spaces
369 | *
370 | * @param string $name The name you want to make friendly.
371 | * @return string The human friendly name.
372 | */
373 | function get_human_friendly( $name = null ) {
374 |
375 | // If no name is passed the post_type_name is used.
376 | if ( ! isset( $name ) ) {
377 |
378 | $name = $this->post_type_name;
379 | }
380 |
381 | // Return human friendly name.
382 | return ucwords( strtolower( str_replace( "-", " ", str_replace( "_", " ", $name ) ) ) );
383 | }
384 |
385 | /**
386 | * Register Post Type
387 | *
388 | * @see http://codex.wordpress.org/Function_Reference/register_post_type
389 | */
390 | function register_post_type() {
391 |
392 | // Friendly post type names.
393 | $plural = $this->plural;
394 | $singular = $this->singular;
395 | $slug = $this->slug;
396 |
397 | // Default labels.
398 | $labels = array(
399 | 'name' => sprintf( __( '%s', $this->textdomain ), $plural ),
400 | 'singular_name' => sprintf( __( '%s', $this->textdomain ), $singular ),
401 | 'menu_name' => sprintf( __( '%s', $this->textdomain ), $plural ),
402 | 'all_items' => sprintf( __( '%s', $this->textdomain ), $plural ),
403 | 'add_new' => __( 'Add New', $this->textdomain ),
404 | 'add_new_item' => sprintf( __( 'Add New %s', $this->textdomain ), $singular ),
405 | 'edit_item' => sprintf( __( 'Edit %s', $this->textdomain ), $singular ),
406 | 'new_item' => sprintf( __( 'New %s', $this->textdomain ), $singular ),
407 | 'view_item' => sprintf( __( 'View %s', $this->textdomain ), $singular ),
408 | 'search_items' => sprintf( __( 'Search %s', $this->textdomain ), $plural ),
409 | 'not_found' => sprintf( __( 'No %s found', $this->textdomain ), $plural ),
410 | 'not_found_in_trash' => sprintf( __( 'No %s found in Trash', $this->textdomain ), $plural ),
411 | 'parent_item_colon' => sprintf( __( 'Parent %s:', $this->textdomain ), $singular )
412 | );
413 |
414 | // Default options.
415 | $defaults = array(
416 | 'labels' => $labels,
417 | 'public' => true,
418 | 'rewrite' => array(
419 | 'slug' => $slug,
420 | )
421 | );
422 |
423 | // Merge user submitted options with defaults.
424 | $options = array_replace_recursive( $defaults, $this->options );
425 |
426 | // Set the object options as full options passed.
427 | $this->options = $options;
428 |
429 | // Check that the post type doesn't already exist.
430 | if ( ! post_type_exists( $this->post_type_name ) ) {
431 |
432 | // Register the post type.
433 | register_post_type( $this->post_type_name, $options );
434 | }
435 | }
436 |
437 | /**
438 | * Register taxonomy
439 | *
440 | * @see http://codex.wordpress.org/Function_Reference/register_taxonomy
441 | *
442 | * @param string $taxonomy_name The slug for the taxonomy.
443 | * @param array $options Taxonomy options.
444 | */
445 | function register_taxonomy($taxonomy_names, $options = array()) {
446 |
447 | // Post type defaults to $this post type if unspecified.
448 | $post_type = $this->post_type_name;
449 |
450 | // An array of the names required excluding taxonomy_name.
451 | $names = array(
452 | 'singular',
453 | 'plural',
454 | 'slug'
455 | );
456 |
457 | // if an array of names are passed
458 | if ( is_array( $taxonomy_names ) ) {
459 |
460 | // Set the taxonomy name
461 | $taxonomy_name = $taxonomy_names['taxonomy_name'];
462 |
463 | // Cycle through possible names.
464 | foreach ( $names as $name ) {
465 |
466 | // If the user has set the name.
467 | if ( isset( $taxonomy_names[ $name ] ) ) {
468 |
469 | // Use user submitted name.
470 | $$name = $taxonomy_names[ $name ];
471 |
472 | // Else generate the name.
473 | } else {
474 |
475 | // Define the function to be used.
476 | $method = 'get_' . $name;
477 |
478 | // Generate the name
479 | $$name = $this->$method( $taxonomy_name );
480 |
481 | }
482 | }
483 |
484 | // Else if only the taxonomy_name has been supplied.
485 | } else {
486 |
487 | // Create user friendly names.
488 | $taxonomy_name = $taxonomy_names;
489 | $singular = $this->get_singular( $taxonomy_name );
490 | $plural = $this->get_plural( $taxonomy_name );
491 | $slug = $this->get_slug( $taxonomy_name );
492 |
493 | }
494 |
495 | // Default labels.
496 | $labels = array(
497 | 'name' => sprintf( __( '%s', $this->textdomain ), $plural ),
498 | 'singular_name' => sprintf( __( '%s', $this->textdomain ), $singular ),
499 | 'menu_name' => sprintf( __( '%s', $this->textdomain ), $plural ),
500 | 'all_items' => sprintf( __( 'All %s', $this->textdomain ), $plural ),
501 | 'edit_item' => sprintf( __( 'Edit %s', $this->textdomain ), $singular ),
502 | 'view_item' => sprintf( __( 'View %s', $this->textdomain ), $singular ),
503 | 'update_item' => sprintf( __( 'Update %s', $this->textdomain ), $singular ),
504 | 'add_new_item' => sprintf( __( 'Add New %s', $this->textdomain ), $singular ),
505 | 'new_item_name' => sprintf( __( 'New %s Name', $this->textdomain ), $singular ),
506 | 'parent_item' => sprintf( __( 'Parent %s', $this->textdomain ), $plural ),
507 | 'parent_item_colon' => sprintf( __( 'Parent %s:', $this->textdomain ), $plural ),
508 | 'search_items' => sprintf( __( 'Search %s', $this->textdomain ), $plural ),
509 | 'popular_items' => sprintf( __( 'Popular %s', $this->textdomain ), $plural ),
510 | 'separate_items_with_commas' => sprintf( __( 'Seperate %s with commas', $this->textdomain ), $plural ),
511 | 'add_or_remove_items' => sprintf( __( 'Add or remove %s', $this->textdomain ), $plural ),
512 | 'choose_from_most_used' => sprintf( __( 'Choose from most used %s', $this->textdomain ), $plural ),
513 | 'not_found' => sprintf( __( 'No %s found', $this->textdomain ), $plural ),
514 | );
515 |
516 | // Default options.
517 | $defaults = array(
518 | 'labels' => $labels,
519 | 'hierarchical' => true,
520 | 'rewrite' => array(
521 | 'slug' => $slug
522 | )
523 | );
524 |
525 | // Merge default options with user submitted options.
526 | $options = array_replace_recursive( $defaults, $options );
527 |
528 | // Add the taxonomy to the object array, this is used to add columns and filters to admin panel.
529 | $this->taxonomies[] = $taxonomy_name;
530 |
531 | // Create array used when registering taxonomies.
532 | $this->taxonomy_settings[ $taxonomy_name ] = $options;
533 |
534 | }
535 |
536 |
537 |
538 | /**
539 | * Register taxonomies
540 | *
541 | * Cycles through taxonomies added with the class and registers them.
542 | */
543 | function register_taxonomies() {
544 |
545 | if ( is_array( $this->taxonomy_settings ) ) {
546 |
547 | // Foreach taxonomy registered with the post type.
548 | foreach ( $this->taxonomy_settings as $taxonomy_name => $options ) {
549 |
550 | // Register the taxonomy if it doesn't exist.
551 | if ( ! taxonomy_exists( $taxonomy_name ) ) {
552 |
553 | // Register the taxonomy with Wordpress
554 | register_taxonomy( $taxonomy_name, $this->post_type_name, $options );
555 |
556 | } else {
557 |
558 | // If taxonomy exists, register it later with register_exisiting_taxonomies
559 | $this->exisiting_taxonomies[] = $taxonomy_name;
560 | }
561 | }
562 | }
563 | }
564 |
565 | /**
566 | * Register Exisiting Taxonomies
567 | *
568 | * Cycles through exisiting taxonomies and registers them after the post type has been registered
569 | */
570 | function register_exisiting_taxonomies() {
571 |
572 | if( is_array( $this->exisiting_taxonomies ) ) {
573 | foreach( $this->exisiting_taxonomies as $taxonomy_name ) {
574 | register_taxonomy_for_object_type( $taxonomy_name, $this->post_type_name );
575 | }
576 | }
577 | }
578 |
579 | /**
580 | * Add admin columns
581 | *
582 | * Adds columns to the admin edit screen. Function is used with add_action
583 | *
584 | * @param array $columns Columns to be added to the admin edit screen.
585 | * @return array
586 | */
587 | function add_admin_columns( $columns ) {
588 |
589 | // If no user columns have been specified, add taxonomies
590 | if ( ! isset( $this->columns ) ) {
591 |
592 | $new_columns = array();
593 |
594 | // determine which column to add custom taxonomies after
595 | if ( is_array( $this->taxonomies ) && in_array( 'post_tag', $this->taxonomies ) || $this->post_type_name === 'post' ) {
596 | $after = 'tags';
597 | } elseif( is_array( $this->taxonomies ) && in_array( 'category', $this->taxonomies ) || $this->post_type_name === 'post' ) {
598 | $after = 'categories';
599 | } elseif( post_type_supports( $this->post_type_name, 'author' ) ) {
600 | $after = 'author';
601 | } else {
602 | $after = 'title';
603 | }
604 |
605 | // foreach exisiting columns
606 | foreach( $columns as $key => $title ) {
607 |
608 | // add exisiting column to the new column array
609 | $new_columns[$key] = $title;
610 |
611 | // we want to add taxonomy columns after a specific column
612 | if( $key === $after ) {
613 |
614 | // If there are taxonomies registered to the post type.
615 | if ( is_array( $this->taxonomies ) ) {
616 |
617 | // Create a column for each taxonomy.
618 | foreach( $this->taxonomies as $tax ) {
619 |
620 | // WordPress adds Categories and Tags automatically, ignore these
621 | if( $tax !== 'category' && $tax !== 'post_tag' ) {
622 | // Get the taxonomy object for labels.
623 | $taxonomy_object = get_taxonomy( $tax );
624 |
625 | // Column key is the slug, value is friendly name.
626 | $new_columns[ $tax ] = sprintf( __( '%s', $this->textdomain ), $taxonomy_object->labels->name );
627 | }
628 | }
629 | }
630 | }
631 | }
632 |
633 | // overide with new columns
634 | $columns = $new_columns;
635 |
636 | } else {
637 |
638 | // Use user submitted columns, these are defined using the object columns() method.
639 | $columns = $this->columns;
640 | }
641 |
642 | return $columns;
643 | }
644 |
645 | /**
646 | * Populate admin columns
647 | *
648 | * Populate custom columns on the admin edit screen.
649 | *
650 | * @param string $column The name of the column.
651 | * @param integer $post_id The post ID.
652 | */
653 | function populate_admin_columns( $column, $post_id ) {
654 |
655 | // Get wordpress $post object.
656 | global $post;
657 |
658 | // determine the column
659 | switch( $column ) {
660 |
661 | // If column is a taxonomy associated with the post type.
662 | case ( taxonomy_exists( $column ) ) :
663 |
664 | // Get the taxonomy for the post
665 | $terms = get_the_terms( $post_id, $column );
666 |
667 | // If we have terms.
668 | if ( ! empty( $terms ) ) {
669 |
670 | $output = array();
671 |
672 | // Loop through each term, linking to the 'edit posts' page for the specific term.
673 | foreach( $terms as $term ) {
674 |
675 | // Output is an array of terms associated with the post.
676 | $output[] = sprintf(
677 |
678 | // Define link.
679 | '%s',
680 |
681 | // Create filter url.
682 | esc_url( add_query_arg( array( 'post_type' => $post->post_type, $column => $term->slug ), 'edit.php' ) ),
683 |
684 | // Create friendly term name.
685 | esc_html( sanitize_term_field( 'name', $term->name, $term->term_id, $column, 'display' ) )
686 | );
687 |
688 | }
689 |
690 | // Join the terms, separating them with a comma.
691 | echo join( ', ', $output );
692 |
693 | // If no terms found.
694 | } else {
695 |
696 | // Get the taxonomy object for labels
697 | $taxonomy_object = get_taxonomy( $column );
698 |
699 | // Echo no terms.
700 | printf( __( 'No %s', $this->textdomain ), $taxonomy_object->labels->name );
701 | }
702 |
703 | break;
704 |
705 | // If column is for the post ID.
706 | case 'post_id' :
707 |
708 | echo $post->ID;
709 |
710 | break;
711 |
712 | // if the column is prepended with 'meta_', this will automagically retrieve the meta values and display them.
713 | case ( preg_match( '/^meta_/', $column ) ? true : false ) :
714 |
715 | // meta_book_author (meta key = book_author)
716 | $x = substr( $column, 5 );
717 |
718 | $meta = get_post_meta( $post->ID, $x );
719 |
720 | echo join( ", ", $meta );
721 |
722 | break;
723 |
724 | // If the column is post thumbnail.
725 | case 'icon' :
726 |
727 | // Create the edit link.
728 | $link = esc_url( add_query_arg( array( 'post' => $post->ID, 'action' => 'edit' ), 'post.php' ) );
729 |
730 | // If it post has a featured image.
731 | if ( has_post_thumbnail() ) {
732 |
733 | // Display post featured image with edit link.
734 | echo '';
735 | the_post_thumbnail( array(60, 60) );
736 | echo '';
737 |
738 | } else {
739 |
740 | // Display default media image with link.
741 | echo '
';
742 |
743 | }
744 |
745 | break;
746 |
747 | // Default case checks if the column has a user function, this is most commonly used for custom fields.
748 | default :
749 |
750 | // If there are user custom columns to populate.
751 | if ( isset( $this->custom_populate_columns ) && is_array( $this->custom_populate_columns ) ) {
752 |
753 | // If this column has a user submitted function to run.
754 | if ( isset( $this->custom_populate_columns[ $column ] ) && is_callable( $this->custom_populate_columns[ $column ] ) ) {
755 |
756 | // Run the function.
757 | call_user_func_array( $this->custom_populate_columns[ $column ], array( $column, $post ) );
758 |
759 | }
760 | }
761 |
762 | break;
763 | } // end switch( $column )
764 | }
765 |
766 | /**
767 | * Filters
768 | *
769 | * User function to define which taxonomy filters to display on the admin page.
770 | *
771 | * @param array $filters An array of taxonomy filters to display.
772 | */
773 | function filters( $filters = array() ) {
774 |
775 | $this->filters = $filters;
776 | }
777 |
778 | /**
779 | * Add taxtonomy filters
780 | *
781 | * Creates select fields for filtering posts by taxonomies on admin edit screen.
782 | */
783 | function add_taxonomy_filters() {
784 |
785 | global $typenow;
786 | global $wp_query;
787 |
788 | // Must set this to the post type you want the filter(s) displayed on.
789 | if ( $typenow == $this->post_type_name ) {
790 |
791 | // if custom filters are defined use those
792 | if ( is_array( $this->filters ) ) {
793 |
794 | $filters = $this->filters;
795 |
796 | // else default to use all taxonomies associated with the post
797 | } else {
798 |
799 | $filters = $this->taxonomies;
800 | }
801 |
802 | if ( ! empty( $filters ) ) {
803 |
804 | // Foreach of the taxonomies we want to create filters for...
805 | foreach ( $filters as $tax_slug ) {
806 |
807 | // ...object for taxonomy, doesn't contain the terms.
808 | $tax = get_taxonomy( $tax_slug );
809 |
810 | // Get taxonomy terms and order by name.
811 | $args = array(
812 | 'orderby' => 'name',
813 | 'hide_empty' => false
814 | );
815 |
816 | // Get taxonomy terms.
817 | $terms = get_terms( $tax_slug, $args );
818 |
819 | // If we have terms.
820 | if ( $terms ) {
821 |
822 | // Set up select box.
823 | printf( ' ' );
844 | }
845 | }
846 | }
847 | }
848 | }
849 |
850 | /**
851 | * Columns
852 | *
853 | * Choose columns to be displayed on the admin edit screen.
854 | *
855 | * @param array $columns An array of columns to be displayed.
856 | */
857 | function columns( $columns ) {
858 |
859 | // If columns is set.
860 | if( isset( $columns ) ) {
861 |
862 | // Assign user submitted columns to object.
863 | $this->columns = $columns;
864 |
865 | }
866 | }
867 |
868 | /**
869 | * Populate columns
870 | *
871 | * Define what and how to populate a speicific admin column.
872 | *
873 | * @param string $column_name The name of the column to populate.
874 | * @param mixed $callback An anonyous function or callable array to call when populating the column.
875 | */
876 | function populate_column( $column_name, $callback ) {
877 |
878 | $this->custom_populate_columns[ $column_name ] = $callback;
879 |
880 | }
881 |
882 | /**
883 | * Sortable
884 | *
885 | * Define what columns are sortable in the admin edit screen.
886 | *
887 | * @param array $columns An array of columns that are sortable.
888 | */
889 | function sortable( $columns = array() ) {
890 |
891 | // Assign user defined sortable columns to object variable.
892 | $this->sortable = $columns;
893 |
894 | // Run filter to make columns sortable.
895 | $this->add_filter( 'manage_edit-' . $this->post_type_name . '_sortable_columns', array( &$this, 'make_columns_sortable' ) );
896 |
897 | // Run action that sorts columns on request.
898 | $this->add_action( 'load-edit.php', array( &$this, 'load_edit' ) );
899 | }
900 |
901 | /**
902 | * Make columns sortable
903 | *
904 | * Internal function that adds user defined sortable columns to WordPress default columns.
905 | *
906 | * @param array $columns Columns to be sortable.
907 | *
908 | */
909 | function make_columns_sortable( $columns ) {
910 |
911 | // For each sortable column.
912 | foreach ( $this->sortable as $column => $values ) {
913 |
914 | // Make an array to merge into wordpress sortable columns.
915 | $sortable_columns[ $column ] = $values[0];
916 | }
917 |
918 | // Merge sortable columns array into wordpress sortable columns.
919 | $columns = array_merge( $sortable_columns, $columns );
920 |
921 | return $columns;
922 | }
923 |
924 | /**
925 | * Load edit
926 | *
927 | * Sort columns only on the edit.php page when requested.
928 | *
929 | * @see http://codex.wordpress.org/Plugin_API/Filter_Reference/request
930 | */
931 | function load_edit() {
932 |
933 | // Run filter to sort columns when requested
934 | $this->add_filter( 'request', array( &$this, 'sort_columns' ) );
935 |
936 | }
937 |
938 | /**
939 | * Sort columns
940 | *
941 | * Internal function that sorts columns on request.
942 | *
943 | * @see load_edit()
944 | *
945 | * @param array $vars The query vars submitted by user.
946 | * @return array A sorted array.
947 | */
948 | function sort_columns( $vars ) {
949 |
950 | // Cycle through all sortable columns submitted by the user
951 | foreach ( $this->sortable as $column => $values ) {
952 |
953 | // Retrieve the meta key from the user submitted array of sortable columns
954 | $meta_key = $values[0];
955 |
956 | // If the meta_key is a taxonomy
957 | if( taxonomy_exists( $meta_key ) ) {
958 |
959 | // Sort by taxonomy.
960 | $key = "taxonomy";
961 |
962 | } else {
963 |
964 | // else by meta key.
965 | $key = "meta_key";
966 | }
967 |
968 | // If the optional parameter is set and is set to true
969 | if ( isset( $values[1] ) && true === $values[1] ) {
970 |
971 | // Vaules needed to be ordered by integer value
972 | $orderby = 'meta_value_num';
973 |
974 | } else {
975 |
976 | // Values are to be order by string value
977 | $orderby = 'meta_value';
978 | }
979 |
980 | // Check if we're viewing this post type
981 | if ( isset( $vars['post_type'] ) && $this->post_type_name == $vars['post_type'] ) {
982 |
983 | // find the meta key we want to order posts by
984 | if ( isset( $vars['orderby'] ) && $meta_key == $vars['orderby'] ) {
985 |
986 | // Merge the query vars with our custom variables
987 | $vars = array_merge(
988 | $vars,
989 | array(
990 | 'meta_key' => $meta_key,
991 | 'orderby' => $orderby
992 | )
993 | );
994 | }
995 | }
996 | }
997 | return $vars;
998 | }
999 |
1000 | /**
1001 | * Set menu icon
1002 | *
1003 | * Use this function to set the menu icon in the admin dashboard. Since WordPress v3.8
1004 | * dashicons are used. For more information see @link http://melchoyce.github.io/dashicons/
1005 | *
1006 | * @param string $icon dashicon name
1007 | */
1008 | function menu_icon( $icon = "dashicons-admin-page" ) {
1009 |
1010 | if ( is_string( $icon ) && stripos( $icon, "dashicons" ) !== false ) {
1011 |
1012 | $this->options["menu_icon"] = $icon;
1013 |
1014 | } else {
1015 |
1016 | // Set a default menu icon
1017 | $this->options["menu_icon"] = "dashicons-admin-page";
1018 | }
1019 | }
1020 |
1021 | /**
1022 | * Set textdomain
1023 | *
1024 | * @param string $textdomain Textdomain used for translation.
1025 | */
1026 | function set_textdomain( $textdomain ) {
1027 | $this->textdomain = $textdomain;
1028 | }
1029 |
1030 | /**
1031 | * Updated messages
1032 | *
1033 | * Internal function that modifies the post type names in updated messages
1034 | *
1035 | * @param array $messages an array of post updated messages
1036 | */
1037 | function updated_messages( $messages ) {
1038 |
1039 | $post = get_post();
1040 | $singular = $this->singular;
1041 |
1042 | $messages[$this->post_type_name] = array(
1043 | 0 => '',
1044 | 1 => sprintf( __( '%s updated.', $this->textdomain ), $singular ),
1045 | 2 => __( 'Custom field updated.', $this->textdomain ),
1046 | 3 => __( 'Custom field deleted.', $this->textdomain ),
1047 | 4 => sprintf( __( '%s updated.', $this->textdomain ), $singular ),
1048 | 5 => isset( $_GET['revision'] ) ? sprintf( __( '%2$s restored to revision from %1$s', $this->textdomain ), wp_post_revision_title( (int) $_GET['revision'], false ), $singular ) : false,
1049 | 6 => sprintf( __( '%s updated.', $this->textdomain ), $singular ),
1050 | 7 => sprintf( __( '%s saved.', $this->textdomain ), $singular ),
1051 | 8 => sprintf( __( '%s submitted.', $this->textdomain ), $singular ),
1052 | 9 => sprintf(
1053 | __( '%2$s scheduled for: %1$s.', $this->textdomain ),
1054 | date_i18n( __( 'M j, Y @ G:i', $this->textdomain ), strtotime( $post->post_date ) ),
1055 | $singular
1056 | ),
1057 | 10 => sprintf( __( '%s draft updated.', $this->textdomain ), $singular ),
1058 | );
1059 |
1060 | return $messages;
1061 | }
1062 |
1063 | /**
1064 | * Bulk updated messages
1065 | *
1066 | * Internal function that modifies the post type names in bulk updated messages
1067 | *
1068 | * @param array $messages an array of bulk updated messages
1069 | */
1070 | function bulk_updated_messages( $bulk_messages, $bulk_counts ) {
1071 |
1072 | $singular = $this->singular;
1073 | $plural = $this->plural;
1074 |
1075 | $bulk_messages[ $this->post_type_name ] = array(
1076 | 'updated' => _n( '%s '.$singular.' updated.', '%s '.$plural.' updated.', $bulk_counts['updated'] ),
1077 | 'locked' => _n( '%s '.$singular.' not updated, somebody is editing it.', '%s '.$plural.' not updated, somebody is editing them.', $bulk_counts['locked'] ),
1078 | 'deleted' => _n( '%s '.$singular.' permanently deleted.', '%s '.$plural.' permanently deleted.', $bulk_counts['deleted'] ),
1079 | 'trashed' => _n( '%s '.$singular.' moved to the Trash.', '%s '.$plural.' moved to the Trash.', $bulk_counts['trashed'] ),
1080 | 'untrashed' => _n( '%s '.$singular.' restored from the Trash.', '%s '.$plural.' restored from the Trash.', $bulk_counts['untrashed'] ),
1081 | );
1082 |
1083 | return $bulk_messages;
1084 | }
1085 |
1086 | /**
1087 | * Flush
1088 | *
1089 | * Flush rewrite rules programatically
1090 | */
1091 | function flush() {
1092 | flush_rewrite_rules();
1093 | }
1094 | }
1095 |
--------------------------------------------------------------------------------