├── README.md
├── js
└── taxonomy-term-image.js
└── taxonomy-term-image.php
/README.md:
--------------------------------------------------------------------------------
1 | # Taxonomy Term Image
2 |
3 | An example plugin for adding an image upload field to taxonomy term edit pages, and an example of the new taxonomy term meta data added in WordPress 4.4. This example IS NOT compatible with any version of WordPress lower than 4.4, it is meant to be used as an example only.
4 |
5 | ### How to use within a theme or plugin:
6 |
7 | **Setup file:**
8 |
9 | 1. Delete plugin meta data at the top of taxonomy-term-image.php
10 | 1. include_once taxonomy-term-image.php
11 |
12 | ### Hooks
13 |
14 | **filter `taxonomy-term-image-taxonomy`**:
15 |
16 | Change the taxonomy targeted by the plugin. By default, the `category` taxonomy is the only taxonomy targeted. You can change this to tags if you'd like following the example below:
17 |
18 | ```php
19 | function the_term_image_taxonomy( $taxonomy ) {
20 | // use for tags instead of categories
21 | return 'post_tag';
22 | }
23 | add_filter( 'taxonomy-term-image-taxonomy', 'the_term_image_taxonomy' );
24 | ```
25 |
26 | Alternatively, the plugin can target more than one taxonomy by providing it an array of taxonomy slugs:
27 |
28 | ```php
29 | function the_term_image_taxonomy( $taxonomy ) {
30 | // use for tags and categories
31 | return array( 'post_tag', 'category' );
32 | }
33 | add_filter( 'taxonomy-term-image-taxonomy', 'the_term_image_taxonomy' );
34 | ```
35 |
36 | **filter `taxonomy-term-image-labels`**:
37 |
38 | Change the field and button text.
39 |
40 | ```php
41 | function the_taxonomy_term_image_labels( $labels ) {
42 | $labels['fieldTitle'] = __( 'My Super Rad Plugin', 'yourdomain' );
43 | $labels['fieldDescription'] = __( 'This plugin is cool, and does neat stuff.', 'yourdomain' );
44 |
45 | return $labels;
46 | }
47 | add_filter( 'taxonomy-term-image-labels', 'the_taxonomy_term_image_labels' );
48 | ```
49 |
50 | **filter `taxonomy-term-image-meta-key`**:
51 |
52 | Change the meta key used to save the image ID in the term meta data
53 |
54 | ```php
55 | function the_taxonomy_term_image_meta_key( $option_name ) {
56 | // store in term meta where term meta key is = 'my_term_meta_key'
57 | return 'my_term_meta_key';
58 | }
59 | add_filter( 'taxonomy-term-image-meta-key', 'the_taxonomy_term_image_meta_key' );
60 | ```
61 |
62 | **filter `taxonomy-term-image-js-dir-url`**:
63 |
64 | Change where the js file is located. (no trailing slash)
65 |
66 | ```php
67 | function my_taxonomy_term_image_js_dir_url( $option_name ) {
68 | // change the js directory to a subdirectory of this hook
69 | return plugin_dir_url( __FILE__ ) . '/js';
70 | }
71 | add_filter( 'taxonomy-term-image-js-dir-url', 'my_taxonomy_term_image_js_dir_url' );
72 | ```
73 |
74 | **show image on archive template**
75 |
76 | Term Image IDs are automatically attached to terms that are passed through the `get_term` and `get_terms` filters as the `->term_image` property.
77 |
78 | ```php
79 | $term = get_term( 123, 'category' );
80 |
81 | if ( $term->term_image ) {
82 | echo wp_get_attachment_image( $term->term_image, 'full' );
83 | }
84 | ```
85 |
86 | In order to retrieve the term image on an archive page:
87 |
88 | ```php
89 | $term = get_queried_object();
90 |
91 | if ( $term->term_image ) {
92 | echo wp_get_attachment_image( $term->term_image, 'full' );
93 | }
94 | ```
95 |
96 | ### References:
97 |
98 | **Articles:**
99 |
100 | * [Using Media Uploader in plugins](http://mikejolley.com/2012/12/using-the-new-wordpress-3-5-media-uploader-in-plugins/)
101 | * [Introduction to WordPress term meta](http://themehybrid.com/weblog/introduction-to-wordpress-term-meta)
102 |
103 | **Code References:**
104 |
105 | * Plugin Hooks
106 | * action [admin_init](http://codex.wordpress.org/Plugin_API/Action_Reference/admin_init)
107 | * action [admin_enqueue_scripts](http://codex.wordpress.org/Plugin_API/Action_Reference/admin_enqueue_scripts)
108 | * function [wp_register_script](https://developer.wordpress.org/reference/functions/wp_register_script/)
109 | * function [wp_localize_script](https://developer.wordpress.org/reference/functions/wp_localize_script/)
110 | * function [wp_enqueue_script](https://developer.wordpress.org/reference/functions/wp_enqueue_script/)
111 | * Term Meta Data
112 | * function [register_meta](https://developer.wordpress.org/reference/functions/register_meta/)
113 | * function [get_term_meta](https://make.wordpress.org/core/2015/10/23/4-4-taxonomy-roundup/)
114 | * function [update_term_meta](https://make.wordpress.org/core/2015/10/23/4-4-taxonomy-roundup/)
115 | * function [delete_term_meta](https://make.wordpress.org/core/2015/10/23/4-4-taxonomy-roundup/)
116 | * Taxonomy Hooks
117 | * action [create_{$taxonomy}](https://developer.wordpress.org/reference/hooks/create_taxonomy/)
118 | * action [edit_{$taxonomy}](https://developer.wordpress.org/reference/hooks/edit_taxonomy/)
119 | * action [{$taxonomy}_add_form_fields](https://developer.wordpress.org/reference/hooks/taxonomy_add_form_fields/)
120 | * action [{$taxonomy}_edit_form_fields](https://developer.wordpress.org/reference/hooks/taxonomy_edit_form_fields/)
121 | * filter [get_term](https://developer.wordpress.org/reference/hooks/get_term/)
122 | * filter [get_terms](https://developer.wordpress.org/reference/hooks/get_terms/)
123 | * filter [get_object_terms](https://developer.wordpress.org/reference/hooks/get_object_terms/)
124 |
125 |
--------------------------------------------------------------------------------
/js/taxonomy-term-image.js:
--------------------------------------------------------------------------------
1 | (function($){
2 | var taxonomyTermImageText = TaxonomyTermImageText || {};
3 |
4 | var taxonomyTermImage = {
5 |
6 | // modal frame
7 | file_frame: null,
8 |
9 | // modal settings
10 | settings: {
11 | title: taxonomyTermImageText.modalTitle || 'Select or upload a video',
12 | button: {
13 | text: taxonomyTermImageText.modalButton || 'Attach'
14 | },
15 | multiple: false, // Set to true to allow multiple files to be selected
16 | library: {
17 | type: 'image'
18 | }
19 | },
20 |
21 | /**
22 | * Initialize script
23 | */
24 | init: function(){
25 | var _this = this;
26 |
27 | // delegate our click handler so that the image itself is clickable. because that's cool
28 | $('body').on('click', '.taxonomy-term-image-attach', function ( event ) {
29 | event.preventDefault();
30 |
31 | _this.openModal();
32 | });
33 |
34 | // remove button
35 | $('.taxonomy-term-image-remove').click( _this.removeImage );
36 | },
37 |
38 | /**
39 | * Remove the current image by emptying the container and field
40 | */
41 | removeImage: function(){
42 | $('#taxonomy-term-image-container').html('');
43 | $('#taxonomy-term-image-id').val('');
44 | },
45 |
46 | /**
47 | * Open the media modal window
48 | * - http://mikejolley.com/2012/12/using-the-new-wordpress-3-5-media-uploader-in-plugins/
49 | * - https://gist.github.com/pippinsplugins/29bebb740e09e395dc06
50 | */
51 | openModal: function(){
52 | var _this = this;
53 |
54 | // If the media frame already exists, reopen it.
55 | if ( _this.file_frame ) {
56 | _this.file_frame.open();
57 | return;
58 | }
59 |
60 | // Create the media frame.
61 | _this.file_frame = wp.media.frames.file_frame = wp.media( _this.settings );
62 |
63 | // When an image is selected, run a callback.
64 | _this.file_frame.on( 'select', function() {
65 |
66 | _this.file_frame.state()
67 | .get('selection')
68 |
69 | // handle each attachment
70 | .map( _this.updateImage);
71 | });
72 |
73 | // Finally, open the modal
74 | _this.file_frame.open();
75 | },
76 |
77 | /**
78 | * Handle a single selected image attachment
79 | *
80 | * @param attachment
81 | */
82 | updateImage: function( attachment ){
83 | // the selected image
84 | var image = attachment.toJSON();
85 |
86 | // retrieve image url.
87 | // no bitmap image like svg does not have "sizes" attribute.
88 | var url ;
89 | var sizes = attachment.get('sizes');
90 | if( typeof sizes !== 'undefined' )
91 | url = ( typeof sizes.thumbnail === 'undefined' ) ? sizes.full.url : sizes.thumbnail.url ;
92 | else
93 | url = attachment.get('url');
94 |
95 | //image.id
96 | $('#taxonomy-term-image-id').val( image.id );
97 |
98 | //sizes.thumbnail.url
99 | $('#taxonomy-term-image-container').html("");
100 | }
101 | };
102 |
103 | $(document).ready(function(){
104 | taxonomyTermImage.init();
105 | });
106 |
107 | })(jQuery);
108 |
--------------------------------------------------------------------------------
/taxonomy-term-image.php:
--------------------------------------------------------------------------------
1 | labels = array(
63 | 'fieldTitle' => __( 'Taxonomy Term Image' ),
64 | 'fieldDescription' => __( 'Select which image should represent this term.' ),
65 | 'imageButton' => __( 'Select Image' ),
66 | 'removeButton' => __( 'Remove' ),
67 | 'modalTitle' => __( 'Select or upload an image for this term' ),
68 | 'modalButton' => __( 'Attach' ),
69 | 'adminColumnTitle' => __( 'Image' ),
70 | );
71 |
72 | // allow overriding of the html text
73 | $this->labels = apply_filters( 'taxonomy-term-image-labels', $this->labels );
74 |
75 | // allow overriding of the target taxonomies
76 | $this->taxonomies = apply_filters( 'taxonomy-term-image-taxonomy', $this->taxonomies );
77 |
78 | if ( ! is_array( $this->taxonomies ) ) {
79 | $this->taxonomies = array( $this->taxonomies );
80 | }
81 |
82 | // @deprecated: allow overriding of option_name
83 | // default option name keyed to the taxonomy
84 | $this->option_name = $this->taxonomies[0] . '_term_images';
85 | $this->option_name = apply_filters( 'taxonomy-term-image-option-name', $this->option_name );
86 |
87 | // allow overriding of term_meta
88 | $this->term_meta_key = apply_filters( 'taxonomy-term-image-meta-key', $this->term_meta_key );
89 |
90 | // get our js location for enqueing scripts
91 | $this->js_dir_url = apply_filters( 'taxonomy-term-image-js-dir-url', plugin_dir_url( __FILE__ ) . '/js' );
92 |
93 | // check for updates
94 | $this->upgrade();
95 |
96 | // hook into WordPress
97 | $this->hook_up();
98 | }
99 |
100 | /**
101 | * Check for plugin updates
102 | */
103 | private function upgrade(){
104 | $previous_version = get_option( 'taxonomy-term-image-version', '0.0.0' );
105 |
106 | // if the previous version is less than the current version,
107 | // we need to upgrade
108 | if ( version_compare( $previous_version, $this->version, '<' ) ){
109 |
110 | $old_option = get_option( $this->option_name, array() );
111 |
112 | // if we have data in the old (1.x) option,
113 | // move it to term meta and delete the old option
114 | if ( ! empty( $old_option ) ) {
115 | foreach( $old_option as $term_id => $image_id ) {
116 | update_term_meta( $term_id, $this->term_meta_key, $image_id );
117 | }
118 |
119 | delete_option( $this->option_name );
120 | }
121 |
122 | // modify the stored version data for future checks
123 | update_option( 'taxonomy-term-image-version', $this->version );
124 | }
125 | }
126 |
127 | /**
128 | * Hook into WordPress
129 | */
130 | private function hook_up(){
131 | // register our term meta and sanitize as an integer
132 | register_meta( 'term', $this->term_meta_key, 'absint' );
133 |
134 | // add our data when term is retrieved
135 | add_filter( 'get_term', array( $this, 'get_term' ) );
136 | add_filter( 'get_terms', array( $this, 'get_terms' ) );
137 | add_filter( 'get_object_terms', array( $this, 'get_terms' ) );
138 |
139 | // we only need to add most hooks on the admin side
140 | if ( is_admin() ) {
141 | add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
142 |
143 | foreach ( $this->taxonomies as $taxonomy ) {
144 | // add our image field to the taxonomy term forms
145 | add_action( $taxonomy . '_add_form_fields', array( $this, 'taxonomy_add_form' ) );
146 | add_action( $taxonomy . '_edit_form_fields', array( $this, 'taxonomy_edit_form' ) );
147 |
148 | // hook into term administration actions
149 | add_action( 'create_' . $taxonomy, array( $this, 'taxonomy_term_form_save' ) );
150 | add_action( 'edit_' . $taxonomy, array( $this, 'taxonomy_term_form_save' ) );
151 |
152 | // custom admin taxonomy term list columns
153 | add_filter( 'manage_edit-' . $taxonomy . '_columns', array( $this, 'taxonomy_term_column_image' ) );
154 | add_filter( 'manage_' . $taxonomy . '_custom_column', array( $this, 'taxonomy_term_column_image_content' ), 10, 3 );
155 | }
156 | }
157 | }
158 |
159 | /**
160 | * Add a new column to enabled taxonomy admin pages that show the chosen
161 | * image.
162 | *
163 | * @param $columns
164 | *
165 | * @return mixed
166 | */
167 | function taxonomy_term_column_image( $columns ){
168 | $columns['term_image'] = $this->labels['adminColumnTitle'];
169 |
170 | return $columns;
171 | }
172 |
173 | /**
174 | * Show the selected term image within the newly created admin column
175 | *
176 | * @param $content
177 | * @param $column_name
178 | * @param $term_id
179 | *
180 | * @return mixed
181 | */
182 | function taxonomy_term_column_image_content( $content, $column_name, $term_id ){
183 | if ( 'term_image' == $column_name ){
184 | $term = get_term( $term_id );
185 |
186 | if ( $term->term_image ) {
187 | $content = wp_get_attachment_image( $term->term_image, 'thumbnail', false, array( 'style' => 'max-width:100%; height:auto;' ) );
188 | }
189 | }
190 | return $content;
191 | }
192 |
193 |
194 | /**
195 | * Add the image data to any relevant get_term() call. Double duty as a
196 | * helper function for this->get_terms().
197 | *
198 | * @param $_term
199 | * @return object
200 | */
201 | function get_term( $_term ) {
202 | // only modify term when dealing with our taxonomies
203 | if ( is_object( $_term ) && in_array( $_term->taxonomy, $this->taxonomies ) ) {
204 |
205 | // default to null if not found
206 | $image_id = get_term_meta( $_term->term_id, $this->term_meta_key, true );
207 | $_term->term_image = !empty( $image_id ) ? $image_id : null;
208 | }
209 | return $_term;
210 | }
211 |
212 | /**
213 | * Add term_image data to objects when get_terms() or wp_get_object_terms()
214 | * is called.
215 | *
216 | * @param $terms
217 | * @return array
218 | */
219 | function get_terms( $terms ) {
220 | foreach( $terms as $i => $term ){
221 | if ( is_object( $term ) && !empty( $term->taxonomy ) ) {
222 | $terms[ $i ] = $this->get_term( $term );
223 | }
224 | }
225 | return $terms;
226 | }
227 |
228 | /**
229 | * WordPress action "admin_enqueue_scripts"
230 | */
231 | function admin_enqueue_scripts(){
232 | // get the screen object to decide if we want to inject our scripts
233 | $screen = get_current_screen();
234 |
235 | // check if we are on any edit-{taxonomy} screen
236 | foreach( $this->taxonomies as $taxonomy ) {
237 | if ( $screen->id == 'edit-' . $taxonomy ){
238 | // WP core stuff we need
239 | wp_enqueue_media();
240 | wp_enqueue_style( 'thickbox' );
241 |
242 | // register our custom script
243 | wp_register_script( 'taxonomy-term-image-js', $this->js_dir_url . '/taxonomy-term-image.js', array( 'jquery', 'thickbox', 'media-upload' ), $this->version, true );
244 |
245 | // Localize the modal window text so it can be translated
246 | wp_localize_script( 'taxonomy-term-image-js', 'TaxonomyTermImageText', $this->labels );
247 |
248 | // enqueue the registered and localized script
249 | wp_enqueue_script( 'taxonomy-term-image-js' );
250 | break;
251 | }
252 | }
253 | }
254 |
255 | /**
256 | * The HTML form for our taxonomy image field
257 | *
258 | * @param int $image_ID the image ID
259 | * @return string the html output for the image form
260 | */
261 | function taxonomy_term_image_field( $image_ID = null ) {
262 | $image_src = ( $image_ID ) ? wp_get_attachment_image_src( $image_ID, 'thumbnail' ) : array();
263 |
264 | wp_nonce_field( 'taxonomy-term-image-form-save', 'taxonomy-term-image-save-form-nonce' );
265 | ?>
266 |
267 |
268 |
269 |
labels['fieldDescription']; ?>
270 | 271 |
272 |
273 |
274 |
275 |