PluginProbe
Edit Flow / 0.9.9
Edit Flow v0.9.9
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 / common / php / class-module.php

class-module.php in Edit Flow 0.9.9, at common/php/class-module.php

596 lines 18.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * class EF_Module
4 *
5 * @desc Base class any Edit Flow module should extend
6 */
7
8 if ( !class_exists( 'EF_Module' ) ) {
9
10 class EF_Module {
11
12 public $published_statuses = array(
13 'publish',
14 'future',
15 'private',
16 );
17
18 public $module_url;
19
20 public $module;
21
22 function __construct() {}
23
24 /**
25 * Returns whether the current module is enabled.
26 *
27 * @since 0.9.1
28 *
29 * @return <code>true</code> if the module is enabled, <code>false</code> otherwise
30 */
31 public function is_enabled() {
32 return $this->module->options->enabled === 'on';
33 }
34
35 /**
36 * Returns whether the module with the given name is enabled.
37 *
38 * @since 0.7
39 *
40 * @param string module Slug of the module to check
41 * @return <code>true</code> if the module is enabled, <code>false</code> otherwise
42 */
43 function module_enabled( $slug ) {
44 global $edit_flow;
45
46 return isset( $edit_flow->$slug ) && $edit_flow->$slug->is_enabled();
47 }
48
49 /**
50 * Gets an array of allowed post types for a module
51 *
52 * @return array post-type-slug => post-type-label
53 */
54 function get_all_post_types() {
55
56 $allowed_post_types = array(
57 'post' => __( 'Post' ),
58 'page' => __( 'Page' ),
59 );
60 $custom_post_types = $this->get_supported_post_types_for_module();
61
62 foreach( $custom_post_types as $custom_post_type => $args ) {
63 $allowed_post_types[$custom_post_type] = $args->label;
64 }
65 return $allowed_post_types;
66 }
67
68 /**
69 * Cleans up the 'on' and 'off' for post types on a given module (so we don't get warnings all over)
70 * For every post type that doesn't explicitly have the 'on' value, turn it 'off'
71 * If add_post_type_support() has been used anywhere (legacy support), inherit the state
72 *
73 * @param array $module_post_types Current state of post type options for the module
74 * @param string $post_type_support What the feature is called for post_type_support (e.g. 'ef_calendar')
75 * @return array $normalized_post_type_options The setting for each post type, normalized based on rules
76 *
77 * @since 0.7
78 */
79 function clean_post_type_options( $module_post_types = array(), $post_type_support = null ) {
80 $normalized_post_type_options = array();
81 $all_post_types = array_keys( $this->get_all_post_types() );
82 foreach( $all_post_types as $post_type ) {
83 if ( ( isset( $module_post_types[$post_type] ) && $module_post_types[$post_type] == 'on' ) || post_type_supports( $post_type, $post_type_support ) )
84 $normalized_post_type_options[$post_type] = 'on';
85 else
86 $normalized_post_type_options[$post_type] = 'off';
87 }
88 return $normalized_post_type_options;
89 }
90
91 /**
92 * Get all of the possible post types that can be used with a given module
93 *
94 * @param object $module The full module
95 * @return array $post_types An array of post type objects
96 *
97 * @since 0.7.2
98 */
99 function get_supported_post_types_for_module( $module = null ) {
100
101 $pt_args = array(
102 '_builtin' => false,
103 'public' => true,
104 );
105 $pt_args = apply_filters( 'edit_flow_supported_module_post_types_args', $pt_args, $module );
106 return get_post_types( $pt_args, 'objects' );
107 }
108
109 /**
110 * Collect all of the active post types for a given module
111 *
112 * @param object $module Module's data
113 * @return array $post_types All of the post types that are 'on'
114 *
115 * @since 0.7
116 */
117 function get_post_types_for_module( $module ) {
118
119 $post_types = array();
120 if ( isset( $module->options->post_types ) && is_array( $module->options->post_types ) ) {
121 foreach( $module->options->post_types as $post_type => $value )
122 if ( 'on' == $value )
123 $post_types[] = $post_type;
124 }
125 return $post_types;
126 }
127
128 /**
129 * Get all of the currently available post statuses
130 * This should be used in favor of calling $edit_flow->custom_status->get_custom_statuses() directly
131 *
132 * @return array $post_statuses All of the post statuses that aren't a published state
133 *
134 * @since 0.7
135 */
136 function get_post_statuses() {
137 global $edit_flow;
138
139 if ( $this->module_enabled('custom_status') ) {
140 return $edit_flow->custom_status->get_custom_statuses();
141 } else {
142 return $this->get_core_post_statuses();
143 }
144 }
145
146 /**
147 * Get core's 'draft' and 'pending' post statuses, but include our special attributes
148 *
149 * @since 0.8.1
150 *
151 * @return array
152 */
153 protected function get_core_post_statuses() {
154
155 return array(
156 (object)array(
157 'name' => __( 'Draft' ),
158 'description' => '',
159 'slug' => 'draft',
160 'position' => 1,
161 ),
162 (object)array(
163 'name' => __( 'Pending Review' ),
164 'description' => '',
165 'slug' => 'pending',
166 'position' => 2,
167 ),
168 );
169 }
170
171 /**
172 * Gets the name of the default custom status. If custom statuses are disabled,
173 * returns 'draft'.
174 *
175 * @return str Name of the status
176 */
177 function get_default_post_status(){
178
179 // Check if custom status module is enabled
180 $custom_status_module = EditFlow()->custom_status->module->options;
181
182 if( $custom_status_module->enabled == 'on' )
183 return $custom_status_module->default_status;
184 else
185 return 'draft';
186
187 }
188
189 /**
190 * Filter to all posts with a given post status (can be a custom status or a built-in status) and optional custom post type.
191 *
192 * @since 0.7
193 *
194 * @param string $slug The slug for the post status to which to filter
195 * @param string $post_type Optional post type to which to filter
196 * @return an edit.php link to all posts with the given post status and, optionally, the given post type
197 */
198 function filter_posts_link( $slug, $post_type = 'post' ) {
199 $filter_link = add_query_arg( 'post_status', $slug, get_admin_url( null, 'edit.php' ) );
200 if ( $post_type != 'post' && in_array( $post_type, get_post_types( '', 'names' ) ) )
201 $filter_link = add_query_arg( 'post_type', $post_type, $filter_link );
202 return $filter_link;
203 }
204
205 /**
206 * Enqueue any resources (CSS or JS) associated with datepicker functionality
207 *
208 * @since 0.7
209 */
210 function enqueue_datepicker_resources() {
211
212 wp_enqueue_script( 'jquery-ui-datepicker' );
213
214 //Timepicker needs to come after jquery-ui-datepicker and jquery
215 wp_enqueue_script( 'edit_flow-timepicker', EDIT_FLOW_URL . 'common/js/jquery-ui-timepicker-addon.js', array( 'jquery', 'jquery-ui-datepicker' ), EDIT_FLOW_VERSION, true );
216 wp_enqueue_script( 'edit_flow-date_picker', EDIT_FLOW_URL . 'common/js/ef_date.js', array( 'jquery', 'jquery-ui-datepicker', 'edit_flow-timepicker' ), EDIT_FLOW_VERSION, true );
217 wp_add_inline_script( 'edit_flow-date_picker', sprintf( 'var ef_week_first_day = %s;', wp_json_encode( get_option( 'start_of_week' ) ) ), 'before' );
218
219 // Now styles
220 wp_enqueue_style( 'jquery-ui-datepicker', EDIT_FLOW_URL . 'common/css/jquery.ui.datepicker.css', array( 'wp-jquery-ui-dialog' ), EDIT_FLOW_VERSION, 'screen' );
221 wp_enqueue_style( 'jquery-ui-theme', EDIT_FLOW_URL . 'common/css/jquery.ui.theme.css', false, EDIT_FLOW_VERSION, 'screen' );
222 }
223
224 /**
225 * Checks for the current post type
226 *
227 * @since 0.7
228 * @return string|null $post_type The post type we've found, or null if no post type
229 */
230 function get_current_post_type() {
231 global $post, $typenow, $pagenow, $current_screen;
232 //get_post() needs a variable
233 $post_id = isset( $_REQUEST['post'] ) ? (int)$_REQUEST['post'] : false;
234
235 if ( $post && $post->post_type ) {
236 $post_type = $post->post_type;
237 } elseif ( $typenow ) {
238 $post_type = $typenow;
239 } elseif ( $current_screen && !empty( $current_screen->post_type ) ) {
240 $post_type = $current_screen->post_type;
241 } elseif ( isset( $_REQUEST['post_type'] ) ) {
242 $post_type = sanitize_key( $_REQUEST['post_type'] );
243 } elseif ( 'post.php' == $pagenow
244 && $post_id
245 && !empty( get_post( $post_id )->post_type ) ) {
246 $post_type = get_post( $post_id )->post_type;
247 } elseif ( 'edit.php' == $pagenow && empty( $_REQUEST['post_type'] ) ) {
248 $post_type = 'post';
249 } else {
250 $post_type = null;
251 }
252
253 return $post_type;
254 }
255
256 /**
257 * Wrapper for the get_user_meta() function so we can replace it if we need to
258 *
259 * @since 0.7
260 *
261 * @param int $user_id Unique ID for the user
262 * @param string $key Key to search against
263 * @param bool $single Whether or not to return just one value
264 * @return string|bool|array $value Whatever the stored value was
265 */
266 function get_user_meta( $user_id, $key, $string = true ) {
267
268 $response = null;
269 $response = apply_filters( 'ef_get_user_meta', $response, $user_id, $key, $string );
270 if ( !is_null( $response ) )
271 return $response;
272
273 return get_user_meta( $user_id, $key, $string );
274
275 }
276
277 /**
278 * Wrapper for the update_user_meta() function so we can replace it if we need to
279 *
280 * @since 0.7
281 *
282 * @param int $user_id Unique ID for the user
283 * @param string $key Key to search against
284 * @param string|bool|array $value Whether or not to return just one value
285 * @param string|bool|array $previous (optional) Previous value to replace
286 * @return bool $success Whether we were successful in saving
287 */
288 function update_user_meta( $user_id, $key, $value, $previous = null ) {
289
290 $response = null;
291 $response = apply_filters( 'ef_update_user_meta', $response, $user_id, $key, $value, $previous );
292 if ( !is_null( $response ) )
293 return $response;
294
295 return update_user_meta( $user_id, $key, $value, $previous );
296
297 }
298
299 /**
300 * Take a status and a message, JSON encode and print
301 *
302 * @since 0.7
303 *
304 * @param string $status Whether it was a 'success' or an 'error'
305 */
306 function print_ajax_response( $status, $message = '' ) {
307 header( 'Content-type: application/json;' );
308 echo json_encode( array( 'status' => $status, 'message' => $message ) );
309 exit;
310 }
311
312 /**
313 * Whether or not the current page is a user-facing Edit Flow View
314 * @todo Think of a creative way to make this work
315 *
316 * @since 0.7
317 *
318 * @param string $module_name (Optional) Module name to check against
319 */
320 function is_whitelisted_functional_view( $module_name = null ) {
321
322 // @todo complete this method
323
324 return true;
325 }
326
327 /**
328 * Whether or not the current page is an Edit Flow settings view (either main or module)
329 * Determination is based on $pagenow, $_GET['page'], and the module's $settings_slug
330 * If there's no module name specified, it will return true against all Edit Flow settings views
331 *
332 * @since 0.7
333 *
334 * @param string $module_name (Optional) Module name to check against
335 * @return bool $is_settings_view Return true if it is
336 */
337 function is_whitelisted_settings_view( $module_name = null ) {
338 global $pagenow, $edit_flow;
339
340 // All of the settings views are based on admin.php and a $_GET['page'] parameter
341 if ( $pagenow != 'admin.php' || !isset( $_GET['page'] ) )
342 return false;
343
344 // Load all of the modules that have a settings slug/ callback for the settings page
345 foreach ( $edit_flow->modules as $mod_name => $mod_data ) {
346 if ( isset( $mod_data->options->enabled ) && $mod_data->options->enabled == 'on' && $mod_data->configure_page_cb )
347 $settings_view_slugs[] = $mod_data->settings_slug;
348 }
349
350 // The current page better be in the array of registered settings view slugs
351 if ( !in_array( $_GET['page'], $settings_view_slugs ) )
352 return false;
353
354 if ( $module_name && $edit_flow->modules->$module_name->settings_slug != $_GET['page'] )
355 return false;
356
357 return true;
358 }
359
360
361 /**
362 * This is a hack, Hack, HACK!!!
363 * Encode all of the given arguments as a serialized array, and then base64_encode
364 * Used to store extra data in a term's description field
365 *
366 * @since 0.7
367 *
368 * @param array $args The arguments to encode
369 * @return string Arguments encoded in base64
370 */
371 function get_encoded_description( $args = array() ) {
372 return base64_encode( maybe_serialize( $args ) );
373 }
374
375 /**
376 * If given an encoded string from a term's description field,
377 * return an array of values. Otherwise, return the original string
378 *
379 * @since 0.7
380 *
381 * @param string $string_to_unencode Possibly encoded string
382 * @return array Array if string was encoded, otherwise the string as the 'description' field
383 */
384 function get_unencoded_description( $string_to_unencode ) {
385 return maybe_unserialize( base64_decode( $string_to_unencode ) );
386 }
387
388 /**
389 * Get the publicly accessible URL for the module based on the filename
390 *
391 * @since 0.7
392 *
393 * @param string $filepath File path for the module
394 * @return string $module_url Publicly accessible URL for the module
395 */
396 function get_module_url( $file ) {
397 $module_url = plugins_url( '/', $file );
398 return trailingslashit( $module_url );
399 }
400
401 /**
402 * Produce a human-readable version of the time since a timestamp
403 *
404 * @param int $original The UNIX timestamp we're producing a relative time for
405 * @return string $relative_time Human-readable version of the difference between the timestamp and now
406 */
407 function timesince( $original ) {
408 // array of time period chunks
409 $chunks = array(
410 array(60 * 60 * 24 * 365 , 'year'),
411 array(60 * 60 * 24 * 30 , 'month'),
412 array(60 * 60 * 24 * 7, 'week'),
413 array(60 * 60 * 24 , 'day'),
414 array(60 * 60 , 'hour'),
415 array(60 , 'minute'),
416 array(1 , 'second'),
417 );
418
419 $today = time(); /* Current unix time */
420 $since = $today - $original;
421
422 if ( $since > $chunks[2][0] ) {
423 $print = date("M jS", $original);
424
425 if( $since > $chunks[0][0] ) { // Seconds in a year
426 $print .= ", " . date( "Y", $original );
427 }
428
429 return $print;
430 }
431
432 // $j saves performing the count function each time around the loop
433 for ($i = 0, $j = count($chunks); $i < $j; $i++) {
434
435 $seconds = $chunks[$i][0];
436 $name = $chunks[$i][1];
437
438 // finding the biggest chunk (if the chunk fits, break)
439 if (($count = floor($since / $seconds)) != 0) {
440 break;
441 }
442 }
443
444 return sprintf( _n( "1 $name ago", "$count {$name}s ago", $count), $count);
445 }
446
447 /**
448 * Displays a list of users that can be selected!
449 *
450 * @since 0.7
451 *
452 * @todo Add pagination support for blogs with billions of users
453 *
454 * @param ???
455 * @param ???
456 */
457 function users_select_form( $selected = null, $args = null ) {
458
459 // Set up arguments
460 $defaults = array(
461 'list_class' => 'ef-users-select-form',
462 'input_id' => 'ef-selected-users'
463 );
464 $parsed_args = wp_parse_args( $args, $defaults );
465 extract($parsed_args, EXTR_SKIP);
466
467 $args = array(
468 'capability' => 'publish_posts',
469 'fields' => array(
470 'ID',
471 'display_name',
472 'user_email'
473 ),
474 'orderby' => 'display_name',
475 );
476 $args = apply_filters( 'ef_users_select_form_get_users_args', $args );
477
478 $users = get_users( $args );
479
480 if ( !is_array($selected) ) $selected = array();
481 ?>
482
483 <?php if( !empty($users) ) : ?>
484 <ul class="<?php echo esc_attr( $list_class ) ?>">
485 <?php foreach( $users as $user ) :
486 $checked = ( in_array($user->ID, $selected) ) ? 'checked="checked"' : '';
487 // Add a class to checkbox of current user so we know not to add them in notified list during notifiedMessage() js function
488 $current_user_class = ( get_current_user_id() == $user->ID ) ? 'class="post_following_list-current_user" ' : '';
489 ?>
490 <li>
491 <label for="<?php echo esc_attr( $input_id .'-'. $user->ID ) ?>">
492 <div class="ef-user-subscribe-actions">
493 <?php do_action( 'ef_user_subscribe_actions', $user->ID, $checked ) ?>
494 <input type="checkbox" id="<?php echo esc_attr( $input_id .'-'. $user->ID ) ?>" name="<?php echo esc_attr( $input_id ) ?>[]" value="<?php echo esc_attr( $user->ID ); ?>" <?php echo $checked; echo $current_user_class; ?> />
495 </div>
496
497 <span class="ef-user_displayname"><?php echo esc_html( $user->display_name ); ?></span>
498 <span class="ef-user_useremail"><?php echo esc_html( $user->user_email ); ?></span>
499 </label>
500 </li>
501 <?php endforeach; ?>
502 </ul>
503 <?php endif; ?>
504 <?php
505 }
506
507 /**
508 * Adds an array of capabilities to a role.
509 *
510 * @since 0.7
511 *
512 * @param string $role A standard WP user role like 'administrator' or 'author'
513 * @param array $caps One or more user caps to add
514 */
515 function add_caps_to_role( $role, $caps ) {
516
517 // In some contexts, we don't want to add caps to roles
518 if ( apply_filters( 'ef_kill_add_caps_to_role', false, $role, $caps ) )
519 return;
520
521 global $wp_roles;
522
523 if ( $wp_roles->is_role( $role ) ) {
524 $role = get_role( $role );
525 foreach ( $caps as $cap ) {
526 $role->add_cap( $cap );
527 }
528 }
529 }
530
531 /**
532 * Add settings help menus to our module screens if the values exist
533 * Auto-registered in Edit_Flow::register_module()
534 *
535 * @since 0.7
536 */
537 function action_settings_help_menu() {
538
539 $screen = get_current_screen();
540
541 if ( !method_exists( $screen, 'add_help_tab' ) )
542 return;
543
544 if ( $screen->id != 'edit-flow_page_' . $this->module->settings_slug )
545 return;
546
547 // Make sure we have all of the required values for our tab
548 if ( isset( $this->module->settings_help_tab['id'], $this->module->settings_help_tab['title'], $this->module->settings_help_tab['content'] ) ) {
549 $screen->add_help_tab( $this->module->settings_help_tab );
550
551 if ( isset( $this->module->settings_help_sidebar ) ) {
552 $screen->set_help_sidebar( $this->module->settings_help_sidebar );
553 }
554 }
555 }
556
557 /**
558 * Upgrade the term descriptions for all of the terms in a given taxonomy
559 */
560 function upgrade_074_term_descriptions( $taxonomy ) {
561 $args = array(
562 'hide_empty' => false,
563 );
564 $terms = get_terms( $taxonomy, $args );
565 foreach( $terms as $term ) {
566 // If we can detect that this term already follows the new scheme, let's skip it
567 $maybe_serialized = base64_decode( $term->description );
568 if ( is_serialized( $maybe_serialized ) )
569 continue;
570
571 $description_args = array();
572 // This description has been JSON-encoded, so let's decode it
573 if ( 0 === strpos( $term->description, '{' ) ) {
574 $string_to_unencode = stripslashes( htmlspecialchars_decode( $term->description ) );
575 $unencoded_array = json_decode( $string_to_unencode, true );
576 // Only continue processing if it actually was an array. Otherwise, set to the original string
577 if ( is_array( $unencoded_array ) ) {
578 foreach( $unencoded_array as $key => $value ) {
579 // html_entity_decode only works on strings but sometimes we store nested arrays
580 if ( !is_array( $value ) )
581 $description_args[$key] = html_entity_decode( $value, ENT_QUOTES );
582 else
583 $description_args[$key] = $value;
584 }
585 }
586 } else {
587 $description_args['description'] = $term->description;
588 }
589 $new_description = $this->get_encoded_description( $description_args );
590 wp_update_term( $term->term_id, $taxonomy, array( 'description' => $new_description ) );
591 }
592 }
593 }
594
595 }
596