PluginProbe
Edit Flow / 0.1.5
Edit Flow v0.1.5
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 / php / custom_status.php

custom_status.php in Edit Flow 0.1.5, at php/custom_status.php

597 lines 19.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // Functions related to hooking into custom statuses will go here
4
5 class custom_status {
6
7 // This is taxonomy name used to store all our custom statuses
8 var $status_taxonomy = 'post_status';
9
10 /**
11 * Constructor
12 */
13 function __construct ( ) {
14
15 // Register new taxonomy so that we can store all our fancy new custom statuses (or is it stati?)
16 if(!is_taxonomy($this->status_taxonomy)) register_taxonomy( $this->status_taxonomy, 'post', array('hierarchical' => false, 'update_count_callback' => '_update_post_term_count', 'label' => false, 'query_var' => false, 'rewrite' => false) );
17
18 // Hooks to add "status" column to Edit Posts page
19 // BUT, only add it if not being filtered by post_status
20 if(!(isset($_GET['post_status'])) && !(isset($_POST['post_status']))) {
21 add_filter('manage_posts_columns', array('custom_status', '_filter_manage_posts_columns'));
22 add_action('manage_posts_custom_column', array('custom_status', '_filter_manage_posts_custom_column'));
23 }
24
25 // Add actions and filters for the Edit/Manage Posts page
26 add_action('load-edit.php', array(&$this, 'load_edit_hooks'));
27
28 } // END: __construct()
29
30 /**
31 * Hooks to make modifications to the Manage/Edit Posts
32 */
33 function load_edit_hooks() {
34 // Add custom stati to Edit/Manage Posts
35 add_action('admin_notices',array(&$this, 'enable_custom_status_filters'));
36 // Modify the posts_where query to include custom stati
37 add_filter('posts_where', array(&$this, 'custom_status_where_filter'));
38 } // END: load_edit_hooks()
39
40 /**
41 * Adds custom stati to the $post_stati array.
42 * This is used to generate the list of statuses on the Edit/Manage Posts page.
43 *
44 */
45 function enable_custom_status_filters() {
46 // This is the array WP uses to store custom stati (really? stati?)
47 // The status list at the top of the Manage/Edit Posts page is generated using this array
48 global $post_stati;
49
50 if(is_array($post_stati)) {
51
52 // @ TODO Don't return statuses that are empty (i.e. no posts)
53 // Get a list of ALL the custom statuses
54 $custom_statuses = $this->get_custom_statuses();
55
56 // Alright, now append them to the $post_stati array
57 foreach($custom_statuses as $status) {
58 if(!$this->is_restricted_status($status->slug)) {
59 $slug = $status->slug;
60 $post_stati[$slug] = array(
61 $status->name,
62 $status->description,
63 array(
64 $status->name.' <span class="count">(%s)</span>',
65 $status->name.' <span class="count">(%s)</span>'
66 )
67 );
68
69 }
70 }
71 }
72 } // END: enable_custom_status_filters()
73
74 /**
75 * Edits the WHERE clause for the the get_post query.
76 * This is used to show all the posts with custom statuses.
77 * Why? Because WordPress automatically hides anything without an allowed status (e.g. "publish", "draft",, etc.)
78 */
79 function custom_status_where_filter($where){
80 global $wpdb;
81 if(is_admin()) {
82
83 if(!(isset($_GET['post_status'])) && !(isset($_POST['post_status']))) {
84 $custom_statuses = $this->get_custom_statuses();
85 foreach($custom_statuses as $status) {
86 $where .= " OR ".$wpdb->posts.".post_status = '".$status->slug."'";
87 }
88 } else {
89 // Okay, we're filtering by statuses
90 $status = $_GET['post_status'];
91
92 // if not one of inbuilt custom statuses, delete query where AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'future' OR wp_posts.post_status = 'draft' OR wp_posts.post_status = 'pending' OR wp_posts.post_status = 'private')
93 // append status to where
94 if(is_term($status, $this->status_taxonomy)) {
95 $where = "AND ".$wpdb->posts.".post_type = 'post' AND (".$wpdb->posts.".post_status = '".$status."')";
96 }
97 }
98
99 }
100 return $where;
101 } // END: custom_status_where_filter()
102
103 /**
104 * Adds a new custom status as a term in the wp_terms table.
105 * Basically a wrapper for the wp_insert_term class.
106 *
107 * The arguments decide how the term is handled based on the $args parameter.
108 * The following is a list of the available overrides and the defaults.
109 *
110 * 'description'. There is no default. If exists, will be added to the database
111 * along with the term. Expected to be a string.
112 *
113 * 'slug'. Expected to be a string. There is no default.
114 *
115 * @param int|string $term The status to add or update
116 * @param array|string $args Change the values of the inserted term
117 * @return array|WP_Error The Term ID and Term Taxonomy ID
118 *
119 */
120 function add_custom_status ( $term, $args = array() ) {
121 // $args = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
122 return wp_insert_term( $term, $this->status_taxonomy, $args );
123
124 } // END: add_custom_status
125
126 /**
127 *
128 * Basically a wrapper for the wp_update_term function
129 */
130 function update_custom_status ( $status_id, $args = array() ) {
131
132 // Reassign posts to new status slug
133 $old_status = get_term($status_id, $this->status_taxonomy)->slug;
134 // if($old_status != 'draft' || $old_status != 'pending' || $old_status != 'publish') {
135 if(!$this->is_restricted_status($old_status)) {
136 // If new status not indicated, set to "draft", else get slug for new status
137 $new_status = $args['slug'];
138 $this->reassign_post_status( $old_status, $new_status );
139 }
140
141
142 return wp_update_term( $status_id, $this->status_taxonomy, $args );
143 } // END: update_custom_status
144
145 /**
146 * Deletes a custom status from the wp_terms table.
147 *
148 * Partly a wrapper for the wp_delete_term function.
149 * BUT, also reassigns posts that currently have the deleted status assigned.
150 */
151 function delete_custom_status ( $status_id, $args = array(), $reassign = '' ) {
152
153 // Reassign posts to alternate status
154
155 // Get slug for the old status
156 $old_status = get_term($status_id, $this->status_taxonomy)->slug;
157
158 if(!$this->is_restricted_status($old_status)) {
159
160 // If new status not indicated, set to "draft", else get slug for new status
161 if(!$reassign) $new_status = 'draft';
162 else $new_status = get_term($reassign, $this->status_taxonomy)->slug;
163
164 $this->reassign_post_status( $old_status, $new_status );
165 }
166
167 return wp_delete_term( $status_id, $this->status_taxonomy, $args );
168 } // END: delete_custom_status
169
170
171 function get_custom_statuses ($statuses = '', $args ='' ) {
172
173 // @TODO: implement $args, to allow for pagination, etc.
174
175 if(!$statuses) {
176 // return all stati
177 $statuses = get_terms( $this->status_taxonomy, array( 'get' => 'all' ) );
178 } else if (!is_array($statuses)) {
179 // return a single status
180 } else {
181 // return multiple stati
182 }
183
184 return $statuses;
185 }
186
187 function reassign_post_status( $old_status, $new_status = 'draft' ) {
188 global $wpdb;
189
190 // Make the database call
191 $result = $wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'post_status' => $old_status ), array( '%s' ));
192 }
193
194 /**
195 * Insert new column header for post status
196 *
197 * @param array $post_columns
198 **/
199 function _filter_manage_posts_columns($posts_columns) {
200 $result = array();
201 foreach ($posts_columns as $key => $value) {
202 if ($key == 'author') {
203 $result[$key] = $value;
204 $result['status'] = __('Status', 'edit-flow');
205 } else $result[$key] = $value;
206 }
207 return $result;
208 } // END: _filter_manage_posts_columns
209
210 /**
211 * Adds a Post's status to its row on the Edit page
212 *
213 * @param string $column_name
214 **/
215 function _filter_manage_posts_custom_column($column_name) {
216 if ($column_name == 'status') {
217 global $post, $custom_status;
218 echo get_status_name('slug' , $post->post_status);
219 }
220 }
221
222
223 /**
224 * Determines whether the slug indicated belongs to a restricted status or not
225 * @param string Slug of the status
226 * @return bool True if restricted, false if not
227 */
228 function is_restricted_status ( $slug ) {
229
230 switch($slug) {
231 case 'publish':
232 case 'draft':
233 case 'private':
234 case 'future':
235 case 'pending':
236 case 'new':
237 case 'inherit':
238 $return = true;
239 break;
240
241 default:
242 $return = false;
243 break;
244 }
245 return $return;
246 }
247
248
249
250 function admin_page ( ) {
251 global $wpdb, $edit_flow;
252
253 // @TODO JS form validation
254
255 $nonce_fail_msg = __('There\'s something fishy going on! We don\'t like this type of nonce-sense. Hmph.');
256 $msg_class = 'updated';
257
258 $action = ($_POST['action']) ? $wpdb->escape($_POST['action']) : $wpdb->escape($_GET['action']);
259
260
261
262 switch($action) {
263
264 case 'add':
265
266 // Verfiy nonce
267 if(wp_verify_nonce($_POST['custom-status-add-nonce'], 'custom-status-add-nonce')) {
268
269 // @TODO Make sure content is secure, ie: check inputs so nothing nasty gets through
270
271 // Check if name field was filled in
272 if(!($name = $_POST['status_name'])) {
273 $error_details = __('Please enter a name for the status');
274 break;
275 }
276
277 // Check to make sure the name is not restricted
278 if($this->is_restricted_status(strtolower(trim($name)))) {
279 $error_details = __('That status name is restricted. Please use another name.');
280 break;
281 }
282
283 // Check to make sure the status doesn't already exist
284 if(is_term(sanitize_title($_POST['status_name']))) {
285 $error_details = __('That status already exists. Please use another name.');
286 break;
287 }
288
289 $args = array('description' => $_POST['status_description'], 'slug' => sanitize_title($_POST['status_name']) );
290
291 // Try to add the status
292 $return = $this->add_custom_status($name, $args);
293 if(!is_wp_error($return)) {
294 $msg = __('Status successfully added.');
295 } else {
296 $error_details = __('Could not add the status: ') . $return->get_error_message();
297 }
298
299 } else {
300 $error_details = $nonce_fail_msg;
301 }
302
303 break;
304
305 case 'edit':
306 $term_id = (int) $_GET['term_id'];
307
308 if($term_id && $the_status = get_term($term_id, $this->status_taxonomy)) {
309
310 // Stop users from editing restricted statuses
311 if($this->is_restricted_status($the_status->slug)) {
312 $error_details = __('That status is restricted and cannot be edited. You are welcome to delete it, however.');
313 $update = false;
314 } else {
315 $update = true;
316 $edit_status = $the_status;
317 }
318 }
319 break;
320
321 case 'update':
322
323 // @TODO if updated status is the same as the default_status, update the default
324
325 // Verfiy nonce
326 if(wp_verify_nonce($_POST['custom-status-add-nonce'], 'custom-status-add-nonce')) {
327 $term_id = (int) $_POST['term_id'];
328
329 $status_name = $_POST['status_name'];
330 $status_description = $_POST['status_description'];
331 $status_slug = sanitize_title($_POST['status_name']);
332
333
334 // Check to make sure the status doesn't already exist
335 if(is_term(sanitize_title($_POST['status_name'])) && (get_term($term_id, $this->status_taxonomy)->slug != $status_slug)) {
336 $error_details = __('That status already exists. Please use another name.');
337 break;
338 }
339
340 // get status_name & status_description
341 $args = array( 'name' => $status_name, 'description' => $status_description, 'slug' => $status_slug );
342
343 $return = $this->update_custom_status($term_id, $args);
344 if(!is_wp_error($return)) {
345 $msg = __('Status successfully updated.');
346 } else {
347 $error_details = __('Could not update the status: ') . $return->get_error_message();
348 }
349
350 } else {
351 $error_details = $nonce_fail_msg;
352 }
353
354
355 break;
356
357 case 'delete':
358
359 // @TODO if updated status is the same as the default_status, update the default
360
361 // Verfiy nonce
362 if(wp_verify_nonce($_GET['_wpnonce'], 'custom-status-delete-nonce')) {
363 $term_id = (int) $_GET['term_id'];
364
365 // Check to make sure the status doesn't already exist
366 if(!is_term($term_id, $this->status_taxonomy)) {
367 $error_details = __('That status does not exist. Try again?');
368 break;
369 }
370
371 $return = $this->delete_custom_status($term_id);
372 if(!is_wp_error($return)) {
373 $msg = __('Status successfully deleted.');
374 } else {
375 $error_details = __('Could not delete the status: ') . $return->get_error_message();
376 }
377
378 } else {
379 $error_details = $nonce_fail_msg;
380 }
381
382 break;
383
384 default:
385 $update = false;
386 break;
387
388 }
389
390 if($error_details) {
391 $msg = __('There was an error with your request. ');
392 $msg .= '<br /><br /><strong>'.$error_details.'</strong>';
393 $msg_class = 'error';
394 }
395
396 $statuses = $this->get_custom_statuses();
397
398 ?>
399 <div class="wrap">
400 <h2><?php _e('Custom Post Statuses') ?></h2>
401
402 <?php if(!$edit_flow->get_plugin_option('custom_statuses_enabled')) : ?>
403 <div class="error" id="plugin-message">
404 <p><strong><?php _e('Note: Custom Statuses are currently disabled') ?></strong></p>
405 <p><em><?php _e('While you are free to add, edit and delete to your heart\'s content, please note that you will not be able to assign posts to custom statuses unless you <a href="'. EDIT_FLOW_SETTINGS_PAGE.'">enable them</a>.') ?></em></p>
406 </div>
407 <?php endif ?>
408
409 <?php if($msg) : ?>
410 <div id="message" class="<?php echo $msg_class ?> fade below-h2">
411 <p><?php echo $msg ?></p>
412 </div>
413 <?php endif; ?>
414
415
416 <div id="col-container">
417 <div id="col-right">
418 <div class="col-wrap">
419
420 <table cellspacing="0" class="widefat fixed">
421 <thead>
422 <tr>
423 <th class="manage-column column-cb check-column" id="cb" scope="col"><!--<input type="checkbox"/>--></th>
424 <th style="" class="manage-column column-name" id="name" scope="col"><?php _e('Name') ?></th>
425 <th style="" class="manage-column column-description" id="description" scope="col"><?php _e('Description') ?></th>
426 <th style="" class="manage-column column-posts num" id="posts" scope="col"><?php _e('# of Posts') ?></th>
427 </tr>
428 </thead>
429 <tfoot>
430 <tr>
431 <th style="" class="manage-column column-cb check-column" scope="col"><!--<input type="checkbox"/>--></th>
432 <th style="" class="manage-column column-name" scope="col"><?php _e('Name') ?></th>
433 <th style="" class="manage-column column-description" scope="col"><?php _e('Description') ?></th>
434 <th style="" class="manage-column column-posts num" scope="col"><?php _e('Posts') ?></th>
435 </tr>
436 </tfoot>
437
438 <tbody class="list:post_status" id="the-list">
439
440 <?php
441 if (is_array($statuses)) {
442
443 $delete_nonce = wp_create_nonce('custom-status-delete-nonce');
444
445 foreach ($statuses as $status) {
446
447 $count = get_custom_status_post_count($status->slug);
448
449 $status_link = get_custom_status_filter_link($status->slug);
450 $edit_link = get_custom_status_edit_link($status->term_id);
451 $delete_link = EDIT_FLOW_CUSTOM_STATUS_PAGE.'&amp;action=delete&amp;term_id='.$status->term_id.'&amp;_wpnonce='.$delete_nonce;
452
453 ?>
454
455 <tr class="iedit alternate" id="status-<?php echo $status->term_id ?>">
456 <th class="check-column" scope="row">
457 <!--<input type="checkbox" value="32" name="delete[]"/>-->
458 </th>
459 <td class="name column-name">
460 <a title="Edit “<?php echo $status->name ?>”" href="<?php echo $edit_link ?>" class="row-title">
461 <?php echo $status->name ?>
462 </a>
463 <br/>
464 <div class="row-actions">
465 <span class="edit">
466 <a href="<?php echo $edit_link ?>">
467 <?php _e('Edit') ?>
468 </a>
469 |
470 </span>
471 <span class="delete">
472 <a href="<?php echo $delete_link ?>" class="delete:the-list:status-<?php echo $status->term_is ?> submitdelete" onclick="if(!confirm('Are you sure you want to delete this status?')) return false;">
473 <?php _e('Delete') ?>
474 </a>
475 </span>
476 </div>
477 </td>
478 <td class="description column-description">
479 <?php echo $status->description ?>
480 </td>
481 <td class="posts column-posts num">
482 <a href="<?php echo $status_link ?>" title="View all posts with the status <?php echo $status->name ?>"><?php echo $count ?></a>
483 </td>
484 <?php
485 }
486 }
487 ?>
488 </tr>
489 </tbody>
490 </table>
491
492 <div class="form-wrap">
493 <p><?php _e('<strong>Note:</strong><br/>Deleting a status does not delete the posts assigned that status. Instead, the posts will be set to the default status: <strong>Draft</strong>') ?>.
494 </p>
495 </div>
496
497 </div>
498 </div>
499
500
501 <div id="col-left">
502 <div class="col-wrap">
503 <div class="form-wrap">
504 <h3><?php echo ($update) ? __('Update Custom Status') : __('Add Custom Status') ?></h3>
505 <form class="add:the-list: validate" action="<?php echo EDIT_FLOW_CUSTOM_STATUS_PAGE ?>" method="post" id="addstatus" name="addstatus">
506
507 <div class="form-field form-required">
508 <label for="status_name"><?php _e('Name') ?></label>
509 <input type="text" aria-required="true" size="40" id="status_name" name="status_name" value="<?php echo $edit_status->name ?>" />
510 <p><? _e('The name is used to identify the status.') ?></p>
511 </div>
512
513 <div class="form-field">
514 <label for="status_description"><?php _e('Description') ?></label>
515 <textarea cols="40" rows="5" id="status_description" name="status_description"><?php echo $edit_status->description ?></textarea>
516 <p><?php _e('The description is mainly for administrative use, just to give you some context on what the custom status is to be used for or means.') ?></p>
517 </div>
518
519 <input type="hidden" name="action" value="<?php echo ($update) ? 'update' : 'add' ?>" />
520 <?php if($update) : ?>
521 <input type="hidden" name="term_id" value="<?php echo $edit_status->term_id ?>" />
522 <?php endif; ?>
523 <input type="hidden" name="page" value="Edit-Flow-Project/php/custom_status.php" />
524 <input type="hidden" name="custom-status-add-nonce" id="custom-status-add-nonce" value="<?php echo wp_create_nonce('custom-status-add-nonce') ?>" />
525
526 <p class="submit"><input type="submit" value="<?php echo ($update) ? __('Update Custom Status') : __('Add Custom Status') ?>" name="submit" class="button"/></p>
527 </form>
528 </div>
529 </div>
530 </div>
531 </div>
532
533 </div>
534 <?php
535 } // END: admin_page()
536
537
538 } // END: class custom_status
539
540
541
542 /**
543 * Gets the proper name for the custom status
544 * Can be fetched using either the "slug" or "id"
545 * @param $field The field to search by: "slug" or "id"
546 * @param $value The value to search for
547 */
548 function get_status_name ( $field, $value ) {
549 switch($value) {
550 case 'publish':
551 return 'Published';
552 case 'draft':
553 return 'Draft';
554 case 'future':
555 return 'Scheduled';
556 case 'private':
557 return 'Private';
558 case 'pending':
559 return 'Pending Review';
560
561 default:
562 switch($field) {
563 case 'slug':
564 $status = get_term_by('slug', $value, 'post_status');
565 break;
566 case 'id':
567 $status = get_term_by('term_id', $value, 'post_status');
568 break;
569 default:
570 return null;
571 }
572 break;
573 }
574 return $status->name;
575 } // END: get_status_name()
576
577 function get_custom_status_filter_link ( $slug ) {
578 return 'edit.php?post_status='.$slug;
579 }
580
581 function get_custom_status_edit_link( $id ) {
582 return EDIT_FLOW_CUSTOM_STATUS_PAGE.'&amp;action=edit&amp;term_id='.$id;
583 }
584
585 function get_custom_status_post_count ( $status ) {
586 global $wpdb;
587
588 if(is_int($status)) {
589 $status = get_term_by('term_id', $status, 'post_status')->slug;
590 }
591
592 $query = $wpdb->prepare("SELECT count(ID) FROM $wpdb->posts WHERE post_status = %s", $status);
593
594 return $wpdb->get_var($query);
595 }
596
597 ?>