PluginProbe
Edit Flow / 0.7.4
Edit Flow v0.7.4
0.11.1 0.11.0 0.7.2 0.7.3 0.7.4 0.7.5 0.7.6 0.8 0.8.1 0.8.2 0.9 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5 0.9.6 0.9.7 0.9.8 0.9.9 trunk 0.1.5 0.10.0 0.10.1 0.10.2 All 44 releases
edit-flow / modules / editorial-metadata / editorial-metadata.php

editorial-metadata.php in Edit Flow 0.7.4, at modules/editorial-metadata/editorial-metadata.php

1,747 lines 68.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * class EF_Editorial_Metadata
4 * This class gives publishers arbitrary structured content details to go along with every post
5 *
6 * @author sbressler, danielbachhuber
7 *
8 * Ways to test and play with this class:
9 * 1) Create a new term by selecting Editorial Metadata from the Edit Flow settings
10 * 2) Edit an existing term (slug, description, etc.)
11 * 3) Create a post and assign metadata to it
12 * 4) Look at the list of terms again - the count should go up!
13 * 5) Play with adding more metadata to a post
14 * 6) Clear the metadata for a single term in a post and watch the count go down!
15 * 6) Delete a term and note the metadata disappears from posts
16 * 7) Re-add the term (same slug) and the metadata returns!
17 *
18 * Improvements to make:
19 * @todo Abstract the permissions check for management to class level
20 */
21 if ( !class_exists('EF_Editorial_Metadata') ) {
22
23 class EF_Editorial_Metadata extends EF_Module {
24
25 /**
26 * The name of the taxonomy we're going to register for editorial metadata.
27 */
28 const metadata_taxonomy = 'ef_editorial_meta';
29 const metadata_postmeta_key = "_ef_editorial_meta";
30
31 var $module_name = 'editorial_metadata';
32
33 /**
34 * Construct the EF_Editorial_Metadata class
35 */
36 function __construct() {
37 global $edit_flow;
38
39 $this->module_url = $this->get_module_url( __FILE__ );
40 // Register the module with Edit Flow
41 $args = array(
42 'title' => __( 'Editorial Metadata', 'edit-flow' ),
43 'short_description' => __( 'Track details about your posts in progress.', 'edit-flow' ),
44 'extended_description' => __( 'Log details on every assignment using configurable editorial metadata. It’s completely customizable; create fields for everything from due date to location to contact information to role assignments.', 'edit-flow' ),
45 'module_url' => $this->module_url,
46 'img_url' => $this->module_url . 'lib/editorial_metadata_s128.png',
47 'slug' => 'editorial-metadata',
48 'default_options' => array(
49 'enabled' => 'on',
50 'post_types' => array(
51 'post' => 'on',
52 'page' => 'off',
53 ),
54 ),
55 'messages' => array(
56 'term-added' => __( "Metadata term added.", 'edit-flow' ),
57 'term-updated' => __( "Metadata term updated.", 'edit-flow' ),
58 'term-missing' => __( "Metadata term doesn't exist.", 'edit-flow' ),
59 'term-deleted' => __( "Metadata term deleted.", 'edit-flow' ),
60 'term-position-updated' => __( "Term order updated.", 'edit-flow' ),
61 'term-visibility-changed' => __( "Term visibility changed.", 'edit-flow' ),
62 ),
63 'configure_page_cb' => 'print_configure_view',
64 'settings_help_tab' => array(
65 'id' => 'ef-editorial-metadata-overview',
66 'title' => __('Overview', 'edit-flow'),
67 'content' => __('<p>Keep track of important details about your content with editorial metadata. This feature allows you to create as many date, text, number, etc. fields as you like, and then use them to store information like contact details, required word count, or the location of an interview.</p><p>Once you’ve set your fields up, editorial metadata integrates with both the calendar and the story budget. Make an editorial metadata item visible to have it appear to the rest of your team. Keep it hidden to restrict the information between the writer and their editor.</p>', 'edit-flow'),
68 ),
69 'settings_help_sidebar' => __( '<p><strong>For more information:</strong></p><p><a href="http://editflow.org/features/editorial-metadata/">Editorial Metadata Documentation</a></p><p><a href="http://wordpress.org/tags/edit-flow?forum_id=10">Edit Flow Forum</a></p><p><a href="https://github.com/danielbachhuber/Edit-Flow">Edit Flow on Github</a></p>', 'edit-flow' ),
70 );
71 EditFlow()->register_module( $this->module_name, $args );
72 }
73
74 /**
75 * Initialize the module. Conditionally loads if the module is enabled
76 */
77 function init() {
78
79 // Register the taxonomy we use for Editorial Metadata with WordPress core
80 $this->register_taxonomy();
81
82 // Anything that needs to happen in the admin
83 add_action( 'admin_init', array( $this, 'action_admin_init' ) );
84
85 // Register our settings
86 add_action( 'admin_init', array( $this, 'register_settings' ) );
87
88 // Actions relevant to the configuration view (adding, editing, or sorting existing Editorial Metadata)
89 add_action( 'admin_init', array( $this, 'handle_add_editorial_metadata' ) );
90 add_action( 'admin_init', array( $this, 'handle_edit_editorial_metadata' ) );
91 add_action( 'admin_init', array( $this, 'handle_change_editorial_metadata_visibility' ) );
92 add_action( 'admin_init', array( $this, 'handle_delete_editorial_metadata' ) );
93 add_action( 'wp_ajax_inline_save_term', array( $this, 'handle_ajax_inline_save_term' ) );
94 add_action( 'wp_ajax_update_term_positions', array( $this, 'handle_ajax_update_term_positions' ) );
95
96 add_action( 'add_meta_boxes', array( $this, 'handle_post_metaboxes' ) );
97 add_action( 'save_post', array( $this, 'save_meta_box' ), 10, 2 );
98
99 // Add Editorial Metadata columns to the Manage Posts view
100 $supported_post_types = $this->get_post_types_for_module( $this->module );
101 foreach( $supported_post_types as $post_type ) {
102 add_filter( "manage_{$post_type}_posts_columns", array( $this, 'filter_manage_posts_columns' ) );
103 add_action( 'manage_posts_custom_column', array( $this, 'action_manage_posts_custom_column' ), 10, 2 );
104 }
105
106 // Add Editorial Metadata to the calendar if the calendar is activated
107 if ( $this->module_enabled( 'calendar' ) )
108 add_filter( 'ef_calendar_item_information_fields', array( $this, 'filter_calendar_item_fields' ), 10, 2 );
109
110 // Add Editorial Metadata columns to the Story Budget if it exists
111 if ( $this->module_enabled( 'story_budget' ) ) {
112 add_filter( 'ef_story_budget_term_columns', array( $this, 'filter_story_budget_term_columns' ) );
113 // Register an action to handle this data later
114 add_filter( 'ef_story_budget_term_column_value', array( $this, 'filter_story_budget_term_column_values' ), 10, 3 );
115 }
116
117 // Load necessary scripts and stylesheets
118 add_action( 'admin_enqueue_scripts', array( $this, 'add_admin_scripts' ) );
119
120 }
121
122 /**
123 * Load default editorial metadata the first time the module is loaded
124 *
125 * @since 0.7
126 */
127 function install() {
128 // Our default metadata fields
129 $default_metadata = array(
130 array(
131 'name' => __( 'First Draft Date', 'edit-flow' ),
132 'slug' => 'first-draft-date',
133 'type' => 'date',
134 'description' => __( 'When the first draft needs to be ready.', 'edit-flow' ),
135 ),
136 array(
137 'name' => __( 'Assignment', 'edit-flow' ),
138 'slug' => 'assignment',
139 'type' => 'paragraph',
140 'description' => __( 'What the post needs to cover.', 'edit-flow' ),
141 ),
142 array(
143 'name' => __( 'Needs Photo', 'edit-flow' ),
144 'slug' => 'needs-photo',
145 'type' => 'checkbox',
146 'description' => __( 'Checked if this post needs a photo.', 'edit-flow' ),
147 ),
148 array(
149 'name' => __( 'Word Count', 'edit-flow' ),
150 'slug' => 'word-count',
151 'type' => 'number',
152 'description' => __( 'Required post length in words.', 'edit-flow' ),
153 ),
154 );
155 // Load the metadata fields if the slugs don't conflict
156 foreach ( $default_metadata as $args ) {
157 if ( !term_exists( $args['slug'], self::metadata_taxonomy ) ) {
158 $this->insert_editorial_metadata_term( $args );
159 }
160 }
161 }
162
163 /**
164 * Upgrade our data in case we need to
165 *
166 * @since 0.7
167 */
168 function upgrade( $previous_version ) {
169 global $edit_flow;
170
171 // Upgrade path to v0.7
172 if ( version_compare( $previous_version, '0.7' , '<' ) ) {
173 // Technically we've run this code before so we don't want to auto-install new data
174 $edit_flow->update_module_option( $this->module->name, 'loaded_once', true );
175 }
176 // Upgrade path to v0.7.4
177 if ( version_compare( $previous_version, '0.7.4', '<' ) ) {
178 // Editorial metadata descriptions become base64_encoded, instead of maybe json_encoded.
179 $this->upgrade_074_term_descriptions( self::metadata_taxonomy );
180 }
181
182 }
183
184 /**
185 * Anything that needs to happen on the 'admin_init' hook
186 *
187 * @since 0.7.4
188 */
189 function action_admin_init() {
190
191 // Parse the query when we're ordering by an editorial metadata term
192 add_action( 'parse_query', array( $this, 'action_parse_query' ) );
193 }
194
195 /**
196 * Generate <select> HTML for all of the metadata types
197 */
198 function get_select_html( $description ) {
199 $current_metadata_type = $description->type;
200 $metadata_types = $this->get_supported_metadata_types();
201 ?>
202 <select id="<?php echo self::metadata_taxonomy; ?>'_type" name="<?php echo self::metadata_taxonomy; ?>'_type">
203 <?php foreach ( $metadata_types as $metadata_type => $metadata_type_name ) : ?>
204 <option value="<?php echo $metadata_type; ?>" <?php selected( $metadata_type, $current_metadata_type ); ?>><?php echo $metadata_type_name; ?></option>
205 <?php endforeach; ?>
206 </select>
207 <?php
208 }
209
210 /**
211 * Prepare an array of supported editorial metadata types
212 *
213 * @return array $supported_metadata_types All of the supported metadata
214 */
215 function get_supported_metadata_types() {
216 $supported_metadata_types = array(
217 'checkbox' => __('Checkbox', 'edit-flow'),
218 'date' => __('Date', 'edit-flow'),
219 'location' => __('Location', 'edit-flow'),
220 'number' => __('Number', 'edit-flow'),
221 'paragraph' => __('Paragraph', 'edit-flow'),
222 'text' => __('Text', 'edit-flow'),
223 'user' => __('User', 'edit-flow'),
224 );
225 return $supported_metadata_types;
226 }
227
228 /**
229 * Enqueue relevant admin Javascript
230 */
231 function add_admin_scripts() {
232 global $current_screen, $pagenow;
233
234 // Add the metabox date picker JS and CSS
235 $current_post_type = $this->get_current_post_type();
236 $supported_post_types = $this->get_post_types_for_module( $this->module );
237 if ( in_array( $current_post_type, $supported_post_types ) ) {
238 $this->enqueue_datepicker_resources();
239
240 // Now add the rest of the metabox CSS
241 wp_enqueue_style( 'edit_flow-editorial_metadata-styles', $this->module_url . 'lib/editorial-metadata.css', false, EDIT_FLOW_VERSION, 'all' );
242 }
243 // A bit of custom CSS for the Manage Posts view if we have viewable metadata
244 if ( $current_screen->base == 'edit' && in_array( $current_post_type, $supported_post_types ) ) {
245 $terms = $this->get_editorial_metadata_terms();
246 $viewable_terms = array();
247 foreach( $terms as $term ) {
248 if ( $term->viewable )
249 $viewable_terms[] = $term;
250 }
251 if ( !empty( $viewable_terms ) ) {
252 $css_rules = array(
253 '.wp-list-table.fixed .column-author' => array(
254 'min-width: 7em;',
255 'width: auto;',
256 ),
257 '.wp-list-table.fixed .column-tags' => array(
258 'min-width: 7em;',
259 'width: auto;',
260 ),
261 '.wp-list-table.fixed .column-categories' => array(
262 'min-width: 7em;',
263 'width: auto;',
264 ),
265 );
266 foreach( $viewable_terms as $viewable_term ) {
267 switch( $viewable_term->type ) {
268 case 'checkbox':
269 case 'number':
270 case 'date':
271 $css_rules['.wp-list-table.fixed .column-' . $this->module->slug . '-' . $viewable_term->slug] = array(
272 'min-width: 6em;',
273 );
274 break;
275 case 'location':
276 case 'text':
277 case 'user':
278 $css_rules['.wp-list-table.fixed .column-' . $this->module->slug . '-' . $viewable_term->slug] = array(
279 'min-width: 7em;',
280 );
281 break;
282 case 'paragraph':
283 $css_rules['.wp-list-table.fixed .column-' . $this->module->slug . '-' . $viewable_term->slug] = array(
284 'min-width: 8em;',
285 );
286 break;
287 }
288 }
289 // Allow users to filter out rules if there's something wonky
290 $css_rules = apply_filters( 'ef_editorial_metadata_manage_posts_css_rules', $css_rules );
291 echo "<style type=\"text/css\">\n";
292 foreach( (array)$css_rules as $css_property => $rules ) {
293 echo $css_property . " {" . implode( ' ', $rules ) . "}\n";
294 }
295 echo '</style>';
296 }
297
298 }
299
300 // Load Javascript specific to the editorial metadata configuration view
301 if ( $this->is_whitelisted_settings_view( $this->module->name ) ) {
302 wp_enqueue_script( 'jquery-ui-sortable' );
303 wp_enqueue_script( 'edit-flow-editorial-metadata-configure', EDIT_FLOW_URL . 'modules/editorial-metadata/lib/editorial-metadata-configure.js', array( 'jquery', 'jquery-ui-sortable', 'edit-flow-settings-js' ), EDIT_FLOW_VERSION, true );
304 }
305 }
306
307 /**
308 * Register the post metadata taxonomy
309 */
310 function register_taxonomy() {
311
312 // We need to make sure taxonomy is registered for all of the post types that support it
313 $supported_post_types = $this->get_post_types_for_module( $this->module );
314
315 register_taxonomy( self::metadata_taxonomy, $supported_post_types,
316 array(
317 'public' => false,
318 'labels' => array(
319 'name' => _x( 'Editorial Metadata', 'taxonomy general name', 'edit-flow' ),
320 'singular_name' => _x( 'Editorial Metadata', 'taxonomy singular name', 'edit-flow' ),
321 'search_items' => __( 'Search Editorial Metadata', 'edit-flow' ),
322 'popular_items' => __( 'Popular Editorial Metadata', 'edit-flow' ),
323 'all_items' => __( 'All Editorial Metadata', 'edit-flow' ),
324 'edit_item' => __( 'Edit Editorial Metadata', 'edit-flow' ),
325 'update_item' => __( 'Update Editorial Metadata', 'edit-flow' ),
326 'add_new_item' => __( 'Add New Editorial Metadata', 'edit-flow' ),
327 'new_item_name' => __( 'New Editorial Metadata', 'edit-flow' ),
328 ),
329 'rewrite' => false,
330 )
331 );
332 }
333
334 /*****************************************************
335 * Post meta box generation and processing
336 ****************************************************/
337
338 /**
339 * Load the post metaboxes for all of the post types that are supported
340 */
341 function handle_post_metaboxes() {
342 $title = __( 'Editorial Metadata', 'edit-flow' );
343 if ( current_user_can( 'manage_options' ) ) {
344 // Make the metabox title include a link to edit the Editorial Metadata terms. Logic similar to how Core dashboard widgets work.
345 $url = add_query_arg( 'page', 'ef-editorial-metadata-settings', get_admin_url( null, 'admin.php' ) );
346 $title .= ' <span class="postbox-title-action"><a href="' . esc_url( $url ) . '" class="edit-box open-box">' . __( 'Configure' ) . '</a></span>';
347 }
348
349 $supported_post_types = $this->get_post_types_for_module( $this->module );
350 foreach ( $supported_post_types as $post_type ) {
351 add_meta_box( self::metadata_taxonomy, $title, array( $this, 'display_meta_box' ), $post_type, 'side' );
352 }
353 }
354
355 /**
356 * Displays HTML output for Editorial Metadata post meta box
357 *
358 * @param object $post Current post
359 */
360 function display_meta_box( $post ) {
361 echo "<div id='" . self::metadata_taxonomy . "_meta_box'>";
362 // Add nonce for verification upon save
363 echo "<input type='hidden' name='" . self::metadata_taxonomy . "_nonce' value='" . wp_create_nonce(__FILE__) . "' />";
364
365 $terms = $this->get_editorial_metadata_terms();
366 if ( !count( $terms ) ) {
367 $message = __( 'No editorial metadata available.' );
368 if ( current_user_can( 'manage_options' ) )
369 $message .= sprintf( __( ' <a href="%s">Add fields to get started</a>.' ), $this->get_link() );
370 else
371 $message .= __( ' Encourage your site administrator to configure your editorial workflow by adding editorial metadata.' );
372 echo '<p>' . $message . '</p>';
373 } else {
374 foreach ( $terms as $term ) {
375 $postmeta_key = $this->get_postmeta_key( $term );
376 $current_metadata = esc_attr( $this->get_postmeta_value( $term, $post->ID ) );
377 $type = $term->type;
378 $description = $term->description;
379 if ( $description )
380 $description_span = "<span class='description'>$description</span>";
381 else
382 $description_span = '';
383 echo "<div class='" . self::metadata_taxonomy . " " . self::metadata_taxonomy . "_$type'>";
384 switch( $type ) {
385 case "date":
386 // TODO: Move this to a function
387 if ( !empty( $current_metadata ) ) {
388 // Turn timestamp into a human-readable date
389 $current_metadata = date( 'M d Y' , intval( $current_metadata ) );
390 }
391 echo "<label for='$postmeta_key'>{$term->name}</label>";
392 if ( $description_span )
393 echo "<label for='$postmeta_key'>$description_span</label>";
394 echo "<input id='$postmeta_key' name='$postmeta_key' type='text' class='date-pick' value='$current_metadata' />";
395 break;
396 case "location":
397 echo "<label for='$postmeta_key'>{$term->name}</label>";
398 if ( $description_span )
399 echo "<label for='$postmeta_key'>$description_span</label>";
400 echo "<input id='$postmeta_key' name='$postmeta_key' type='text' value='$current_metadata' />";
401 if ( !empty( $current_metadata ) )
402 echo "<div><a href='http://maps.google.com/?q={$current_metadata}&t=m' target='_blank'>" . sprintf( __( 'View &#8220;%s&#8221; on Google Maps', 'edit-flow' ), $current_metadata ) . "</a></div>";
403 break;
404 case "text":
405 echo "<label for='$postmeta_key'>{$term->name}$description_span</label>";
406 echo "<input id='$postmeta_key' name='$postmeta_key' type='text' value='$current_metadata' />";
407 break;
408 case "paragraph":
409 echo "<label for='$postmeta_key'>{$term->name}$description_span</label>";
410 echo "<textarea id='$postmeta_key' name='$postmeta_key'>$current_metadata</textarea>";
411 break;
412 case "checkbox":
413 echo "<label for='$postmeta_key'>{$term->name}$description_span</label>";
414 echo "<input id='$postmeta_key' name='$postmeta_key' type='checkbox' value='1' " . checked($current_metadata, 1, false) . " />";
415 break;
416 case "user":
417 echo "<label for='$postmeta_key'>{$term->name}$description_span</label>";
418 $user_dropdown_args = array(
419 'show_option_all' => __( '-- Select a user --', 'edit-flow' ),
420 'name' => $postmeta_key,
421 'selected' => $current_metadata
422 );
423 wp_dropdown_users( $user_dropdown_args );
424 break;
425 case "number":
426 echo "<label for='$postmeta_key'>{$term->name}$description_span</label>";
427 echo "<input id='$postmeta_key' name='$postmeta_key' type='text' value='$current_metadata' />";
428 break;
429 default:
430 echo "<p>" . __( 'This editorial metadata type is not yet supported.', 'edit-flow' ) . "</p>";
431 }
432 echo "</div>";
433 echo "<div class='clear'></div>";
434 } // Done iterating through metadata terms
435 }
436 echo "</div>";
437 }
438
439 /**
440 * Save any values in the editorial metadata post meta box
441 *
442 * @param int $id Unique ID for the post being saved
443 * @param object $post Post object
444 */
445 function save_meta_box( $id, $post ) {
446
447 // Authentication checks: make sure data came from our meta box and that the current user is allowed to edit the post
448 // TODO: switch to using check_admin_referrer? See core (e.g. edit.php) for usage
449 if ( ! isset( $_POST[self::metadata_taxonomy . "_nonce"] )
450 || ! wp_verify_nonce( $_POST[self::metadata_taxonomy . "_nonce"], __FILE__ ) ) {
451 return $id;
452 }
453
454 if( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
455 || ! in_array( $post->post_type, $this->get_post_types_for_module( $this->module ) )
456 || $post->post_type == 'post' && !current_user_can( 'edit_post', $id )
457 || $post->post_type == 'page' && !current_user_can( 'edit_page', $id ) ) {
458 return $id;
459 }
460
461 // Authentication passed, let's save the data
462 $terms = $this->get_editorial_metadata_terms();
463 $term_slugs = array();
464
465 foreach ( $terms as $term ) {
466 // Setup the key for this editorial metadata term (same as what's in $_POST)
467 $key = $this->get_postmeta_key( $term );
468
469 // Get the current editorial metadata
470 // TODO: do we care about the current_metadata at all?
471 //$current_metadata = get_post_meta( $id, $key, true );
472
473 $new_metadata = isset( $_POST[$key] ) ? $_POST[$key] : '';
474
475 if ( empty ( $new_metadata ) ) {
476 delete_post_meta( $id, $key );
477 } else {
478
479 $type = $term->type;
480 // TODO: Move this to a function
481 if ( $type == 'date' ) {
482 $new_metadata = strtotime( $new_metadata );
483 }
484 if ( $type == 'number' ) {
485 $new_metadata = (int)$new_metadata;
486 }
487
488 $new_metadata = strip_tags( $new_metadata );
489 update_post_meta( $id, $key, $new_metadata );
490
491 // Add the slugs of the terms with non-empty new metadata to an array
492 $term_slugs[] = $term->slug;
493 }
494 }
495
496 // Relate the post to the terms used and taxonomy type (wp_term_relationships table).
497 // This will allow us to update and display the count of metadata in posts in use per term.
498 // TODO: Core only correlates posts with terms if the post_status is publish. Do we care what it is?
499 if ( $post->post_status === 'publish' ) {
500 wp_set_object_terms( $id, $term_slugs, self::metadata_taxonomy );
501 }
502 }
503
504 /**
505 * Generate a unique key based on the term
506 *
507 * @param object $term Term object
508 * @return string $postmeta_key Unique key
509 */
510 function get_postmeta_key( $term ) {
511 $key = self::metadata_postmeta_key;
512 $type = $term->type;
513 $prefix = "{$key}_{$type}";
514 $postmeta_key = "{$prefix}_" . ( is_object( $term ) ? $term->slug : $term );
515 return $postmeta_key;
516 }
517
518 /**
519 * Returns the value for the given metadata
520 *
521 * @param object|string|int term The term object, slug or ID for the metadata field term
522 * @param int post_id The ID of the post
523 */
524 function get_postmeta_value( $term, $post_id ) {
525 if( ! is_object( $term ) ) {
526 if ( is_int( $term ) )
527 $term = $this->get_editorial_metadata_term_by( 'id', $term );
528 else
529 $term = $this->get_editorial_metadata_term_by( 'slug', $term );
530 }
531 $postmeta_key = $this->get_postmeta_key( $term );
532 return get_metadata( 'post', $post_id, $postmeta_key, true );
533 }
534
535 /**
536 * Get all of the editorial metadata terms as objects and sort by position
537 * @todo Figure out what we should do with the filter...
538 *
539 * @param array $filter_args Filter to specific arguments
540 * @return array $ordered_terms The terms as they should be ordered
541 */
542 function get_editorial_metadata_terms( $filter_args = array() ) {
543
544
545 $args = array(
546 'orderby' => apply_filters( 'ef_editorial_metadata_term_order', 'name' ),
547 'hide_empty' => false
548 );
549 $terms = get_terms( self::metadata_taxonomy, $args );
550 $ordered_terms = array();
551 $hold_to_end = array();
552 // Order the terms
553 foreach ( $terms as $key => $term ) {
554
555 // Unencode and set all of our psuedo term meta because we need the position and viewable if they exists
556 // First do an array_merge() on the term object to make sure the keys exist, then array_merge()
557 // any values that may already exist
558 $unencoded_description = $this->get_unencoded_description( $term->description );
559 $defaults = array(
560 'description' => '',
561 'viewable' => false,
562 'position' => false,
563 );
564 $term = array_merge( $defaults, (array)$term );
565 if ( is_array( $unencoded_description ) ) {
566 $term = array_merge( $term, $unencoded_description );
567 }
568 $term = (object)$term;
569 // We used to store the description field in a funny way
570 if ( isset( $term->desc ) ) {
571 $term->description = $term->desc;
572 unset( $term->desc );
573 }
574 // Only add the term to the ordered array if it has a set position and doesn't conflict with another key
575 // Otherwise, hold it for later
576 if ( $term->position && !array_key_exists( $term->position, $ordered_terms ) )
577 $ordered_terms[(int)$term->position] = $term;
578 else
579 $hold_to_end[] = $term;
580 }
581 // Sort the items numerically by key
582 ksort( $ordered_terms, SORT_NUMERIC );
583 // Append all of the terms that didn't have an existing position
584 foreach( $hold_to_end as $unpositioned_term )
585 $ordered_terms[] = $unpositioned_term;
586
587 // If filter arguments were passed, do our filtering
588 $ordered_terms = wp_filter_object_list( $ordered_terms, $filter_args );
589 return $ordered_terms;
590 }
591
592 /**
593 * Returns a term for single metadata field
594 *
595 * @param int|string $field The slug or ID for the metadata field term to return
596 * @return object $term Term's object representation
597 */
598 function get_editorial_metadata_term_by( $field, $value ) {
599
600 $term = get_term_by( $field, $value, self::metadata_taxonomy );
601 if ( ! $term || is_wp_error( $term ) )
602 return $term;
603
604 // Unencode and set all of our psuedo term meta because we need the position and viewable if they exists
605 $term->position = false;
606 $term->viewable = false;
607 $unencoded_description = $this->get_unencoded_description( $term->description );
608 if ( is_array( $unencoded_description ) ) {
609 foreach( $unencoded_description as $key => $value ) {
610 $term->$key = $value;
611 }
612 // We used to store the description field in a funny way
613 if ( isset( $term->desc ) ) {
614 $term->description = $term->desc;
615 unset( $term->desc );
616 }
617 }
618 return $term;
619 }
620
621 /**
622 * Register editorial metadata fields as columns in the manage posts view
623 * Only adds columns for the currently active post types - logic controlled in $this->init()
624 *
625 * @since 0.7
626 * @uses apply_filters( 'manage_posts_columns' ) in wp-admin/includes/class-wp-posts-list-table.php
627 *
628 * @param array $posts_columns Existing post columns prepared by WP_List_Table
629 * @param array $posts_columns Previous post columns with the new values
630 */
631 function filter_manage_posts_columns( $posts_columns ) {
632 $screen = get_current_screen();
633
634 add_filter( "manage_{$screen->id}_sortable_columns", array( $this, 'filter_manage_posts_sortable_columns' ) );
635
636 $terms = $this->get_editorial_metadata_terms( array( 'viewable' => true ) );
637 foreach( $terms as $term ) {
638 // Prefixing slug with module slug because it isn't stored prefixed and we want to avoid collisions
639 $key = $this->module->slug . '-' . $term->slug;
640 $posts_columns[$key] = $term->name;
641 }
642 return $posts_columns;
643 }
644
645 /**
646 * Register any viewable date editorial metadata as a sortable column
647 *
648 * @since 0.7.4
649 *
650 * @param array $sortable_columns Any existing sortable columns (e.g. Title)
651 * @return array $sortable_columms Sortable columns with editorial metadata date fields added
652 */
653 function filter_manage_posts_sortable_columns( $sortable_columns ) {
654
655 $terms = $this->get_editorial_metadata_terms( array( 'viewable' => true, 'type' => 'date' ) );
656 foreach( $terms as $term ) {
657 // Prefixing slug with module slug because it isn't stored prefixed and we want to avoid collisions
658 $key = $this->module->slug . '-' . $term->slug;
659 $sortable_columns[$key] = $key;
660 }
661 return $sortable_columns;
662 }
663
664 /**
665 * If we're ordering by a sortable column, let's modify the query
666 *
667 * @since 0.7.4
668 */
669 function action_parse_query( $query ) {
670
671 if ( is_admin() && false !== stripos( get_query_var( 'orderby' ), $this->module->slug ) ) {
672 $term_slug = sanitize_key( str_replace( $this->module->slug . '-', '', get_query_var( 'orderby') ) );
673 $term = $this->get_editorial_metadata_term_by( 'slug', $term_slug );
674 $meta_key = $this->get_postmeta_key( $term );
675 set_query_var( 'meta_key', $meta_key );
676 set_query_var( 'orderby', 'meta_value_num' );
677 }
678 }
679
680 /**
681 * Handle the output of an editorial metadata custom column
682 * Logic for the post types this is called on is controlled in $this->init()
683 *
684 * @since 0.7
685 * @uses do_action( 'manage_posts_custom_column' ) in wp-admin/includes/class-wp-posts-list-table.php
686 *
687 * @param string $column_name Unique string for the column
688 * @param int $post_id ID for the post of the row
689 */
690 function action_manage_posts_custom_column( $column_name, $post_id ) {
691
692 $terms = $this->get_editorial_metadata_terms();
693 // We're looking for the proper term to display its saved value
694 foreach( $terms as $term ) {
695 $key = $this->module->slug . '-' . $term->slug;
696 if ( $column_name != $key )
697 continue;
698
699 $postmeta_key = $this->get_postmeta_key( $term );
700 $current_metadata = $this->get_postmeta_value( $term, $post_id );
701 $type = $term->type;
702 switch( $type ) {
703 case "date":
704 if ( !empty( $current_metadata ) )
705 $current_metadata = date( get_option( 'date_format' ), intval( $current_metadata ) );
706 case "location":
707 case "text":
708 case "number":
709 case "paragraph":
710 echo esc_html( $current_metadata );
711 break;
712 case "checkbox":
713 if ( $current_metadata )
714 echo __( 'Yes', 'edit-flow' );
715 else
716 echo __( 'No', 'edit-flow' );
717 break;
718 case "user":
719 $userdata = get_userdata( $current_metadata );
720 if ( is_object( $userdata ) )
721 echo esc_html( $userdata->display_name );
722 break;
723 default:
724 break;
725 }
726
727 }
728
729 }
730
731 /**
732 * If the Edit Flow Calendar is enabled, add viewable Editorial Metadata terms
733 *
734 * @since 0.7
735 * @uses apply_filters( 'ef_calendar_item_information_fields' )
736 *
737 * @param array $calendar_fields Additional data fields to include on the calendar
738 * @param int $post_id Unique ID for the post data we're building
739 * @return array $calendar_fields Calendar fields with our viewable Editorial Metadata added
740 */
741 function filter_calendar_item_fields( $calendar_fields, $post_id ) {
742
743
744 // Make sure we respect which post type we're on
745 if ( !in_array( get_post_type( $post_id ), $this->get_post_types_for_module( $this->module ) ) )
746 return $calendar_fields;
747
748 $terms = $this->get_editorial_metadata_terms( array( 'viewable' => true ) );
749
750 foreach( $terms as $term ) {
751 $key = $this->module->slug . '-' . $term->slug;
752
753 // Default values
754 $term_data = array(
755 'label' => $term->name,
756 'value' => '',
757 );
758 $postmeta_key = $this->get_postmeta_key( $term );
759 $current_metadata = $this->get_postmeta_value( $term, $post_id );
760 $type = $term->type;
761 switch( $type ) {
762 case "date":
763 if ( !empty( $current_metadata ) )
764 $current_metadata = date( get_option( 'date_format' ), intval( $current_metadata ) );
765 $term_data['value'] = esc_html( $current_metadata );
766 break;
767 case "location":
768 case "text":
769 case "number":
770 case "paragraph":
771 if ( $current_metadata )
772 $term_data['value'] = esc_html( $current_metadata );
773 break;
774 case "checkbox":
775 if ( $current_metadata )
776 $term_data['value'] = __( 'Yes', 'edit-flow' );
777 else
778 $term_data['value'] = __( 'No', 'edit-flow' );
779 break;
780 case "user":
781 $userdata = get_userdata( $current_metadata );
782 if ( is_object( $userdata ) )
783 $term_data['value'] = esc_html( $userdata->display_name );
784 break;
785 default:
786 break;
787 }
788
789 $calendar_fields[$key] = $term_data;
790 }
791 return $calendar_fields;
792
793 }
794
795 /**
796 * If the Edit Flow Story Budget is enabled, register our viewable terms as columns
797 *
798 * @since 0.7
799 * @uses apply_filters( 'ef_story_budget_term_columns' )
800 *
801 * @param array $term_columns The existing columns on the story budget
802 * @return array $term_columns Term columns with viewable Editorial Metadata terms
803 */
804 function filter_story_budget_term_columns( $term_columns ) {
805
806 $terms = $this->get_editorial_metadata_terms( array( 'viewable' => true ) );
807 foreach( $terms as $term ) {
808 // Prefixing slug with module slug because it isn't stored prefixed and we want to avoid collisions
809 $key = $this->module->slug . '-' . $term->slug;
810 // Switch to underscores
811 $key = str_replace( '-', '_', $key );
812 $term_columns[$key] = $term->name;
813 }
814 return $term_columns;
815
816 }
817
818 /**
819 * If the Edit Flow Story Budget is enabled,
820 *
821 * @since 0.7
822 * @uses apply_filters( 'ef_story_budget_term_column_value' )
823 *
824 * @param object $post The post we're displaying
825 * @param string $column_name Name of the column, as registered with EF_Story_Budget::register_term_columns
826 * @param object $parent_term The parent term for the term column
827 */
828 function filter_story_budget_term_column_values( $column_name, $post, $parent_term ) {
829
830 $local_column_name = str_replace( '_', '-', $column_name );
831 // Don't accidentally handle values not our own
832 if ( false === strpos( $local_column_name, $this->module->slug ) )
833 return $column_name;
834
835 $term_slug = str_replace( $this->module->slug . '-', '', $local_column_name );
836 $term = $this->get_editorial_metadata_term_by( 'slug', $term_slug );
837
838 // Don't allow non-viewable term data to be displayed
839 if ( !$term->viewable )
840 return $column_name;
841
842 $output = '';
843 $postmeta_key = $this->get_postmeta_key( $term );
844 $current_metadata = $this->get_postmeta_value( $term, $post->ID );
845 switch( $term->type ) {
846 case "date":
847 if ( !empty( $current_metadata ) )
848 $current_metadata = date( get_option( 'date_format' ), intval( $current_metadata ) );
849 $output = esc_html( $current_metadata );
850 break;
851 case "location":
852 case "text":
853 case "number":
854 case "paragraph":
855 if ( $current_metadata )
856 $output = esc_html( $current_metadata );
857 break;
858 case "checkbox":
859 if ( $current_metadata )
860 $output = __( 'Yes', 'edit-flow' );
861 else
862 $output = __( 'No', 'edit-flow' );
863 break;
864 case "user":
865 $userdata = get_userdata( $current_metadata );
866 if ( is_object( $userdata ) )
867 $output = esc_html( $userdata->display_name );
868 break;
869 default:
870 break;
871 }
872 return $output;
873
874 }
875
876 /**
877 * Update an existing editorial metadata term if the term_id exists
878 *
879 * @since 0.7
880 *
881 * @param int $term_id The term's unique ID
882 * @param array $args Any values that need to be updated for the term
883 * @return object|WP_Error $updated_term The updated term or a WP_Error object if something disastrous happened
884 */
885 function update_editorial_metadata_term( $term_id, $args ) {
886
887 $new_args = array();
888 $old_term = $this->get_editorial_metadata_term_by( 'id', $term_id );
889 if ( $old_term )
890 $old_args = array(
891 'position' => $old_term->position,
892 'name' => $old_term->name,
893 'slug' => $old_term->slug,
894 'description' => $old_term->description,
895 'type' => $old_term->type,
896 'viewable' => $old_term->viewable,
897 );
898 $new_args = array_merge( $old_args, $args );
899
900 // We're encoding metadata that isn't supported by default in the term's description field
901 $args_to_encode = array(
902 'description' => $new_args['description'],
903 'position' => $new_args['position'],
904 'type' => $new_args['type'],
905 'viewable' => $new_args['viewable'],
906 );
907 $encoded_description = $this->get_encoded_description( $args_to_encode );
908 $new_args['description'] = $encoded_description;
909
910 $updated_term = wp_update_term( $term_id, self::metadata_taxonomy, $new_args );
911 $updated_term = $this->get_editorial_metadata_term_by( 'id', $term_id );
912 return $updated_term;
913 }
914
915 /**
916 * Insert a new editorial metadata term
917 * @todo Handle conflicts with existing terms at that position (if relevant)
918 *
919 * @since 0.7
920 */
921 function insert_editorial_metadata_term( $args ) {
922
923
924 // Term is always added to the end of the list
925 $default_position = count( $this->get_editorial_metadata_terms() ) + 2;
926 $defaults = array(
927 'position' => $default_position,
928 'name' => '',
929 'slug' => '',
930 'description' => '',
931 'type' => '',
932 'viewable' => false,
933 );
934 $args = array_merge( $defaults, $args );
935 $term_name = $args['name'];
936 unset( $args['name'] );
937
938 // We're encoding metadata that isn't supported by default in the term's description field
939 $args_to_encode = array(
940 'description' => $args['description'],
941 'position' => $args['position'],
942 'type' => $args['type'],
943 'viewable' => $args['viewable'],
944 );
945 $encoded_description = $this->get_encoded_description( $args_to_encode );
946 $args['description'] = $encoded_description;
947
948 $inserted_term = wp_insert_term( $term_name, self::metadata_taxonomy, $args );
949 return $inserted_term;
950 }
951
952 /**
953 * Settings and other management code
954 */
955
956 /**
957 * Delete an existing editorial metadata term
958 *
959 * @since 0.7
960 *
961 * @param int $term_id The term we want deleted
962 * @return bool $result Whether or not the term was deleted
963 */
964 function delete_editorial_metadata_term( $term_id ) {
965 $result = wp_delete_term( $term_id, self::metadata_taxonomy );
966 return $result;
967 }
968
969 /**
970 * Generate a link to one of the editorial metadata actions
971 *
972 * @since 0.7
973 *
974 * @param array $args (optional) Action and any query args to add to the URL
975 * @return string $link Direct link to complete the action
976 */
977 function get_link( $args = array() ) {
978 if ( !isset( $args['action'] ) )
979 $args['action'] = '';
980 if ( !isset( $args['page'] ) )
981 $args['page'] = $this->module->settings_slug;
982 // Add other things we may need depending on the action
983 switch( $args['action'] ) {
984 case 'make-viewable':
985 case 'make-hidden':
986 case 'delete-term':
987 $args['nonce'] = wp_create_nonce( $args['action'] );
988 break;
989 default:
990 break;
991 }
992 return add_query_arg( $args, get_admin_url( null, 'admin.php' ) );
993 }
994
995 /**
996 * Handles a request to add a new piece of editorial metadata
997 */
998 function handle_add_editorial_metadata() {
999
1000 if ( !isset( $_POST['submit'], $_POST['form-action'], $_GET['page'] )
1001 || $_GET['page'] != $this->module->settings_slug || $_POST['form-action'] != 'add-term' )
1002 return;
1003
1004 if ( !wp_verify_nonce( $_POST['_wpnonce'], 'editorial-metadata-add-nonce' ) )
1005 wp_die( $this->module->messages['nonce-failed'] );
1006
1007 if ( !current_user_can( 'manage_options' ) )
1008 wp_die( $this->module->messages['invalid-permissions'] );
1009
1010 // Sanitize all of the user-entered values
1011 $term_name = strip_tags( trim( $_POST['metadata_name'] ) );
1012 $term_slug = ( !empty( $_POST['metadata_slug'] ) ) ? sanitize_title( $_POST['metadata_slug'] ) : sanitize_title( $term_name );
1013 $term_description = strip_tags( trim( $_POST['metadata_description'] ) );
1014 $term_type = sanitize_key( $_POST['metadata_type'] );
1015
1016 $_REQUEST['form-errors'] = array();
1017
1018 /**
1019 * Form validation for adding new editorial metadata term
1020 *
1021 * Details
1022 * - "name", "slug", and "type" are required fields
1023 * - "description" can accept a limited amount of HTML, and is optional
1024 */
1025 // Field is required
1026 if ( empty( $term_name ) )
1027 $_REQUEST['form-errors']['name'] = __( 'Please enter a name for the editorial metadata.', 'edit-flow' );
1028 // Field is required
1029 if ( empty( $term_slug ) )
1030 $_REQUEST['form-errors']['slug'] = __( 'Please enter a slug for the editorial metadata.', 'edit-flow' );
1031 if ( term_exists( $term_slug ) )
1032 $_REQUEST['form-errors']['name'] = __( 'Name conflicts with existing term. Please choose another.', 'edit-flow' );
1033 // Check to ensure a term with the same name doesn't exist
1034 if ( $this->get_editorial_metadata_term_by( 'name', $term_name, self::metadata_taxonomy ) )
1035 $_REQUEST['form-errors']['name'] = __( 'Name already in use. Please choose another.', 'edit-flow' );
1036 // Check to ensure a term with the same slug doesn't exist
1037 if ( $this->get_editorial_metadata_term_by( 'slug', $term_slug ) )
1038 $_REQUEST['form-errors']['slug'] = __( 'Slug already in use. Please choose another.', 'edit-flow' );
1039 // Check to make sure the status doesn't already exist as another term because otherwise we'd get a weird slug
1040 // Check that the term name doesn't exceed 50 chars
1041 if ( strlen( $term_name ) > 50 )
1042 $_REQUEST['form-errors']['name'] = __( 'Name cannot exceed 50 characters. Please try a shorter name.', 'edit-flow' );
1043 // Metadata type needs to pass our whitelist check
1044 $metadata_types = $this->get_supported_metadata_types();
1045 if ( empty( $_POST['metadata_type'] ) || !isset( $metadata_types[$_POST['metadata_type'] ] ) )
1046 $_REQUEST['form-errors']['type'] = __( 'Please select a valid metadata type.', 'edit-flow' );
1047 // Metadata viewable needs to be a valid Yes or No
1048 $term_viewable = false;
1049 if ( $_POST['metadata_viewable'] == 'yes' )
1050 $term_viewable = true;
1051
1052 // Kick out if there are any errors
1053 if ( count( $_REQUEST['form-errors'] ) ) {
1054 $_REQUEST['error'] = 'form-error';
1055 return;
1056 }
1057
1058 // Try to add the status
1059 $args = array(
1060 'name' => $term_name,
1061 'description' => $term_description,
1062 'slug' => $term_slug,
1063 'type' => $term_type,
1064 'viewable' => $term_viewable,
1065 );
1066 $return = $this->insert_editorial_metadata_term( $args );
1067 if ( is_wp_error( $return ) )
1068 wp_die( __( 'Error adding term.', 'edit-flow' ) );
1069
1070 $redirect_url = add_query_arg( array( 'page' => $this->module->settings_slug, 'message' => 'term-added' ), get_admin_url( null, 'admin.php' ) );
1071 wp_redirect( $redirect_url );
1072 exit;
1073 }
1074
1075 /**
1076 * Handles a request to edit an editorial metadata
1077 */
1078 function handle_edit_editorial_metadata() {
1079 if ( !isset( $_POST['submit'], $_GET['page'], $_GET['action'], $_GET['term-id'] )
1080 || $_GET['page'] != $this->module->settings_slug || $_GET['action'] != 'edit-term' )
1081 return;
1082
1083 if ( !wp_verify_nonce( $_POST['_wpnonce'], 'editorial-metadata-edit-nonce' ) )
1084 wp_die( $this->module->messages['nonce-failed'] );
1085
1086 if ( !current_user_can( 'manage_options' ) )
1087 wp_die( $this->module->messages['invalid-permissions'] );
1088
1089 if ( !$existing_term = $this->get_editorial_metadata_term_by( 'id', (int)$_GET['term-id'] ) )
1090 wp_die( $this->module->messsage['term-error'] );
1091
1092 $new_name = strip_tags( trim( $_POST['name'] ) );
1093 $new_description = strip_tags( trim( $_POST['description'] ) );
1094
1095 /**
1096 * Form validation for editing editorial metadata term
1097 *
1098 * Details
1099 * - "name", "slug", and "type" are required fields
1100 * - "description" can accept a limited amount of HTML, and is optional
1101 */
1102 $_REQUEST['form-errors'] = array();
1103 // Check if name field was filled in
1104 if( empty( $new_name ) )
1105 $_REQUEST['form-errors']['name'] = __( 'Please enter a name for the editorial metadata', 'edit-flow' );
1106
1107 // Check that the name isn't numeric
1108 if ( is_numeric( $new_name ) )
1109 $_REQUEST['form-errors']['name'] = __( 'Please enter a valid, non-numeric name for the editorial metadata.', 'edit-flow' );
1110
1111 $term_exists = term_exists( sanitize_title( $new_name ) );
1112 if ( $term_exists && $term_exists != $existing_term->term_id )
1113 $_REQUEST['form-errors']['name'] = __( 'Metadata name conflicts with existing term. Please choose another.', 'edit-flow' );
1114
1115 // Check to ensure a term with the same name doesn't exist,
1116 $search_term = $this->get_editorial_metadata_term_by( 'name', $new_name );
1117 if ( is_object( $search_term ) && $search_term->term_id != $existing_term->term_id )
1118 $_REQUEST['form-errors']['name'] = __( 'Name already in use. Please choose another.', 'edit-flow' );
1119 // or that the term name doesn't map to an existing term's slug
1120 $search_term = $this->get_editorial_metadata_term_by( 'slug', sanitize_title( $new_name ) );
1121 if ( is_object( $search_term ) && $search_term->term_id != $existing_term->term_id )
1122 $_REQUEST['form-errors']['name'] = __( 'Name conflicts with slug for another term. Please choose something else.', 'edit-flow' );
1123
1124 // Check that the term name doesn't exceed 50 chars
1125 if ( strlen( $new_name ) > 50 )
1126 $_REQUEST['form-errors']['name'] = __( 'Name cannot exceed 50 characters. Please try a shorter name.', 'edit-flow' );
1127 // Make sure the viewable state is valid
1128 $new_viewable = false;
1129 if ( $_POST['viewable'] == 'yes' )
1130 $new_viewable = true;
1131
1132 // Kick out if there are any errors
1133 if ( count( $_REQUEST['form-errors'] ) ) {
1134 $_REQUEST['error'] = 'form-error';
1135 return;
1136 }
1137
1138 // Try to add the metadata term
1139 $args = array(
1140 'name' => $new_name,
1141 'description' => $new_description,
1142 'viewable' => $new_viewable,
1143 );
1144 $return = $this->update_editorial_metadata_term( $existing_term->term_id, $args );
1145 if ( is_wp_error( $return ) )
1146 wp_die( __( 'Error updating term.', 'edit-flow' ) );
1147
1148 $redirect_url = add_query_arg( array( 'page' => $this->module->settings_slug, 'message' => 'term-updated' ), get_admin_url( null, 'admin.php' ) );
1149 wp_redirect( $redirect_url );
1150 exit;
1151 }
1152
1153 /**
1154 * Handle a $_GET request to change the visibility of an Editorial Metadata term
1155 *
1156 * @since 0.7
1157 */
1158 function handle_change_editorial_metadata_visibility() {
1159
1160 // Check that the current GET request is our GET request
1161 if ( !isset( $_GET['page'], $_GET['action'], $_GET['term-id'], $_GET['nonce'] )
1162 || $_GET['page'] != $this->module->settings_slug || !in_array( $_GET['action'], array( 'make-viewable', 'make-hidden' ) ) )
1163 return;
1164
1165 // Check for proper nonce
1166 if ( !wp_verify_nonce( $_GET['nonce'], 'make-viewable' ) && !wp_verify_nonce( $_GET['nonce'], 'make-hidden' ) )
1167 wp_die( $this->module->messages['nonce-failed'] );
1168
1169 // Only allow users with the proper caps
1170 if ( !current_user_can( 'manage_options' ) )
1171 wp_die( $this->module->messages['invalid-permissions'] );
1172
1173 $term_id = (int)$_GET['term-id'];
1174 $args = array();
1175 if ( $_GET['action'] == 'make-viewable' )
1176 $args['viewable'] = true;
1177 elseif ( $_GET['action'] == 'make-hidden' )
1178 $args['viewable'] = false;
1179
1180 $return = $this->update_editorial_metadata_term( $term_id, $args );
1181 if ( is_wp_error( $return ) )
1182 wp_die( __( 'Error updating term.', 'edit-flow' ) );
1183
1184 $redirect_url = $this->get_link( array( 'message' => 'term-visibility-changed' ) );
1185 wp_redirect( $redirect_url );
1186 exit;
1187
1188 }
1189
1190 /**
1191 * Handle the request to update a given Editorial Metadata term via inline edit
1192 *
1193 * @since 0.7
1194 */
1195 function handle_ajax_inline_save_term() {
1196
1197 if ( !wp_verify_nonce( $_POST['inline_edit'], 'editorial-metadata-inline-edit-nonce' ) )
1198 die( $this->module->messages['nonce-failed'] );
1199
1200 if ( !current_user_can( 'manage_options') )
1201 die( $this->module->messages['invalid-permissions'] );
1202
1203 $term_id = (int) $_POST['term_id'];
1204 if ( !$existing_term = $this->get_editorial_metadata_term_by( 'id', $term_id ) )
1205 die( $this->module->messsage['term-error'] );
1206
1207 $metadata_name = strip_tags( trim( $_POST['name'] ) );
1208 $metadata_description = strip_tags( trim( $_POST['description'] ) );
1209
1210 /**
1211 * Form validation for editing editorial metadata term
1212 */
1213 // Check if name field was filled in
1214 if ( empty( $metadata_name ) ) {
1215 $change_error = new WP_Error( 'invalid', __( 'Please enter a name for the editorial metadata', 'edit-flow' ) );
1216 die( $change_error->get_error_message() );
1217 }
1218
1219 // Check that the name isn't numeric
1220 if( is_numeric( $metadata_name) ) {
1221 $change_error = new WP_Error( 'invalid', __( 'Please enter a valid, non-numeric name for the editorial metadata.', 'edit-flow' ) );
1222 die( $change_error->get_error_message() );
1223 }
1224
1225 // Check that the term name doesn't exceed 50 chars
1226 if ( strlen( $metadata_name ) > 50 ) {
1227 $change_error = new WP_Error( 'invalid', __( 'Name cannot exceed 50 characters. Please try a shorter name.' ) );
1228 die( $change_error->get_error_message() );
1229 }
1230
1231 // Check to make sure the status doesn't already exist as another term because otherwise we'd get a fatal error
1232 $term_exists = term_exists( sanitize_title( $metadata_name ) );
1233 if ( $term_exists && $term_exists != $term_id ) {
1234 $change_error = new WP_Error( 'invalid', __( 'Metadata name conflicts with existing term. Please choose another.', 'edit-flow' ) );
1235 die( $change_error->get_error_message() );
1236 }
1237
1238 // Check to ensure a term with the same name doesn't exist,
1239 $search_term = get_term_by( 'name', $metadata_name, self::metadata_taxonomy );
1240 if ( is_object( $search_term ) && $search_term->term_id != $existing_term->term_id ) {
1241 $change_error = new WP_Error( 'invalid', __( 'Name already in use. Please choose another.', 'edit-flow' ) );
1242 die( $change_error->get_error_message() );
1243 }
1244 // or that the term name doesn't map to an existing term's slug
1245 $search_term = get_term_by( 'slug', sanitize_title( $metadata_name ), self::metadata_taxonomy );
1246 if ( is_object( $search_term ) && $search_term->term_id != $existing_term->term_id ) {
1247 $change_error = new WP_Error( 'invalid', __( 'Name conflicts with slug for another term. Please choose again.', 'edit-flow' ) );
1248 die( $change_error->get_error_message() );
1249 }
1250
1251 // Prepare the term name and description for saving
1252 $args = array(
1253 'name' => $metadata_name,
1254 'description' => $metadata_description,
1255 );
1256 $return = $this->update_editorial_metadata_term( $existing_term->term_id, $args );
1257 if( !is_wp_error( $return ) ) {
1258 set_current_screen( 'edit-editorial-metadata' );
1259 $wp_list_table = new EF_Editorial_Metadata_List_Table();
1260 $wp_list_table->prepare_items();
1261 echo $wp_list_table->single_row( $return );
1262 die();
1263 } else {
1264 $change_error = new WP_Error( 'invalid', sprintf( __( 'Could not update the term: <strong>%s</strong>', 'edit-flow' ), $status_name ) );
1265 die( $change_error->get_error_message() );
1266 }
1267
1268 }
1269
1270 /**
1271 * Handle the ajax request to update all of the term positions
1272 *
1273 * @since 0.7
1274 */
1275 function handle_ajax_update_term_positions() {
1276
1277 if ( !wp_verify_nonce( $_POST['editorial_metadata_sortable_nonce'], 'editorial-metadata-sortable' ) )
1278 $this->print_ajax_response( 'error', $this->module->messages['nonce-failed'] );
1279
1280 if ( !current_user_can( 'manage_options') )
1281 $this->print_ajax_response( 'error', $this->module->messages['invalid-permissions'] );
1282
1283 if ( !isset( $_POST['term_positions'] ) || !is_array( $_POST['term_positions'] ) )
1284 $this->print_ajax_response( 'error', __( 'Terms not set.', 'edit-flow' ) );
1285
1286 foreach ( $_POST['term_positions'] as $position => $term_id ) {
1287
1288 // Have to add 1 to the position because the index started with zero
1289 $args = array(
1290 'position' => (int)$position + 1,
1291 );
1292 $return = $this->update_editorial_metadata_term( (int)$term_id, $args );
1293 // @todo check that this was a valid return
1294 }
1295 $this->print_ajax_response( 'success', $this->module->messages['term-position-updated'] );
1296 }
1297
1298 /**
1299 * Handles a request to delete an editorial metadata term
1300 */
1301 function handle_delete_editorial_metadata() {
1302 if ( !isset( $_GET['page'], $_GET['action'], $_GET['term-id'] )
1303 || $_GET['page'] != $this->module->settings_slug || $_GET['action'] != 'delete-term' )
1304 return;
1305
1306 if ( !wp_verify_nonce( $_GET['nonce'], 'delete-term' ) )
1307 wp_die( $this->module->messages['nonce-failed'] );
1308
1309 if ( !current_user_can( 'manage_options' ) )
1310 wp_die( $this->module->messages['invalid-permissions'] );
1311
1312 if ( !$existing_term = $this->get_editorial_metadata_term_by( 'id', (int)$_GET['term-id'] ) )
1313 wp_die( $this->module->messsage['term-error'] );
1314
1315 $result = $this->delete_editorial_metadata_term( $existing_term->term_id );
1316 if ( !$result || is_wp_error( $result ) )
1317 wp_die( __( 'Error deleting term.', 'edit-flow' ) );
1318
1319 $redirect_url = add_query_arg( array( 'page' => $this->module->settings_slug, 'message' => 'term-deleted' ), get_admin_url( null, 'admin.php' ) );
1320 wp_redirect( $redirect_url );
1321 exit;
1322 }
1323
1324 /**
1325 * Register settings for notifications so we can partially use the Settings API
1326 * (We use the Settings API for form generation, but not saving)
1327 *
1328 * @since 0.7
1329 * @uses add_settings_section(), add_settings_field()
1330 */
1331 function register_settings() {
1332 add_settings_section( $this->module->options_group_name . '_general', false, '__return_false', $this->module->options_group_name );
1333 add_settings_field( 'post_types', __( 'Add to these post types:', 'edit-flow' ), array( $this, 'settings_post_types_option' ), $this->module->options_group_name, $this->module->options_group_name . '_general' );
1334 }
1335
1336 /**
1337 * Choose the post types for editorial metadata
1338 *
1339 * @since 0.7
1340 */
1341 function settings_post_types_option() {
1342 global $edit_flow;
1343 $edit_flow->settings->helper_option_custom_post_type( $this->module );
1344 }
1345
1346 /**
1347 * Validate data entered by the user
1348 *
1349 * @since 0.7
1350 *
1351 * @param array $new_options New values that have been entered by the user
1352 * @return array $new_options Form values after they've been sanitized
1353 */
1354 function settings_validate( $new_options ) {
1355
1356 // Whitelist validation for the post type options
1357 if ( !isset( $new_options['post_types'] ) )
1358 $new_options['post_types'] = array();
1359 $new_options['post_types'] = $this->clean_post_type_options( $new_options['post_types'], $this->module->post_type_support );
1360
1361 return $new_options;
1362 }
1363
1364 /**
1365 * Prepare and display the configuration view for editorial metadata.
1366 * There are four primary components:
1367 * - Form to add a new Editorial Metadata term
1368 * - Form generated by the settings API for managing Editorial Metadata options
1369 * - Table of existing Editorial Metadata terms with ability to take actions on each
1370 * - Full page width view for editing a single Editorial Metadata term
1371 *
1372 * @since 0.7
1373 */
1374 function print_configure_view() {
1375 global $edit_flow;
1376 $wp_list_table = new EF_Editorial_Metadata_List_Table();
1377 $wp_list_table->prepare_items();
1378 ?>
1379 <script type="text/javascript">
1380 var ef_confirm_delete_term_string = "<?php echo esc_js( __( 'Are you sure you want to delete this term? Any metadata for this term will remain but will not be visible unless this term is re-added.', 'edit-flow' ) ); ?>";
1381 </script>
1382 <?php if ( !isset( $_GET['action'] ) || ( isset( $_GET['action'] ) && $_GET['action'] != 'edit-term' ) ): ?>
1383 <div id="col-right">
1384 <div class="col-wrap">
1385 <form id="posts-filter" action="" method="post">
1386 <?php $wp_list_table->display(); ?>
1387 <?php wp_nonce_field( 'editorial-metadata-sortable', 'editorial-metadata-sortable' ); ?>
1388 </form>
1389 </div>
1390 </div><!-- /col-right -->
1391 <?php $wp_list_table->inline_edit(); ?>
1392 <?php endif; ?>
1393
1394 <?php if ( isset( $_GET['action'], $_GET['term-id'] ) && $_GET['action'] == 'edit-term' ): ?>
1395 <?php /** Full page width view for editing a given editorial metadata term **/ ?>
1396 <?php
1397 // Check whether the term exists
1398 $term_id = (int)$_GET['term-id'];
1399 $term = $this->get_editorial_metadata_term_by( 'id', $term_id );
1400 if ( !$term ) {
1401 echo '<div class="error"><p>' . $this->module->messages['term-missing'] . '</p></div>';
1402 return;
1403 }
1404 $metadata_types = $this->get_supported_metadata_types();
1405 $type = $term->type;
1406 $edit_term_link = $this->get_link( array( 'action' => 'edit-term', 'term-id' => $term->term_id ) );
1407
1408 $name = ( isset( $_POST['name'] ) ) ? stripslashes( $_POST['name'] ) : $term->name;
1409 $description = ( isset( $_POST['description'] ) ) ? stripslashes( $_POST['description'] ) : $term->description;
1410 if ( $term->viewable )
1411 $viewable = 'yes';
1412 else
1413 $viewable = 'no';
1414 $viewable = ( isset( $_POST['viewable'] ) ) ? stripslashes( $_POST['viewable'] ) : $viewable;
1415 ?>
1416
1417 <form method="post" action="<?php echo esc_url( $edit_term_link ); ?>" >
1418 <input type="hidden" name="action" value="editedtag" />
1419 <input type="hidden" name="tag_id" value="<?php echo esc_attr( $term->term_id ); ?>" />
1420 <input type="hidden" name="taxonomy" value="<?php echo esc_attr( self::metadata_taxonomy ) ?>" />
1421 <?php
1422 wp_original_referer_field();
1423 wp_nonce_field( 'editorial-metadata-edit-nonce' );
1424 ?>
1425 <table class="form-table">
1426 <tr class="form-field form-required">
1427 <th scope="row" valign="top"><label for="name"><?php _e( 'Name' ); ?></label></th>
1428 <td><input name="name" id="name" type="text" value="<?php echo esc_attr( $name ); ?>" size="40" aria-required="true" />
1429 <?php $edit_flow->settings->helper_print_error_or_description( 'name', __( 'The name is for labeling the metadata field.', 'edit-flow' ) ); ?>
1430 </tr>
1431 <tr class="form-field">
1432 <th scope="row" valign="top"><?php _e( 'Slug', 'edit-flow' ); ?></th>
1433 <td>
1434 <input type="text" disabled="disabled" value="<?php echo esc_attr( $term->slug ); ?>" />
1435 <p class="description"><?php _e( 'The slug cannot be changed once the term has been created.', 'edit-flow' ); ?></p>
1436 </td>
1437 </tr>
1438 <tr class="form-field">
1439 <th scope="row" valign="top"><label for="description"><?php _e( 'Description', 'edit-flow' ); ?></label></th>
1440 <td>
1441 <textarea name="description" id="description" rows="5" cols="50" style="width: 97%;"><?php echo esc_html( $description ); ?></textarea>
1442 <?php $edit_flow->settings->helper_print_error_or_description( 'description', __( 'The description can be used to communicate with your team about what the metadata is for.', 'edit-flow' ) ); ?>
1443 </td>
1444 </tr>
1445 <tr class="form-field">
1446 <th scope="row" valign="top"><?php _e( 'Type', 'edit-flow' ); ?></th>
1447 <td>
1448 <input type="text" disabled="disabled" value="<?php echo esc_attr( $metadata_types[$type] ); ?>" />
1449 <p class="description"><?php _e( 'The metadata type cannot be changed once created.', 'edit-flow' ); ?></p>
1450 </td>
1451 </tr>
1452 <tr class="form-field">
1453 <th scope="row" valign="top"><?php _e( 'Viewable', 'edit-flow' ); ?></th>
1454 <td>
1455 <?php
1456 $metadata_viewable_options = array(
1457 'no' => __( 'No', 'edit-flow' ),
1458 'yes' => __( 'Yes', 'edit-flow' ),
1459 );
1460 ?>
1461 <select id="viewable" name="viewable">
1462 <?php foreach ( $metadata_viewable_options as $metadata_viewable_key => $metadata_viewable_value ) : ?>
1463 <option value="<?php echo esc_attr( $metadata_viewable_key ); ?>" <?php selected( $viewable, $metadata_viewable_key ); ?>><?php echo esc_attr( $metadata_viewable_value ); ?></option>
1464 <?php endforeach; ?>
1465 </select>
1466 <?php $edit_flow->settings->helper_print_error_or_description( 'viewable', __( 'When viewable, metadata can be seen on views other than the edit post view (e.g. calendar, manage posts, story budget, etc.)', 'edit-flow' ) ); ?>
1467 </td>
1468 </tr>
1469 <input type="hidden" name="<?php echo self::metadata_taxonomy ?>'_type" value="<?php echo $type; ?>" />
1470 </table>
1471 <p class="submit">
1472 <?php submit_button( __( 'Update Metadata Term', 'edit-flow' ), 'primary', 'submit', false ); ?>
1473 <a class="cancel-settings-link" href="<?php echo esc_url( add_query_arg( 'page', $this->module->settings_slug, get_admin_url( null, 'admin.php' ) ) ); ?>"><?php _e( 'Cancel', 'edit-flow' ); ?></a>
1474 </p>
1475 </form>
1476
1477 <?php else: ?>
1478 <?php /** If not in full-screen edit term mode, we can create new terms or change options **/ ?>
1479 <div id="col-left">
1480 <div class="col-wrap">
1481 <div class="form-wrap">
1482 <h3 class="nav-tab-wrapper">
1483 <a href="<?php echo esc_url( add_query_arg( array( 'page' => $this->module->settings_slug ), get_admin_url( null, 'admin.php' ) ) ); ?>" class="nav-tab<?php if ( !isset( $_GET['action'] ) || $_GET['action'] != 'change-options' ) echo ' nav-tab-active'; ?>"><?php _e( 'Add New', 'edit-flow' ); ?></a>
1484 <a href="<?php echo esc_url( add_query_arg( array( 'page' => $this->module->settings_slug, 'action' => 'change-options' ), get_admin_url( null, 'admin.php' ) ) ); ?>" class="nav-tab<?php if ( isset( $_GET['action'] ) && $_GET['action'] == 'change-options' ) echo ' nav-tab-active'; ?>"><?php _e( 'Options', 'edit-flow' ); ?></a>
1485 </h3>
1486
1487 <?php if ( isset( $_GET['action'] ) && $_GET['action'] == 'change-options' ): ?>
1488 <?php /** Basic form built on WP Settings API for outputting Editorial Metadata options **/ ?>
1489 <form class="basic-settings" action="<?php echo esc_url( add_query_arg( array( 'page' => $this->module->settings_slug, 'action' => 'change-options' ), get_admin_url( null, 'admin.php' ) ) ); ?>" method="post">
1490 <?php settings_fields( $this->module->options_group_name ); ?>
1491 <?php do_settings_sections( $this->module->options_group_name ); ?>
1492 <?php echo '<input id="edit_flow_module_name" name="edit_flow_module_name" type="hidden" value="' . esc_attr( $this->module->name ) . '" />'; ?>
1493 <?php submit_button(); ?>
1494 </form>
1495 <?php else: ?>
1496 <?php /** Custom form for adding a new Editorial Metadata term **/ ?>
1497 <form class="add:the-list:" action="<?php echo esc_url( add_query_arg( array( 'page' => $this->module->settings_slug ), get_admin_url( null, 'admin.php' ) ) ); ?>" method="post" id="addmetadata" name="addmetadata">
1498 <div class="form-field form-required">
1499 <label for="metadata_name"><?php _e( 'Name', 'edit-flow' ); ?></label>
1500 <input type="text" aria-required="true" size="20" maxlength="20" id="metadata_name" name="metadata_name" value="<?php if ( !empty( $_POST['metadata_name'] ) ) echo esc_attr( stripslashes( $_POST['metadata_name'] ) ) ?>" />
1501 <?php $edit_flow->settings->helper_print_error_or_description( 'name', __( 'The name is for labeling the metadata field.', 'edit-flow' ) ); ?>
1502 </div>
1503 <div class="form-field form-required">
1504 <label for="metadata_slug"><?php _e( 'Slug', 'edit-flow' ); ?></label>
1505 <input type="text" aria-required="true" size="20" maxlength="20" id="metadata_slug" name="metadata_slug" value="<?php if ( !empty( $_POST['metadata_slug'] ) ) echo esc_attr( $_POST['metadata_slug'] ) ?>" />
1506 <?php $edit_flow->settings->helper_print_error_or_description( 'slug', __( 'The "slug" is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.', 'edit-flow' ) ); ?>
1507 </div>
1508 <div class="form-field">
1509 <label for="metadata_description"><?php _e( 'Description', 'edit-flow' ); ?></label>
1510 <textarea cols="40" rows="5" id="metadata_description" name="metadata_description"><?php if ( !empty( $_POST['metadata_description'] ) ) echo esc_html( stripslashes( $_POST['metadata_description'] ) ) ?></textarea>
1511 <?php $edit_flow->settings->helper_print_error_or_description( 'description', __( 'The description can be used to communicate with your team about what the metadata is for.', 'edit-flow' ) ); ?>
1512 </div>
1513 <div class="form-field form-required">
1514 <label for="metadata_type"><?php _e( 'Type', 'edit-flow' ); ?></label>
1515 <?php
1516 $metadata_types = $this->get_supported_metadata_types();
1517 // Select the previously selected metadata type if a valid one exists
1518 $current_metadata_type = ( isset( $_POST['metadata_type'] ) && in_array( $_POST['metadata_type'], array_keys( $metadata_types ) ) ) ? $_POST['metadata_type'] : false;
1519 ?>
1520 <select id="metadata_type" name="metadata_type">
1521 <?php foreach ( $metadata_types as $metadata_type => $metadata_type_name ) : ?>
1522 <option value="<?php echo esc_attr( $metadata_type ); ?>" <?php selected( $metadata_type, $current_metadata_type ); ?>><?php echo esc_attr( $metadata_type_name ); ?></option>
1523 <?php endforeach; ?>
1524 </select>
1525 <?php $edit_flow->settings->helper_print_error_or_description( 'type', __( 'Indicate the type of editorial metadata.', 'edit-flow' ) ); ?>
1526 </div>
1527 <div class="form-field form-required">
1528 <label for="metadata_viewable"><?php _e( 'Viewable', 'edit-flow' ); ?></label>
1529 <?php
1530 $metadata_viewable_options = array(
1531 'no' => __( 'No', 'edit-flow' ),
1532 'yes' => __( 'Yes', 'edit-flow' ),
1533 );
1534 $current_metadata_viewable = ( isset( $_POST['metadata_viewable'] ) && in_array( $_POST['metadata_viewable'], array_keys( $metadata_viewable_options ) ) ) ? $_POST['metadata_viewable'] : 'no';
1535 ?>
1536 <select id="metadata_viewable" name="metadata_viewable">
1537 <?php foreach ( $metadata_viewable_options as $metadata_viewable_key => $metadata_viewable_value ) : ?>
1538 <option value="<?php echo esc_attr( $metadata_viewable_key ); ?>" <?php selected( $current_metadata_viewable, $metadata_viewable_key ); ?>><?php echo esc_attr( $metadata_viewable_value ); ?></option>
1539 <?php endforeach; ?>
1540 </select>
1541 <?php $edit_flow->settings->helper_print_error_or_description( 'viewable', __( 'When viewable, metadata can be seen on views other than the edit post view (e.g. calendar, manage posts, story budget, etc.)', 'edit-flow' ) ); ?>
1542 </div>
1543 <?php wp_nonce_field( 'editorial-metadata-add-nonce' );?>
1544 <input type="hidden" id="form-action" name="form-action" value="add-term" />
1545 <p class="submit"><?php submit_button( __( 'Add New Metadata Term', 'edit-flow' ), 'primary', 'submit', false ); ?><a class="cancel-settings-link" href="<?php echo EDIT_FLOW_SETTINGS_PAGE; ?>"><?php _e( 'Back to Edit Flow', 'edit-flow' ); ?></a></p>
1546 </form>
1547 <?php endif; ?>
1548 </div>
1549 </div>
1550 </div>
1551
1552 <?php
1553 endif;
1554 }
1555
1556 }
1557
1558 }
1559
1560 /**
1561 * Management interface for Editorial Metadata. Extends WP_List_Table class
1562 */
1563 class EF_Editorial_Metadata_List_Table extends WP_List_Table {
1564
1565 var $callback_args;
1566 var $taxonomy;
1567 var $tax;
1568
1569 /**
1570 * Construct the class
1571 */
1572 function __construct() {
1573 global $edit_flow;
1574
1575 $this->taxonomy = EF_Editorial_Metadata::metadata_taxonomy;
1576
1577 $this->tax = get_taxonomy( $this->taxonomy );
1578
1579 $columns = $this->get_columns();
1580 $hidden = array(
1581 'position',
1582 );
1583 $sortable = array();
1584
1585 $this->_column_headers = array( $columns, $hidden, $sortable );
1586
1587 parent::__construct( array(
1588 'plural' => 'editorial metadata',
1589 'singular' => 'editorial metadata',
1590 ) );
1591 }
1592
1593 /**
1594 * Prepare the items to be displayed on the list table
1595 *
1596 * @since 0.7
1597 */
1598 function prepare_items() {
1599 global $edit_flow;
1600 $this->items = $edit_flow->editorial_metadata->get_editorial_metadata_terms();
1601
1602 $this->set_pagination_args( array(
1603 'total_items' => count( $this->items ),
1604 'per_page' => count( $this->items ),
1605 ) );
1606 }
1607
1608 /**
1609 * Message to be displayed when there is no editorial metadata
1610 *
1611 * @since 0.7
1612 */
1613 function no_items() {
1614 _e( 'No editorial metadata found.', 'edit-flow' );
1615 }
1616
1617 /**
1618 * Register the columns to appear in the table
1619 *
1620 * @since 0.7
1621 */
1622 function get_columns() {
1623
1624 $columns = array(
1625 'position' => __( 'Position', 'edit-flow' ),
1626 'name' => __( 'Name', 'edit-flow' ),
1627 'type' => __( 'Metadata Type', 'edit-flow' ),
1628 'description' => __( 'Description', 'edit-flow' ),
1629 'viewable' => __( 'Viewable', 'edit-flow' ),
1630 );
1631 return $columns;
1632 }
1633
1634 /**
1635 * Prepare a single row of Editorial Metadata
1636 *
1637 * @since 0.7
1638 *
1639 * @param object $term The current term we're displaying
1640 * @param int $level Level is always zero because it isn't a parent-child tax
1641 */
1642 function single_row( $term, $level = 0 ) {
1643 static $alternate_class = '';
1644 $alternate_class = ( $alternate_class == '' ? ' alternate' : '' );
1645 $row_class = ' class="term-static' . $alternate_class . '"';
1646
1647 echo '<tr id="term-' . $term->term_id . '"' . $row_class . '>';
1648 echo $this->single_row_columns( $term );
1649 echo '</tr>';
1650 }
1651
1652 /**
1653 * Handle the column output when there's no method for it
1654 *
1655 * @since 0.7
1656 *
1657 * @param object $item Editorial Metadata term as an object
1658 * @param string $column_name How the column was registered at birth
1659 */
1660 function column_default( $item, $column_name ) {
1661
1662 switch( $column_name ) {
1663 case 'position':
1664 case 'type':
1665 case 'description':
1666 return esc_html( $item->$column_name );
1667 break;
1668 case 'viewable':
1669 if ( $item->viewable )
1670 return __( 'Yes', 'edit-flow' );
1671 else
1672 return __( 'No', 'edit-flow' );
1673 break;
1674 default:
1675 break;
1676 }
1677
1678 }
1679
1680 /**
1681 * Column for displaying the term's name and associated actions
1682 *
1683 * @since 0.7
1684 *
1685 * @param object $item Editorial Metadata term as an object
1686 */
1687 function column_name( $item ) {
1688 global $edit_flow;
1689 $item_edit_link = esc_url( $edit_flow->editorial_metadata->get_link( array( 'action' => 'edit-term', 'term-id' => $item->term_id ) ) );
1690 $item_delete_link = esc_url( $edit_flow->editorial_metadata->get_link( array( 'action' => 'delete-term', 'term-id' => $item->term_id ) ) );
1691
1692 $out = '<strong><a class="row-title" href="' . $item_edit_link . '">' . esc_html( $item->name ) . '</a></strong>';
1693
1694 $actions = array();
1695 $actions['edit'] = "<a href='$item_edit_link'>" . __( 'Edit', 'edit-flow' ) . "</a>";
1696 $actions['inline hide-if-no-js'] = '<a href="#" class="editinline">' . __( 'Quick&nbsp;Edit' ) . '</a>';
1697 if ( $item->viewable )
1698 $actions['change-visibility make-hidden'] = '<a title="' . esc_attr( __( 'Hidden metadata can only be viewed on the edit post view.', 'edit-flow' ) ) . '" href="' . esc_url( $edit_flow->editorial_metadata->get_link( array( 'action' => 'make-hidden', 'term-id' => $item->term_id ) ) ) . '">' . __( 'Make Hidden', 'edit-flow' ) . '</a>';
1699 else
1700 $actions['change-visibility make-viewable'] = '<a title="' . esc_attr( __( 'When viewable, metadata can be seen on views other than the edit post view (e.g. calendar, manage posts, story budget, etc.)', 'edit-flow' ) ) . '" href="' . esc_url( $edit_flow->editorial_metadata->get_link( array( 'action' => 'make-viewable', 'term-id' => $item->term_id ) ) ) . '">' . __( 'Make Viewable', 'edit-flow' ) . '</a>';
1701 $actions['delete delete-status'] = "<a href='$item_delete_link'>" . __( 'Delete', 'edit-flow' ) . "</a>";
1702
1703 $out .= $this->row_actions( $actions, false );
1704 $out .= '<div class="hidden" id="inline_' . $item->term_id . '">';
1705 $out .= '<div class="name">' . $item->name . '</div>';
1706 $out .= '<div class="description">' . $item->description . '</div>';
1707 $out .= '</div>';
1708
1709 return $out;
1710 }
1711
1712 /**
1713 * Admins can use the inline edit capability to quickly make changes to the title or description
1714 *
1715 * @since 0.7
1716 */
1717 function inline_edit() {
1718
1719 ?>
1720 <form method="get" action=""><table style="display: none"><tbody id="inlineedit">
1721 <tr id="inline-edit" class="inline-edit-row" style="display: none"><td colspan="<?php echo $this->get_column_count(); ?>" class="colspanchange">
1722 <fieldset><div class="inline-edit-col">
1723 <h4><?php _e( 'Quick Edit' ); ?></h4>
1724 <label>
1725 <span class="title"><?php _e( 'Name', 'edit-flow' ); ?></span>
1726 <span class="input-text-wrap"><input type="text" name="name" class="ptitle" value="" maxlength="20" /></span>
1727 </label>
1728 <label>
1729 <span class="title"><?php _e( 'Description', 'edit-flow' ); ?></span>
1730 <span class="input-text-wrap"><input type="text" name="description" class="pdescription" value="" /></span>
1731 </label>
1732 </div></fieldset>
1733 <p class="inline-edit-save submit">
1734 <a accesskey="c" href="#inline-edit" title="<?php _e( 'Cancel' ); ?>" class="cancel button-secondary alignleft"><?php _e( 'Cancel' ); ?></a>
1735 <?php $update_text = __( 'Update Metadata Term', 'edit-flow' ); ?>
1736 <a accesskey="s" href="#inline-edit" title="<?php echo esc_attr( $update_text ); ?>" class="save button-primary alignright"><?php echo $update_text; ?></a>
1737 <img class="waiting" style="display:none;" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
1738 <span class="error" style="display:none;"></span>
1739 <?php wp_nonce_field( 'editorial-metadata-inline-edit-nonce', 'inline_edit', false ); ?>
1740 <br class="clear" />
1741 </p>
1742 </td></tr>
1743 </tbody></table></form>
1744 <?php
1745 }
1746 }
1747