PluginProbe
Edit Flow / 0.9.1
Edit Flow v0.9.1
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.1, at common/php/class-module.php

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