PluginProbe
Edit Flow / 0.9.6
Edit Flow v0.9.6
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.6, at common/php/class-module.php

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