PluginProbe
UpStream: a Project Management Plugin for WordPress / 2.1.0
UpStream: a Project Management Plugin for WordPress v2.1.0
trunk 1.39.0 1.39.1 1.39.2 1.39.3 2.0.7 2.1.0
upstream / includes / up-general-functions.php

up-general-functions.php in UpStream: a Project Management Plugin for WordPress 2.1.0, at includes/up-general-functions.php

2,051 lines 53.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle general functions.
4 *
5 * @package UpStream
6 */
7
8 // Exit if accessed directly.
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Alias for wp_kses_post
15 *
16 * @param string $s String data.
17 */
18 function upstream_esc_w( $s ) {
19 return wp_kses_post( $s );
20 }
21
22 /**
23 * Get a post id,
24 * no matter where we are or what we are doing.
25 */
26 function upstream_post_id() {
27 global $post, $wp_query;
28
29 $post_id = 0;
30 $get_data = isset( $_GET ) ? wp_unslash( $_GET ) : array();
31 $post_data = isset( $_POST ) ? wp_unslash( $_POST ) : array();
32 $post_type = isset( $post_data['post_type'] ) ? sanitize_text_field( $post_data['post_type'] ) : null;
33
34 // Try getting the post ID from get_the_ID function.
35 if ( ! $post_id ) {
36 $post_id = function_exists( 'get_the_ID' ) ? get_the_ID() : 0;
37 }
38
39 // Try getting the post ID from $post global variable.
40 if ( ! $post_id ) {
41 $post_id = ( $post && $post instanceof WP_Post ) ? $post->ID : 0;
42 }
43
44 // Try getting the post ID from $wp_query global variable.
45 if ( ! $post_id ) {
46 $post_id = ( $wp_query && $wp_query instanceof WP_Query ) ? $wp_query->get_queried_object_id() : 0;
47 }
48
49 // Try getting the post ID from $_GET['post'] variable.
50 if ( ! $post_id ) {
51 $post_id = isset( $get_data['post'] ) ? absint( $get_data['post'] ) : 0;
52 }
53
54 // Try getting the post ID from $_POST variable.
55 if ( ! empty( $post_data ) && $post_type && ! $post_id ) {
56 switch ( $post_type ) {
57 case 'project':
58 $nonce = isset( $post_data['upstream_admin_project_form_nonce'] ) ? $post_data['upstream_admin_project_form_nonce'] : null;
59 if ( ! wp_verify_nonce( $nonce, 'upstream_admin_project_form' ) ) {
60 return $post_id;
61 }
62 break;
63 case 'client':
64 $nonce = isset( $post_data['upstream_admin_client_form_nonce'] ) ? $post_data['upstream_admin_client_form_nonce'] : null;
65 if ( ! wp_verify_nonce( $nonce, 'upstream_admin_client_form' ) ) {
66 return $post_id;
67 }
68 break;
69 case 'upst_milestone':
70 $nonce = isset( $post_data['upstream_admin_upst_milestone_form_nonce'] ) ? $post_data['upstream_admin_upst_milestone_form_nonce'] : null;
71 if ( ! wp_verify_nonce( $nonce, 'upstream_admin_upst_milestone_form' ) ) {
72 return $post_id;
73 }
74 break;
75 case 'up_custom_field':
76 $nonce = isset( $post_data['upstream_admin_up_custom_field_form_nonce'] ) ? $post_data['upstream_admin_up_custom_field_form_nonce'] : null;
77 if ( ! wp_verify_nonce( $nonce, 'upstream_admin_up_custom_field_form' ) ) {
78 return $post_id;
79 }
80 break;
81 }
82
83 if ( ! $post_id ) {
84 $post_id = isset( $post_data['post'] ) ? absint( $post_data['post'] ) : 0;
85 }
86 if ( ! $post_id ) {
87 $post_id = isset( $post_data['post_ID'] ) ? absint( $post_data['post_ID'] ) : 0;
88 }
89 if ( ! $post_id ) {
90 $post_id = isset( $post_data['post_id'] ) ? absint( $post_data['post_id'] ) : 0;
91 }
92 if ( ! $post_id ) {
93 $post_id = isset( $post_data['post'] ) ? absint( $post_data['post'] ) : 0;
94 }
95 if ( ! $post_id ) {
96 if ( isset( $post_data['formdata'] ) ) {
97 parse_str( sanitize_text_field( $post_data['formdata'] ), $posted );
98 if ( isset( $posted['post_id'] ) ) {
99 $post_id = (int) $posted['post_id'];
100 }
101 }
102 }
103 }
104
105 // Will be an int post ID -- caller will check that it is a real post and accessible.
106 return $post_id;
107 }
108
109
110 /**
111 * Url for logging out, depending on client or WP user
112 */
113 function upstream_logout_url() {
114 $url = '';
115
116 if (
117 ( ! empty( $_SESSION ) && isset( $_SESSION['upstream'] ) && isset( $_SESSION['upstream']['user_id'] ) ) ||
118 ( ! is_user_logged_in() )
119 ) {
120 $url = '?action=logout';
121 } else {
122 $url = wp_logout_url( get_post_type_archive_link( 'project' ) );
123 }
124
125 return apply_filters( 'upstream_logout_url', $url );
126 }
127
128
129 /**
130 * Disable the bugs option
131 */
132 function upstream_disable_bugs() {
133 $options = get_option( 'upstream_general' );
134 $disable_bugs = isset( $options['disable_bugs'] ) ? $options['disable_bugs'] : array( 'no' );
135
136 return 'yes' === $disable_bugs[0];
137 }
138
139 /**
140 * Upstream_filesytem_enabled
141 */
142 function upstream_filesytem_enabled() {
143 $options = get_option( 'upstream_general' );
144 $use_upfs = isset( $options['use_upfs'] ) ? (int) $options['use_upfs'] : 0;
145
146 return 1 === $use_upfs && trim( upstream_filesystem_path() ) !== '';
147 }
148
149 /**
150 * Upstream_filesystem_max_size
151 */
152 function upstream_filesystem_max_size() {
153 return 100000000;
154 }
155
156 /**
157 * Upstream_filesystem_path
158 */
159 function upstream_filesystem_path() {
160 $options = get_option( 'upstream_general' );
161 $upfs_location = isset( $options['upfs_location'] ) ? $options['upfs_location'] : '';
162
163 return $upfs_location;
164 }
165
166 /**
167 * Set a unique id.
168 */
169 function upstream_admin_set_unique_id() {
170 return uniqid( get_current_user_id() );
171 }
172
173 /**
174 * Is a user logged in.
175 *
176 * @since 1.0.0
177 */
178 function upstream_is_user_logged_in() {
179 // Checks if the user is logged in through WordPress.
180 if ( is_user_logged_in() ) {
181 return true;
182 }
183
184 return UpStream_Login::user_is_logged_in();
185 }
186
187 /**
188 * Checks if current user is a WordPress user or client.
189 *
190 * @since 1.0.0
191 */
192 function upstream_current_user_id() {
193 if ( is_user_logged_in() ) {
194 return get_current_user_id();
195 } else {
196 return isset( $_SESSION['upstream'] ) && isset( $_SESSION['upstream']['user_id'] ) ? absint( $_SESSION['upstream']['user_id'] ) : 0;
197 }
198 }
199
200 /**
201 * Checks if current user is a WordPress user or client
202 */
203 function upstream_user_type() {
204 if ( is_user_logged_in() ) {
205 return 'wp';
206 } else {
207 return 'client';
208 }
209 }
210
211 /**
212 * Gets the client id that a user belongs to
213 *
214 * @param int $user_id user_id.
215 */
216 function upstream_get_users_client_id( $user_id ) {
217 $r = upstream_get_users_client_ids( $user_id );
218
219 if ( count( $r ) > 0 ) {
220 return $r[0];
221 }
222 return 0;
223 }
224
225 /**
226 * Upstream_get_users_client_ids
227 *
228 * @param int $user_id user_id.
229 */
230 function upstream_get_users_client_ids( $user_id ) {
231 global $wpdb;
232
233 $client_ids = Upstream_Cache::get_instance()->get( 'upstream_get_users_client_ids' . $user_id );
234
235 if ( false === $client_ids ) {
236 $client_ids = array();
237
238 $rowset = $wpdb->get_results(
239 sprintf(
240 '
241 SELECT `ID`, `post_title`
242 FROM `%s`
243 WHERE `post_type` = "client"
244 AND `post_status` = "publish"',
245 $wpdb->prefix . 'posts'
246 )
247 );
248
249 foreach ( $rowset as $row ) {
250
251 $client_id = $row->ID;
252 $client_users_list = array_filter( (array) get_post_meta( $client_id, '_upstream_new_client_users', true ) );
253 if ( count( $client_users_list ) > 0 ) {
254 foreach ( $client_users_list as $client_user ) {
255 if ( isset( $client_user['user_id'] ) && $client_user['user_id'] == $user_id ) {
256 $client_ids[] = $client_id;
257 }
258 }
259 }
260 }
261
262 Upstream_Cache::get_instance()->set( 'upstream_get_users_client_ids' . $user_id, $client_ids );
263
264 }
265
266 return $client_ids;
267 }
268
269 /**
270 * Get some data for current user
271 * returns a single item
272 * basically a wrapper for upstream_user_data()
273 *
274 * @param mixed $item Item data.
275 */
276 function upstream_current_user( $item = null ) {
277 if ( ! $item ) {
278 return;
279 }
280 $user_data = upstream_user_data( upstream_current_user_id() );
281 $return = isset( $user_data[ $item ] ) ? $user_data[ $item ] : '';
282
283 return $return;
284 }
285
286 /**
287 * Get some data for a user with ID passed
288 * returns a single item
289 * basically a wrapper for upstream_user_data()
290 *
291 * @param int $id Item id.
292 * @param mixed $item Item data.
293 */
294 function upstream_user_item( $id = 0, $item = null ) {
295 if ( ! $item || ! $id ) {
296 return;
297 }
298 $user_data = upstream_user_data( $id );
299 $return = isset( $user_data[ $item ] ) ? $user_data[ $item ] : '';
300
301 return $return;
302 }
303
304 /**
305 * Get the user avatar with full name in tooltips
306 *
307 * @param int $user_id User id.
308 * @param bool $display_tooltip Is display_tooltip.
309 */
310 function upstream_user_avatar( $user_id, $display_tooltip = true ) {
311 if ( ! $user_id ) {
312 return;
313 }
314
315 // get user data & ignore current user.
316 // if we want current user, pass the ID.
317 $user_data = upstream_user_data( $user_id, true );
318 $user_display_name = $user_data['display_name'];
319
320 // Display the name only.
321 if ( ! upstream_show_users_name() ) {
322 $url = isset( $user_data['avatar'] ) ? $user_data['avatar'] : '';
323 $tooltip = (bool) $display_tooltip ?
324 sprintf(
325 'title="%s" data-toggle="tooltip" data-placement="top" data-original-title="%1$s"',
326 esc_attr( $user_display_name )
327 ) : '';
328 $return = sprintf(
329 '<img class="avatar" src="%s" %s />',
330 esc_attr( $url ),
331 $tooltip
332 );
333 } else {
334 $return = '<span class="avatar_custom_text">' . esc_html( $user_display_name ) . '</span>';
335 }
336
337 return apply_filters( 'upstream_user_avatar', $return );
338 }
339
340 /**
341 * Get data for any user including current
342 * can send id
343 *
344 * @param mixed $data Data.
345 * @param bool $ignore_current Is ignore_current.
346 */
347 function upstream_user_data_uncached( $data = 0, $ignore_current = false ) {
348 // if no data sent, find current user email.
349 if ( ! $data && ! $ignore_current ) {
350 $data = upstream_get_email_address();
351 }
352
353 $user_data = null;
354 $type = is_email( $data ) ? 'email' : 'id';
355
356 $wp_user = Upstream_Cache::get_instance()->get( 'upstream_user_data_by' . $type . '.' . $data );
357
358 if ( false === $wp_user ) {
359 $wp_user = get_user_by( $type, $data );
360 }
361 Upstream_Cache::get_instance()->set( 'upstream_user_data_by' . $type . '.' . $data, $wp_user );
362
363 if ( empty( $wp_user ) ) {
364 $wp_user = wp_get_current_user();
365 }
366
367 if ( ! function_exists( 'is_plugin_active' ) ) {
368 include_once ABSPATH . 'wp-admin/includes/plugin.php';
369 }
370
371 $is_buddy_press_running = is_plugin_active( 'buddypress/bp-loader.php' ) && class_exists( 'BuddyPress' ) && function_exists( 'bp_core_fetch_avatar' );
372
373 if ( $wp_user && is_object( $wp_user ) ) {
374 $role = '';
375
376 if ( isset( $wp_user->roles )
377 && is_array( $wp_user->roles )
378 && count( $wp_user->roles ) > 0
379 ) {
380 $role = ucwords( array_values( $wp_user->roles )[0] );
381 }
382
383 if ( in_array( 'upstream_user', $wp_user->roles, true ) ) {
384 $role = sprintf(
385 // translators: %s: upstream_project_label.
386 __( '%s User', 'upstream' ),
387 upstream_project_label()
388 );
389 }
390 if ( in_array( 'upstream_manager', $wp_user->roles, true ) ) {
391 $role = sprintf(
392 // translators: %s: upstream_project_label.
393 __( '%s Manager', 'upstream' ),
394 upstream_project_label()
395 );
396 }
397 if ( in_array( 'upstream_client_user', $wp_user->roles, true ) ) {
398 $role = sprintf(
399 // translators: %s: upstream_project_label.
400 __( '%s Client User', 'upstream' ),
401 upstream_project_label()
402 );
403 }
404
405 $user_data = array(
406 'id' => $wp_user->ID,
407 'fname' => $wp_user->first_name,
408 'lname' => $wp_user->last_name,
409 'full_name' => $wp_user->first_name . ' ' . $wp_user->last_name,
410 'email' => $wp_user->user_email,
411 'display_name' => $wp_user->display_name,
412 'phone' => '',
413 'projects' => upstream_get_users_projects( $wp_user->ID ),
414 'role' => $role,
415 'avatar' => '',
416 );
417
418 if ( $is_buddy_press_running ) {
419 $user_data['avatar'] = bp_core_fetch_avatar(
420 array(
421 'item_id' => $wp_user->ID,
422 'type' => 'thumb',
423 'html' => false,
424 )
425 );
426 } else {
427 if ( is_plugin_active( 'wp-user-avatar/wp-user-avatar.php' ) && function_exists( 'wpua_functions_init' ) ) {
428 global $wp_query;
429
430 $exception = false;
431 $wp_query_data = $wp_query;
432
433 // Make sure WP_Query is loaded.
434 if ( ! ( $wp_query instanceof \WP_Query ) ) {
435 $wp_query_data = new WP_Query();
436 }
437
438 try {
439 // Make sure WP User Avatar dependencies are loaded.
440 require_once ABSPATH . 'wp-settings.php';
441 require_once ABSPATH . 'wp-includes/pluggable.php';
442 require_once ABSPATH . 'wp-includes/query.php';
443 require_once WP_PLUGIN_DIR . '/wp-user-avatar/wp-user-avatar.php';
444
445 // Load WP User Avatar plugin and its dependencies.
446 wpua_functions_init();
447
448 // Retrieve current user id.
449 $user_id = upstream_current_user_id();
450
451 // Retrieve the current user avatar URL.
452 $user_data['avatar'] = get_wp_user_avatar_src( $wp_user->ID );
453 } catch ( Exception $e ) {
454 $exception = $e;
455 }
456 } elseif ( is_plugin_active( 'custom-user-profile-photo/3five_cupp.php' ) && function_exists( 'get_cupp_meta' ) ) {
457 $user_data['avatar'] = get_cupp_meta( $wp_user->ID );
458 }
459
460 if ( empty( $user_data['avatar'] ) ) {
461 if ( ! function_exists( 'get_avatar_url' ) ) {
462 require_once ABSPATH . 'wp-includes/link-template.php';
463 }
464
465 $user_data['avatar'] = get_avatar_url(
466 $wp_user->user_email,
467 96,
468 get_option( 'avatar_default', 'mystery' )
469 );
470 }
471 }
472 } else {
473 global $wpdb;
474 $users = $wpdb->get_results(
475 $wpdb->prepare(
476 "SELECT *
477 FROM $wpdb->postmeta
478 WHERE meta_key = %s AND
479 meta_value REGEXP '.*\"%s\";s:[0-9]+:\"%s\".*'",
480 array(
481 '_upstream_client_users',
482 $type,
483 $data,
484 )
485 )
486 );
487
488 if ( ! $users ) {
489 return;
490 }
491
492 $metavalue = unserialize( $users[0]->meta_value );
493
494 foreach ( $metavalue as $key => $user ) {
495
496 // get the matching user.
497 if ( in_array( $data, array( $user['id'], $user['email'] ) ) ) {
498 $fname = isset( $user['fname'] ) ? trim( $user['fname'] ) : '';
499 $lname = isset( $user['lname'] ) ? trim( $user['lname'] ) : '';
500 $user_data = array(
501 'id' => $user['id'],
502 'fname' => $fname,
503 'lname' => $lname,
504 'full_name' => trim( $fname . ' ' . $lname ),
505 'email' => isset( $user['email'] ) ? $user['email'] : '',
506 'phone' => isset( $user['phone'] ) ? $user['phone'] : '',
507 'projects' => upstream_get_users_projects( $user['id'] ),
508 'role' => __( 'Client User', 'upstream' ),
509 );
510
511 $display_name = ! empty( $user_data['full_name'] ) ? $user_data['full_name'] : $user_data['email'];
512 $user_data['display_name'] = $display_name;
513
514 if ( $is_buddy_press_running ) {
515 $user_data['avatar'] = bp_core_fetch_avatar(
516 array(
517 'item_id' => $user['id'],
518 'type' => 'thumb',
519 'html' => false,
520 )
521 );
522 } else {
523 if ( ! function_exists( 'get_avatar_url' ) ) {
524 require_once ABSPATH . 'wp-includes/link-template.php';
525 }
526
527 $user_data['avatar'] = get_avatar_url(
528 $user['email'],
529 96,
530 get_option( 'avatar_default', 'mystery' )
531 );
532 }
533 }
534 }
535 }
536
537 return $user_data;
538 }
539
540 /**
541 * Upstream_user_data
542 *
543 * @param mixed $data User data.
544 * @param mixed $ignore_current isignore_current.
545 */
546 function upstream_user_data( $data = 0, $ignore_current = false ) {
547
548 $res = Upstream_Cache::get_instance()->get( 'upstream_user_data' . $data . '.' . $ignore_current );
549
550 if ( false === $res ) {
551
552 $res = upstream_user_data_uncached( $data, $ignore_current );
553 Upstream_Cache::get_instance()->set( 'upstream_user_data' . $data . '.' . $ignore_current, $res );
554 }
555 return $res;
556 }
557
558 /**
559 * Get a users email address from anything
560 * normalizes things as we can pass either nothing, or an id or an email.
561 *
562 * @param int $user User id.
563 */
564 function upstream_get_email_address( $user = 0 ) {
565 // if $user is already an email, simply return it.
566 if ( is_email( $user ) ) {
567 return $user;
568 }
569
570 $email = null;
571
572 // this assumes that $user is a WordPress user id.
573 if ( 0 != $user && is_numeric( $user ) ) {
574 $wp_user = get_user_by( 'id', $user );
575 $email = $wp_user->user_email;
576 }
577
578 // this assumes that $user is a client user id.
579 if ( 0 != $user && ! is_numeric( $user ) ) {
580 $client_id = upstream_get_users_client_id( $user );
581 $users = get_post_meta( $client_id, '_upstream_client_users', true );
582 if ( is_array( $users ) && count( $users ) > 0 ) :
583 foreach ( $users as $key => $user ) {
584 if ( $user['id'] == $user ) {
585 $email = $user['email'];
586 }
587 }
588 endif;
589 }
590
591 // this assumes we are a logged in WordPress user looking for our own info.
592 if ( ! $user && upstream_user_type() == 'wp' ) {
593 $wp_user = get_user_by( 'id', get_current_user_id() );
594 $email = $wp_user->user_email;
595 }
596
597 // this assumes we are a logged in client user looking for our own info.
598 if ( ! $user && upstream_user_type() == 'client' ) {
599 if ( ! isset( $_SESSION['upstream'] ) ) {
600 return null;
601 }
602
603 $client_id = absint( $_SESSION['upstream']['client_id'] );
604 $user_id = absint( $_SESSION['upstream']['user_id'] );
605 $users = get_post_meta( $client_id, '_upstream_client_users', true );
606
607 if ( is_array( $users ) && count( $users ) > 0 ) {
608 foreach ( $users as $key => $user ) {
609 if ( $user['id'] == $user_id ) {
610 $email = isset( $user['email'] ) ? $user['email'] : '';
611 }
612 }
613 }
614 }
615
616 return $email;
617 }
618
619 /**
620 * Gets a users name
621 * displays full name or email if no name set
622 *
623 * @param int $id User id.
624 * @param bool $show_email Is show_email.
625 */
626 function upstream_users_name( $id = 0, $show_email = false ) {
627 $user = upstream_user_data( $id, true );
628
629 if ( ! $user ) {
630 return;
631 }
632
633 // if first name exists, then show name. Else show email.
634 $output = $user['display_name'];
635
636 if ( $show_email && ! empty( $user['email'] ) ) {
637 $output .= " <a target='_blank' href='mailto:" . esc_html( $user['email'] ) . "' title='" . esc_html( $user['email'] ) . "'><span class='dashicons dashicons-email-alt'></span></a>";
638 }
639
640 return $output;
641 }
642
643
644 /**
645 * Retrieve all projects where the user has access to.
646 *
647 * @param numeric/WP_User $user The user to be checked.
648 *
649 * @return array
650 * @since 1.12.2
651 */
652 function upstream_get_users_projects( $user ) {
653 $user = $user instanceof \WP_User ? $user : new \WP_User( $user );
654 if ( 0 === $user->ID && ! apply_filters( 'upstream_permissions_filter_page_access', false ) ) {
655 return array();
656 }
657
658 $data = array();
659
660 $rowset = Upstream_Cache::get_instance()->get( 'upstream_get_users_projects' );
661
662 if ( false === $rowset ) {
663 $rowset = (array) get_posts(
664 array(
665 'post_type' => 'project',
666 'post_status' => 'publish',
667 'posts_per_page' => -1,
668 )
669 );
670 Upstream_Cache::get_instance()->set( 'upstream_get_users_projects', $rowset );
671 }
672
673 if ( count( $rowset ) > 0 ) {
674 foreach ( $rowset as $project ) {
675 if ( upstream_user_can_access_project( $user, $project->ID ) ) {
676 $data[ $project->ID ] = $project;
677 }
678 }
679 }
680
681 return $data;
682 }
683
684
685 /**
686 * Returns percentages for use in dropdowns.
687 */
688 function upstream_get_percentages_for_dropdown() {
689 $array = array(
690 '' => '0%',
691 '5' => '5%',
692 '10' => '10%',
693 '15' => '15%',
694 '20' => '20%',
695 '25' => '25%',
696 '30' => '30%',
697 '35' => '35%',
698 '40' => '40%',
699 '45' => '45%',
700 '50' => '50%',
701 '55' => '55%',
702 '60' => '60%',
703 '65' => '65%',
704 '70' => '70%',
705 '75' => '75%',
706 '80' => '80%',
707 '85' => '85%',
708 '90' => '90%',
709 '95' => '95%',
710 '100' => '100%',
711 );
712
713 return apply_filters( 'upstream_percentages', $array );
714 }
715
716
717 /**
718 * Run date formatting through here
719 *
720 * @param mixed $timestamp Timestamp.
721 * @param mixed $date_format Date_format.
722 */
723 function upstream_format_date( $timestamp, $date_format = null ) {
724 if ( empty( $date_format ) ) {
725 $date_format = get_option( 'date_format', 'Y-m-d' );
726 }
727
728 if ( ! $timestamp ) {
729 $date = null;
730 } else {
731 $date = date_i18n( $date_format, $timestamp );
732 }
733
734 return apply_filters( 'upstream_format_date', $date, $timestamp );
735 }
736
737
738 /**
739 * Convert date to unixtime format
740 *
741 * @param mixed $timestamp Timestamp.
742 * @param mixed $date_format Date_format.
743 */
744 function upstream_date_unixtime( $timestamp, $date_format = null ) {
745 // Return empty string if timestamp is empty.
746 if ( is_string( $timestamp ) ) {
747 $timestamp = trim( $timestamp );
748 }
749
750 if ( empty( $timestamp ) ) {
751 return '';
752 }
753
754 if ( is_null( $date_format ) ) {
755 $date_format = get_option( 'date_format', 'Y-m-d' );
756 }
757
758 $date = \DateTime::createFromFormat( $date_format, $timestamp );
759
760 if ( $date ) {
761 $date = $date->format( 'U' );
762 }
763
764 return apply_filters( 'upstream_date_mysql', $date, $timestamp );
765 }
766
767
768 /**
769 * Run time formatting through here
770 *
771 * @param mixed $timestamp Timestamp.
772 */
773 function upstream_format_time( $timestamp ) {
774 if ( ! $timestamp ) {
775 $time = null;
776 } else {
777 $time = date_i18n( get_option( 'time_format' ), $timestamp, false );
778 }
779
780 return apply_filters( 'upstream_format_date', $time, $timestamp );
781 }
782
783
784 /**
785 * Used within class-up-project
786 *
787 * @param mixed $value Timestamp value.
788 */
789 function upstream_timestamp_from_date( $value ) {
790 // if blank, return empty string.
791 if ( ! $value || empty( $value ) ) {
792 return '';
793 }
794
795 $timestamp = null;
796
797 // if already a timestamp, return the timestamp.
798 if ( is_numeric( $value ) && (int) $value == $value ) {
799 $timestamp = $value;
800 }
801
802 if ( ! $timestamp ) {
803 if ( empty( $value ) || is_array( $value ) ) {
804 return 0;
805 }
806
807 $date_format = get_option( 'date_format' );
808 $date = DateTime::createFromFormat( $date_format, trim( $value ) );
809
810 if ( $date ) {
811 $timestamp = $date->getTimestamp();
812 } else {
813 $date_object = date_create_from_format( $date_format, $value );
814 $timestamp = $date_object ? $date_object->setTime( 0, 0, 0 )->getTimeStamp() : strtotime( $value );
815 }
816 }
817
818 // returns the timestamp and sets it to the start of the day.
819 return strtotime( 'today', $timestamp );
820 }
821
822
823 /**
824 * Function to convert date format
825 * pinched from CMB2
826 */
827 function upstream_php_to_js_dateformat() {
828 $format = get_option( 'date_format' );
829 $supported_options = array(
830 'd' => 'dd', // Day, leading 0.
831 'j' => 'd', // Day, no 0.
832 'z' => 'o', // Day of the year, no leading zeroes,.
833 // 'D' => 'D', // Day name short, not sure how it'll work with translations.
834 // 'l' => 'DD', // Day name full, idem before.
835 'm' => 'mm', // Month of the year, leading 0.
836 'n' => 'm', // Month of the year, no leading 0.
837 // 'M' => 'M', // Month, Short name.
838 'F' => 'MM', // Month, full name,.
839 'y' => 'y', // Year, two digit.
840 'Y' => 'yy', // Year, full.
841 'H' => 'HH', // Hour with leading 0 (24 hour).
842 'G' => 'H', // Hour with no leading 0 (24 hour).
843 'h' => 'hh', // Hour with leading 0 (12 hour).
844 'g' => 'h', // Hour with no leading 0 (12 hour),.
845 'i' => 'mm', // Minute with leading 0,.
846 's' => 'ss', // Second with leading 0,.
847 'a' => 'tt', // am/pm.
848 'A' => 'TT', // AM/PM.
849 );
850
851 foreach ( $supported_options as $php => $js ) {
852 // replaces every instance of a supported option, but skips escaped characters.
853 $format = preg_replace( "~(?<!\\\\)$php~", $js, $format );
854 }
855
856 $format = preg_replace_callback( '~(?:\\\.)+~', 'upstream_wrap_escaped_chars', $format );
857
858 return $format;
859 }
860
861 /**
862 * Upstream_wrap_escaped_chars
863 *
864 * @param array $value Value.
865 */
866 function upstream_wrap_escaped_chars( $value ) {
867 return '&#39;' . str_replace( '\\', '', $value[0] ) . '&#39;';
868 }
869
870 /**
871 * Upstream_filter_closed_items
872 */
873 function upstream_filter_closed_items() {
874 $option = get_option( 'upstream_general' );
875
876 return isset( $option['filter_closed_items'] ) ? (bool) $option['filter_closed_items'] : false;
877 }
878
879 /**
880 * Upstream_archive_closed_items
881 */
882 function upstream_archive_closed_items() {
883 $option = get_option( 'upstream_general' );
884
885 return isset( $option['archive_closed_items'] ) ? (bool) $option['archive_closed_items'] : true;
886 }
887
888 /**
889 * Upstream_show_users_name
890 */
891 function upstream_show_users_name() {
892 $option = get_option( 'upstream_general' );
893
894 return isset( $option['show_users_name'] ) ? (bool) $option['show_users_name'] : false;
895 }
896
897 /**
898 * Upstream_logo_url
899 */
900 function upstream_logo_url() {
901 $option = get_option( 'upstream_general' );
902 $logo = $option['logo'];
903
904 return apply_filters( 'upstream_logo', $logo );
905 }
906
907 /**
908 * Upstream_login_heading
909 */
910 function upstream_login_heading() {
911 $option = get_option( 'upstream_general' );
912
913 return isset( $option['login_heading'] ) ? $option['login_heading'] : '';
914 }
915
916 /**
917 * Upstream_login_text
918 */
919 function upstream_login_text() {
920 $option = get_option( 'upstream_general' );
921
922 return isset( $option['login_text'] ) ? wp_kses_post( wpautop( $option['login_text'] ) ) : '';
923 }
924
925 /**
926 * Upstream_admin_email
927 */
928 function upstream_admin_email() {
929 $option = get_option( 'upstream_general' );
930
931 return isset( $option['admin_email'] ) ? $option['admin_email'] : '';
932 }
933
934 /**
935 * Retrieve the `admin_support_link` option value.
936 *
937 * @param array $option Array of options. If provided, there's no need to fetch everything again from DB.
938 *
939 * @return string
940 * @since 1.12.0
941 *
942 * @see https://github.com/upstreamplugin/UpStream/issues/81
943 */
944 function upstream_admin_support( $option ) {
945 if ( empty( $option ) ) {
946 $option = get_option( 'upstream_general' );
947 }
948
949 if ( isset( $option['admin_support_link'] ) ) {
950 return ! empty( $option['admin_support_link'] ) ? $option['admin_support_link'] : 'mailto:' . $option['admin_email'];
951 } else {
952 return isset( $option['admin_email'] ) ? 'mailto:' . $option['admin_email'] : '#';
953 }
954 }
955
956 /**
957 * Retrieve the `admin_support_link_label` option value.
958 *
959 * @param array $option Array of options. If provided, there's no need to fetch everything again from DB.
960 *
961 * @return string
962 * @since 1.12.0
963 *
964 * @see https://github.com/upstreamplugin/UpStream/issues/81
965 */
966 function upstream_admin_support_label( $option ) {
967 if ( empty( $option ) ) {
968 $option = get_option( 'upstream_general' );
969 }
970
971 if ( isset( $option['admin_support_label'] ) ) {
972 return ! empty( $option['admin_support_label'] ) ? $option['admin_support_label'] : '';
973 } else {
974 return __( 'Contact Admin', 'upstream' );
975 }
976 }
977
978 /**
979 * Check if Milestones are disabled for the current open project.
980 * If no ID is passed, this function tries to guess it by checking $_GET/$_POST vars.
981 *
982 * @param int $post_id The project ID to be checked.
983 *
984 * @return bool
985 * @since 1.8.0
986 */
987 function upstream_are_milestones_disabled( $post_id = 0 ) {
988 $are_milestones_disabled = false;
989 $post_id = (int) $post_id;
990
991 if ( $post_id <= 0 ) {
992 $post_id = (int) upstream_post_id();
993 }
994
995 if ( $post_id > 0 ) {
996 $the_meta = get_post_meta( $post_id, '_upstream_project_disable_milestones', false );
997 $are_milestones_disabled = ! empty( $the_meta ) && 'on' === $the_meta[0];
998 }
999
1000 return $are_milestones_disabled;
1001 }
1002
1003 /**
1004 * Check if Tasks are disabled for the current open project.
1005 * If no ID is passed, this function tries to guess it by checking $_GET/$_POST vars.
1006 *
1007 * @param int $post_id The project ID to be checked.
1008 *
1009 * @return bool
1010 * @since 1.8.0
1011 */
1012 function upstream_are_tasks_disabled( $post_id = 0 ) {
1013 $are_tasks_disabled = false;
1014 $post_id = (int) $post_id;
1015
1016 if ( $post_id <= 0 ) {
1017 $post_id = (int) upstream_post_id();
1018 }
1019
1020 if ( $post_id > 0 ) {
1021 $the_meta = get_post_meta( $post_id, '_upstream_project_disable_tasks', false );
1022 $are_tasks_disabled = ! empty( $the_meta ) && 'on' === $the_meta[0];
1023 }
1024
1025 return $are_tasks_disabled;
1026 }
1027
1028 /**
1029 * Check if Bugs are disabled for the current open project.
1030 * If no ID is passed, this function tries to guess it by checking $_GET/$_POST vars.
1031 *
1032 * @param int $post_id The project ID to be checked.
1033 *
1034 * @return bool
1035 * @since 1.8.0
1036 */
1037 function upstream_are_bugs_disabled( $post_id = 0 ) {
1038 $are_bugs_disabled = false;
1039 $post_id = (int) $post_id;
1040
1041 if ( $post_id <= 0 ) {
1042 $post_id = (int) upstream_post_id();
1043 }
1044
1045 if ( $post_id > 0 ) {
1046 $the_meta = get_post_meta( $post_id, '_upstream_project_disable_bugs', false );
1047 $are_bugs_disabled = ! empty( $the_meta ) && 'on' === $the_meta[0];
1048 }
1049
1050 return $are_bugs_disabled;
1051 }
1052
1053 /**
1054 * Check if Files are disabled for the current open project.
1055 * If no ID is passed, this function tries to guess it by checking $_GET/$_POST vars.
1056 *
1057 * @param int $post_id The project ID to be checked.
1058 *
1059 * @return bool
1060 * @since 1.8.0
1061 */
1062 function upstream_are_files_disabled( $post_id = 0 ) {
1063 $are_bugs_disabled = false;
1064 $post_id = (int) $post_id;
1065
1066 if ( $post_id <= 0 ) {
1067 $post_id = (int) upstream_post_id();
1068 }
1069
1070 if ( $post_id > 0 ) {
1071 $the_meta = get_post_meta( $post_id, '_upstream_project_disable_files', false );
1072 $are_bugs_disabled = ! empty( $the_meta ) && 'on' === $the_meta[0];
1073 }
1074
1075 return $are_bugs_disabled;
1076 }
1077
1078 /**
1079 * Upstream_tinymce_quicktags_settings
1080 *
1081 * @param array $tiny_mce tiny_mce data.
1082 */
1083 function upstream_tinymce_quicktags_settings( $tiny_mce ) {
1084 if ( preg_match( '/^(?:_upstream_project_|description|notes|new_message)/i', $tiny_mce['id'] ) ) {
1085 $buttons = 'strong,em,link,del,ul,ol,li,close';
1086
1087 /**
1088 * Upstream_tinymce_buttons
1089 *
1090 * @param array $buttons
1091 */
1092 $buttons = apply_filters( 'upstream_tinymce_buttons', $buttons );
1093
1094 $tiny_mce['buttons'] = $buttons;
1095 }
1096
1097 return $tiny_mce;
1098 }
1099
1100 /**
1101 * Upstream_tinymce_before_init_setup_toolbar
1102 *
1103 * @param array $tiny_mce tiny_mce data.
1104 */
1105 function upstream_tinymce_before_init_setup_toolbar( $tiny_mce ) {
1106 if ( ! isset( $tiny_mce['selector'] ) ) {
1107 return $tiny_mce;
1108 }
1109
1110 if ( preg_match( '/_upstream_project_|#description|#notes|#new_message|#upstream/i', $tiny_mce['selector'] ) ) {
1111 /**
1112 * Upstream_tinymce_toolbar
1113 *
1114 * @param string $buttons
1115 * @param string $toolbar
1116 */
1117 $tiny_mce['toolbar1'] = apply_filters(
1118 'upstream_tinymce_toolbar',
1119 'bold,italic,underline,strikethrough,bullist,numlist,link',
1120 'toolbar1'
1121 );
1122
1123 /**
1124 * This filter is documented above.
1125 */
1126 $tiny_mce['toolbar2'] = apply_filters( 'upstream_tinymce_toolbar', '', 'toolbar2' );
1127 /**
1128 * This filter is documented above.
1129 */
1130 $tiny_mce['toolbar3'] = apply_filters( 'upstream_tinymce_toolbar', '', 'toolbar3' );
1131 /**
1132 * This filter is documented above.
1133 */
1134 $tiny_mce['toolbar4'] = apply_filters( 'upstream_tinymce_toolbar', '', 'toolbar4' );
1135 }
1136
1137 return $tiny_mce;
1138 }
1139
1140 /**
1141 * Upstream_tinymce_before_init
1142 *
1143 * @param array $tiny_mce tiny_mce data.
1144 */
1145 function upstream_tinymce_before_init( $tiny_mce ) {
1146 if ( ! isset( $tiny_mce['selector'] ) ) {
1147 return $tiny_mce;
1148 }
1149
1150 if ( preg_match( '/_upstream_project_|#description|#notes|#new_message|#upstream/i', $tiny_mce['selector'] ) ) {
1151 if ( isset( $tiny_mce['plugins'] ) ) {
1152 $plugins_to_be_added = array(
1153 'charmap',
1154 'hr',
1155 'media',
1156 'paste',
1157 'tabfocus',
1158 'textcolor',
1159 'wpautoresize',
1160 'wpemoji',
1161 'wpgallery',
1162 'wpdialogs',
1163 'wptextpattern',
1164 'wpview',
1165 );
1166
1167 $plugins_list = explode( ',', $tiny_mce['plugins'] );
1168 $plugins_list_unique = array_unique( array_merge( $plugins_list, $plugins_to_be_added ) );
1169
1170 /**
1171 * Upstream_tinymce_plugins
1172 *
1173 * @param array $plugins_list
1174 */
1175 $plugins_list_unique = apply_filters( 'upstream_tinymce_plugins', $plugins_list_unique );
1176
1177 $tiny_mce['plugins'] = implode( ',', $plugins_list_unique );
1178 }
1179
1180 $external_plugins = apply_filters( 'upstream_tinymce_external_plugins', array() );
1181 $tiny_mce['external_plugins'] = wp_json_encode( $external_plugins );
1182 }
1183
1184 return $tiny_mce;
1185 }
1186
1187 /**
1188 * Upstream_disable_tasks
1189 */
1190 function upstream_disable_tasks() {
1191 $options = get_option( 'upstream_general' );
1192
1193 $disable_tasks = isset( $options['disable_tasks'] ) ? (array) $options['disable_tasks'] : array( 'no' );
1194
1195 $are_tasks_disabled = 'yes' === $disable_tasks[0];
1196
1197 return $are_tasks_disabled;
1198 }
1199
1200 /**
1201 * Upstream_disable_milestones
1202 */
1203 function upstream_disable_milestones() {
1204 $options = get_option( 'upstream_general' );
1205
1206 $disable_milestones = isset( $options['disable_milestones'] ) ? (array) $options['disable_milestones'] : array( 'no' );
1207
1208 $are_milestones_disabled = 'yes' === $disable_milestones[0];
1209
1210 return $are_milestones_disabled;
1211 }
1212
1213 /**
1214 * Upstream_disable_milestone_categories
1215 */
1216 function upstream_disable_milestone_categories() {
1217 $options = get_option( 'upstream_general' );
1218
1219 $checked = isset( $options['disable_milestone_categories'] ) ? (array) $options['disable_milestone_categories'] : array( 0 );
1220
1221 return 1 === $checked[0];
1222 }
1223
1224 /**
1225 * Upstream_disable_files
1226 */
1227 function upstream_disable_files() {
1228 $options = get_option( 'upstream_general' );
1229
1230 $disable_files = isset( $options['disable_files'] ) ? (array) $options['disable_files'] : array( 'no' );
1231
1232 $are_files_disabled = 'yes' === $disable_files[0];
1233
1234 return $are_files_disabled;
1235 }
1236
1237 /**
1238 * Apply OEmbed filters to a given string in an attempt to render potential embeddable content.
1239 * This function is called as a callback from CMB2 field method 'escape_cb'.
1240 *
1241 * @param mixed $content The unescaped content to be analyzed.
1242 * @param array $field_args Array of field arguments.
1243 * @param \CMB2_Field $field The field instance.
1244 *
1245 * @return mixed Escaped value to be displayed.
1246 * @see https://github.com/CMB2/CMB2/wiki/Field-Parameters#escape_cb
1247 *
1248 * @uses $wp_embed
1249 *
1250 * @since 1.10.0
1251 */
1252 function upstream_apply_oembed_filters_to_wysiwyg_editor_content( $content, $field_args, $field ) {
1253 global $wp_embed;
1254
1255 $content = (string) $content;
1256
1257 if ( strlen( $content ) > 0 ) {
1258 $content = $wp_embed->autoembed( $content );
1259 $content = $wp_embed->run_shortcode( $content );
1260 $content = wpautop( $content );
1261 $content = do_shortcode( $content );
1262 }
1263
1264 return $content;
1265 }
1266
1267 /**
1268 * Check if Comments/Discussion are disabled for the current open project.
1269 * If no ID is passed, this function tries to guess it by checking $_GET/$_POST vars.
1270 *
1271 * @param int $post_id The project ID to be checked.
1272 *
1273 * @return bool
1274 * @since 1.8.0
1275 */
1276 function upstream_are_comments_disabled( $post_id = 0 ) {
1277 // General settings.
1278 $plugin_options = get_option( 'upstream_general' );
1279 $disabled = isset( $plugin_options['disable_project_comments'] ) && false === (bool) $plugin_options['disable_project_comments'];
1280
1281 if ( $disabled ) {
1282 return true;
1283 }
1284
1285 // Project's settings.
1286 $are_comments_disabled = false;
1287 $post_id = (int) $post_id;
1288
1289 if ( $post_id <= 0 ) {
1290 $post_id = (int) upstream_post_id();
1291 }
1292
1293 if ( $post_id > 0 ) {
1294 $the_meta = get_post_meta( $post_id, '_upstream_project_disable_comments', false );
1295 $are_comments_disabled = ! empty( $the_meta ) && 'on' === $the_meta[0];
1296 }
1297
1298 return $are_comments_disabled;
1299 }
1300
1301 /**
1302 * Check if Projects Categorization is currently disabled.
1303 *
1304 * @return bool
1305 * @since 1.12.0
1306 */
1307 function upstream_is_project_categorization_disabled() {
1308 $options = get_option( 'upstream_general' );
1309
1310 $is_disabled = isset( $options['disable_categories'] ) ? (bool) $options['disable_categories'] : false;
1311
1312 return $is_disabled;
1313 }
1314
1315 /**
1316 * Check if Clients feature is disabled.
1317 *
1318 * @return bool
1319 * @since 1.12.0
1320 */
1321 function upstream_is_clients_disabled() {
1322 $options = get_option( 'upstream_general' );
1323
1324 $is_disabled = isset( $options['disable_clients'] ) ? (bool) $options['disable_clients'] : false;
1325
1326 return $is_disabled;
1327 }
1328
1329 /**
1330 * Check if should Select Users by Default.
1331 *
1332 * @return bool
1333 */
1334 function upstream_select_users_by_default() {
1335 $options = get_option( 'upstream_general' );
1336
1337 $enabled = isset( $options['pre_select_users'] ) ? (bool) $options['pre_select_users'] : false;
1338
1339 return $enabled;
1340 }
1341
1342 /**
1343 * Retrieve the avatar URL from a given user.
1344 *
1345 * @param int $user_id The user ID.
1346 *
1347 * @return string|bool
1348 * @since 1.12.0
1349 */
1350 function upstream_get_user_avatar_url( $user_id ) {
1351 $user_id = (int) $user_id;
1352 if ( $user_id <= 0 ) {
1353 return false;
1354 }
1355
1356 if ( ! function_exists( 'is_plugin_active' ) ) {
1357 include_once ABSPATH . 'wp-admin/includes/plugin.php';
1358 }
1359
1360 $avatar_url = '';
1361
1362 // Check if BuddyPress is running so we can borrow its functions.
1363 $is_buddy_press_running = is_plugin_active( 'buddypress/bp-loader.php' ) && class_exists( 'BuddyPress' ) && function_exists( 'bp_core_fetch_avatar' );
1364 if ( $is_buddy_press_running ) {
1365 $avatar_url = (string) bp_core_fetch_avatar(
1366 array(
1367 'item_id' => $user_id,
1368 'type' => 'thumb',
1369 'html' => false,
1370 )
1371 );
1372 }
1373
1374 // Check if WP-User-Avatar is running so we can borrow its functions.
1375 if ( empty( $avatar_url ) && is_plugin_active( 'wp-user-avatar/wp-user-avatar.php' ) && function_exists( 'wpua_functions_init' ) ) {
1376 global $wp_query;
1377
1378 $wp_query_data = $wp_query;
1379 $exception = false;
1380
1381 // Make sure WP_Query is loaded.
1382 if ( ! ( $wp_query instanceof \WP_Query ) ) {
1383 $wp_query_data = new WP_Query();
1384 }
1385
1386 try {
1387 // Make sure WP User Avatar dependencies are loaded.
1388 require_once ABSPATH . 'wp-settings.php';
1389 require_once ABSPATH . 'wp-includes/pluggable.php';
1390 require_once ABSPATH . 'wp-includes/query.php';
1391 require_once WP_PLUGIN_DIR . '/wp-user-avatar/wp-user-avatar.php';
1392
1393 // Load WP User Avatar plugin and its dependencies.
1394 wpua_functions_init();
1395
1396 // Retrieve the current user avatar URL.
1397 $avatar_url = (string) get_wp_user_avatar_src( $user_id );
1398 } catch ( Exception $e ) {
1399 // Do nothing.
1400 $exception = $e;
1401 }
1402 }
1403
1404 // Check if Custom User Profile Photo is running so we can borrow its functions.
1405 if ( empty( $avatar_url ) && is_plugin_active( 'custom-user-profile-photo/3five_cupp.php' ) && function_exists( 'get_cupp_meta' ) ) {
1406 $avatar_url = (string) get_cupp_meta( $user_id );
1407 }
1408
1409 if ( empty( $avatar_url ) ) {
1410 if ( ! function_exists( 'get_avatar_url' ) ) {
1411 require_once ABSPATH . 'wp-includes/link-template.php';
1412 }
1413
1414 $avatar_url = (string) get_avatar_url( $user_id, 96, get_option( 'avatar_default', 'mystery' ) );
1415 }
1416
1417 return $avatar_url;
1418 }
1419
1420 /**
1421 * Check if the current user is either administrator or UpStream Manager.
1422 *
1423 * @param WP_User $user User object.
1424 * @return bool
1425 * @since 1.12.0
1426 */
1427 function upstream_is_user_either_manager_or_admin( $user = null ) {
1428 if ( empty( $user ) || ! ( $user instanceof \WP_User ) ) {
1429 $user = wp_get_current_user();
1430 }
1431
1432 if ( $user->ID > 0 && isset( $user->roles ) ) {
1433 return count( array_intersect( (array) $user->roles, array( 'administrator', 'upstream_manager' ) ) ) > 0;
1434 }
1435
1436 return false;
1437 }
1438
1439 /**
1440 * Generates a random string of custom length.
1441 *
1442 * @param int $length The length of the random string.
1443 * @param string $chars_pool The characters that might compose the string.
1444 *
1445 * @return string
1446 * @since 1.12.2
1447 */
1448 function upstream_generate_random_string(
1449 $length,
1450 $chars_pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
1451 ) {
1452 $random_string = '';
1453 $max_chars_pool_length = mb_strlen( $chars_pool, '8bit' ) - 1;
1454
1455 for ( $length_index = 0; $length_index < $length; ++$length_index ) {
1456 $random_string .= $chars_pool[ random_int( 0, $max_chars_pool_length ) ];
1457 }
1458
1459 return $random_string;
1460 }
1461
1462 /**
1463 * Check if comments are allowed on projects.
1464 *
1465 * @return bool
1466 * @since 1.13.0
1467 */
1468 function upstream_are_project_comments_enabled() {
1469 // Retrieve UpStream general options.
1470 $options = get_option( 'upstream_general' );
1471 $option_name = 'disable_project_comments';
1472 // Check if the option exists.
1473 if ( isset( $options[ $option_name ] ) ) {
1474 $allow = (bool) $options[ $option_name ];
1475 } else {
1476 $legacy_option_name = 'disable_discussion';
1477 // Check if user has legacy option set.
1478 if ( isset( $options[ $legacy_option_name ] ) ) {
1479 if ( is_array( $options[ $legacy_option_name ] ) || is_object( $options[ $legacy_option_name ] ) ) {
1480 $options[ $legacy_option_name ] = json_decode( json_encode( $options[ $legacy_option_name ] ), true );
1481 if ( ! empty( $options[ $legacy_option_name ] ) ) {
1482 $options[ $legacy_option_name ] = array_reverse( $options[ $legacy_option_name ] );
1483 $legacy_option_value = array_pop( $options[ $legacy_option_name ] );
1484 } else {
1485 $legacy_option_value = '';
1486 }
1487 } else {
1488 $legacy_option_value = (string) $options[ $legacy_option_name ];
1489 }
1490
1491 if ( is_string( $legacy_option_value ) ) {
1492 $allow = strtoupper( trim( $legacy_option_value ) ) !== 'YES';
1493 } else {
1494 $allow = true;
1495 }
1496
1497 unset( $options[ $legacy_option_name ] );
1498
1499 // Migrate existent legacy option.
1500 $options[ $option_name ] = (int) ! $allow;
1501
1502 // Update options.
1503 update_option( 'upstream_general', $options );
1504 } else {
1505 // Default value.
1506 $allow = true;
1507 }
1508 }
1509
1510 return $allow;
1511 }
1512
1513 /**
1514 * Check if comments are allowed on milestones.
1515 *
1516 * @return bool
1517 * @since 1.13.0
1518 */
1519 function upstream_are_comments_enabled_on_milestones() {
1520 $options = get_option( 'upstream_general' );
1521
1522 $option_name = 'disable_comments_on_milestones';
1523
1524 $allow = isset( $options[ $option_name ] ) ? (bool) $options[ $option_name ] : true;
1525
1526 return $allow;
1527 }
1528
1529 /**
1530 * Check if comments are allowed on tasks.
1531 *
1532 * @return bool
1533 * @since 1.13.0
1534 */
1535 function upstream_are_comments_enabled_on_tasks() {
1536 $options = get_option( 'upstream_general' );
1537
1538 $option_name = 'disable_comments_on_tasks';
1539
1540 $allow = isset( $options[ $option_name ] ) ? (bool) $options[ $option_name ] : true;
1541
1542 return $allow;
1543 }
1544
1545 /**
1546 * Check if comments are allowed on bugs.
1547 *
1548 * @return bool
1549 * @since 1.13.0
1550 */
1551 function upstream_are_comments_enabled_on_bugs() {
1552 $options = get_option( 'upstream_general' );
1553
1554 $option_name = 'disable_comments_on_bugs';
1555
1556 $allow = isset( $options[ $option_name ] ) ? (bool) $options[ $option_name ] : true;
1557
1558 return $allow;
1559 }
1560
1561 /**
1562 * Check if comments are allowed on files.
1563 *
1564 * @return bool
1565 * @since 1.13.0
1566 */
1567 function upstream_are_comments_enabled_on_files() {
1568 $options = get_option( 'upstream_general' );
1569
1570 $option_name = 'disable_comments_on_files';
1571
1572 $allow = isset( $options[ $option_name ] ) ? (bool) $options[ $option_name ] : true;
1573
1574 return $allow;
1575 }
1576
1577 /**
1578 * Check if should show all the projects in the sidebar.
1579 *
1580 * @return bool
1581 * @since 1.13.0
1582 */
1583 function upstream_show_all_projects_in_sidebar() {
1584 $options = get_option( 'upstream_general' );
1585
1586 $option_name = 'show_all_projects_sidebar';
1587
1588 $allow = isset( $options[ $option_name ] ) ? (bool) $options[ $option_name ] : false;
1589
1590 return $allow;
1591 }
1592
1593
1594 /**
1595 * Check if should send emails on new comment.
1596 *
1597 * @return bool
1598 * @since 1.13.0
1599 */
1600 function upstream_send_notifications_for_new_comments() {
1601 $options = get_option( 'upstream_general' );
1602
1603 $option_name = 'send_notifications_for_new_comments';
1604
1605 $allow = isset( $options[ $option_name ] ) ? (bool) $options[ $option_name ] : true;
1606
1607 return $allow;
1608 }
1609
1610 /**
1611 * Slighted modification of PHP's native nl2br function.
1612 *
1613 * @param string $subject String to be processed.
1614 *
1615 * @return string
1616 * @since 1.13.1
1617 */
1618 function upstream_nl2br( $subject ) {
1619 // Step 1: Add <br /> tags for each line-break.
1620 $subject = nl2br( $subject );
1621
1622 // Step 2: Remove the actual line-breaks.
1623 $subject = str_replace( "\n", '', $subject );
1624 $subject = str_replace( "\r", '', $subject );
1625
1626 // Step 3: Restore the line-breaks that are inside <pre></pre> tags.
1627 if ( preg_match_all( '/\<pre\>(.*?)\<\/pre\>/', $subject, $match ) ) {
1628 foreach ( $match as $a ) {
1629 foreach ( $a as $b ) {
1630 $subject = str_replace(
1631 '<pre>' . $b . '</pre>',
1632 '<pre>' . str_replace( '<br />', PHP_EOL, $b ) . '</pre>',
1633 $subject
1634 );
1635 }
1636 }
1637 }
1638
1639 // Step 4: Removes extra <br /> tags.
1640
1641 // Before <pre> tags.
1642 $subject = str_replace( '<br /><br /><br /><pre>', '<br /><br /><pre>', $subject );
1643 // After </pre> tags.
1644 $subject = str_replace( '</pre><br /><br />', '</pre><br />', $subject );
1645
1646 // Arround <ul></ul> tags.
1647 $subject = str_replace( '<br /><br /><ul>', '<br /><ul>', $subject );
1648 $subject = str_replace( '</ul><br /><br />', '</ul><br />', $subject );
1649 // Inside <ul> </ul> tags.
1650 $subject = str_replace( '<ul><br />', '<ul>', $subject );
1651 $subject = str_replace( '<br /></ul>', '</ul>', $subject );
1652
1653 // Arround <ol></ol> tags.
1654 $subject = str_replace( '<br /><br /><ol>', '<br /><ol>', $subject );
1655 $subject = str_replace( '</ol><br /><br />', '</ol><br />', $subject );
1656 // Inside <ol> </ol> tags.
1657 $subject = str_replace( '<ol><br />', '<ol>', $subject );
1658 $subject = str_replace( '<br /></ol>', '</ol>', $subject );
1659
1660 // Arround <li></li> tags.
1661 $subject = str_replace( '<br /><li>', '<li>', $subject );
1662 $subject = str_replace( '</li><br />', '</li>', $subject );
1663
1664 return $subject;
1665 }
1666
1667 /**
1668 * Upstream Should Run Cmb2
1669 */
1670 function upstream_should_run_cmb2() {
1671 global $pagenow;
1672
1673 $get_data = isset( $_GET ) ? wp_unslash( $_GET ) : array();
1674 $post_data = isset( $_POST ) ? wp_unslash( $_POST ) : array();
1675
1676 if (
1677 'post.php' === $pagenow ||
1678 'post-new.php' === $pagenow
1679 ) {
1680 $post_id = isset( $get_data['post'] ) ? absint( $get_data['post'] ) : 0;
1681 $post_type = get_post_type( $post_id );
1682
1683 if ( empty( $post_type ) ) {
1684 $post_type = isset( $get_data['post_type'] ) ? sanitize_text_field( $get_data['post_type'] ) : '';
1685 }
1686
1687 // Check post type based on the $_POST and nonce.
1688 if ( empty( $post_type ) && isset( $post_data['post_type'] ) ) {
1689 $post_type = sanitize_text_field( $post_data['post_type'] );
1690
1691 switch ( $post_type ) {
1692 case 'project':
1693 $nonce = isset( $post_data['upstream_admin_project_form_nonce'] ) ? $post_data['upstream_admin_project_form_nonce'] : null;
1694 if ( wp_verify_nonce( $nonce, 'upstream_admin_project_form' ) ) {
1695 $nonce_passed = true;
1696 }
1697 break;
1698 case 'client':
1699 $nonce = isset( $post_data['upstream_admin_client_form_nonce'] ) ? $post_data['upstream_admin_client_form_nonce'] : null;
1700 if ( wp_verify_nonce( $nonce, 'upstream_admin_client_form' ) ) {
1701 $nonce_passed = true;
1702 }
1703 break;
1704 default:
1705 $nonce_passed = false;
1706 break;
1707 }
1708
1709 return $nonce_passed;
1710 }
1711
1712 $post_types_using_cmb2 = apply_filters( 'upstream:post_types_using_cmb2', array( 'project', 'client' ) );
1713
1714 if ( in_array( $post_type, $post_types_using_cmb2, true ) ) {
1715 return true;
1716 }
1717 } elseif (
1718 'admin.php' === $pagenow
1719 && isset( $get_data['page'] )
1720 && preg_match( '/^upstream_/i', sanitize_text_field( $get_data['page'] ) )
1721 ) {
1722 return true;
1723 }
1724
1725 return false;
1726 }
1727
1728 /**
1729 * UpstreamGetUsersMap
1730 */
1731 function upstream_get_users_map() {
1732 $map = array();
1733
1734 $rowset = get_users(
1735 array(
1736 'fields' => array( 'ID', 'display_name' ),
1737 )
1738 );
1739
1740 foreach ( $rowset as $user ) {
1741 $map[ (int) $user->ID ] = $user->display_name;
1742 }
1743
1744 return $map;
1745 }
1746
1747 /**
1748 * UpstreamGetDateFormatForJsDatepicker
1749 */
1750 function upstream_get_date_format_for_js_datepicker() {
1751 $format = get_option( 'date_format' );
1752 $supported_options = array(
1753 'd' => 'dd', // Day, leading 0.
1754 'j' => 'd', // Day, no 0.
1755 'z' => 'o', // Day of the year, no leading zeroes,.
1756 // 'D' => 'D', // Day name short, not sure how it'll work with translations.
1757 // 'l' => 'DD', // Day name full, idem before.
1758 'm' => 'mm', // Month of the year, leading 0.
1759 'n' => 'm', // Month of the year, no leading 0.
1760 // 'M' => 'M', // Month, Short name.
1761 'F' => 'MM', // Month, full name,.
1762 'y' => 'yy', // Year, two digit.
1763 'Y' => 'yyyy', // Year, full.
1764 'H' => 'HH', // Hour with leading 0 (24 hour).
1765 'G' => 'H', // Hour with no leading 0 (24 hour).
1766 'h' => 'hh', // Hour with leading 0 (12 hour).
1767 'g' => 'h', // Hour with no leading 0 (12 hour),.
1768 'i' => 'mm', // Minute with leading 0,.
1769 's' => 'ss', // Second with leading 0,.
1770 'a' => 'tt', // am/pm.
1771 'A' => 'TT', // AM/PM.
1772 'S' => '', // th, rd, st.
1773 );
1774
1775 foreach ( $supported_options as $php => $js ) {
1776 // replaces every instance of a supported option, but skips escaped characters.
1777 $format = preg_replace( "~(?<!\\\\)$php~", $js, $format );
1778 }
1779
1780 $format = preg_replace_callback( '~(?:\\\.)+~', 'upstream_wrap_escaped_chars', $format );
1781
1782 return $format;
1783 }
1784
1785 /**
1786 * UserCanReceiveCommentRepliesNotification
1787 *
1788 * @param int $user_id User id.
1789 */
1790 function upstream_user_can_receive_comment_replies_notification( $user_id = 0 ) {
1791 if ( ! is_numeric( $user_id ) ) {
1792 return false;
1793 }
1794
1795 if ( (int) $user_id <= 0 ) {
1796 $user_id = get_current_user_id();
1797 }
1798
1799 $receive_notifications = get_user_meta( $user_id, 'upstream_comment_replies_notification', true ) !== 'no';
1800
1801 return $receive_notifications;
1802 }
1803
1804 /**
1805 * Retrieve a list of Milestones available on this instance.
1806 *
1807 * @return array
1808 * @since 1.17.0
1809 */
1810 function upstream_get_milestones() {
1811 $posts = get_posts(
1812 array(
1813 'post_status' => 'publish',
1814 'posts_per_page' => -1,
1815 'post_type' => 'upst_milestone',
1816 'orderby' => 'menu_order',
1817 'order' => 'ASC',
1818 )
1819 );
1820
1821 $milestones = array();
1822
1823 if ( ! empty( $posts ) ) {
1824 foreach ( $posts as $post ) {
1825 $data = $post;
1826 $milestones[ $post->ID ] = $data;
1827 }
1828 }
1829
1830 return $milestones;
1831
1832 }
1833
1834 /**
1835 * Retrieve a list of Milestones titles available on this instance.
1836 *
1837 * @return array
1838 * @since 1.17.0
1839 */
1840 function upstream_get_milestones_titles() {
1841 $data = array();
1842
1843 $milestones = upstream_get_milestones();
1844 foreach ( $milestones as $milestone ) {
1845 if ( isset( $milestone->ID ) ) {
1846 $data[ $milestone->ID ] = $milestone->post_title;
1847 }
1848 }
1849
1850 return $data;
1851 }
1852
1853 /**
1854 * Retrieve a list of Tasks available on this instance.
1855 *
1856 * @return array
1857 * @since 1.17.0
1858 */
1859 function upstream_get_tasks_statuses() {
1860 $data = array();
1861
1862 $tasks = (array) get_option( 'upstream_tasks' );
1863 if ( isset( $tasks['statuses'] ) ) {
1864 foreach ( $tasks['statuses'] as $index => $task ) {
1865 if ( isset( $task['id'] ) ) {
1866 $task['order'] = $index;
1867
1868 $data[ $task['id'] ] = $task;
1869 }
1870 }
1871 }
1872
1873 return $data;
1874 }
1875
1876 /**
1877 * Retrieve a list of Task statuses titles available on this instance.
1878 *
1879 * @return array
1880 * @since 1.17.0
1881 */
1882 function upstream_get_tasks_statuses_titles() {
1883 $data = array();
1884
1885 $tasks = upstream_get_tasks_statuses();
1886 foreach ( $tasks as $task ) {
1887 if ( isset( $task['id'] ) ) {
1888 $data[ $task['id'] ] = $task['name'];
1889 }
1890 }
1891
1892 return $data;
1893 }
1894
1895 /**
1896 * GetBugsStatuses
1897 */
1898 function upstream_get_bugs_statuses() {
1899 $data = array();
1900
1901 $bugs = (array) get_option( 'upstream_bugs' );
1902 if ( isset( $bugs['statuses'] ) ) {
1903 foreach ( $bugs['statuses'] as $index => $bug_status ) {
1904 if ( isset( $bug_status['id'] ) ) {
1905 $bug_status['order'] = $index;
1906
1907 $data[ $bug_status['id'] ] = $bug_status;
1908 }
1909 }
1910 }
1911
1912 return $data;
1913 }
1914
1915 /**
1916 * GetBugsSeverities
1917 */
1918 function upstream_get_bugs_severities() {
1919 $data = array();
1920
1921 $bugs = (array) get_option( 'upstream_bugs' );
1922 if ( isset( $bugs['severities'] ) ) {
1923 foreach ( $bugs['severities'] as $index => $bug_severity ) {
1924 if ( isset( $bug_severity['id'] ) ) {
1925 $bug_severity['order'] = $index;
1926
1927 $data[ $bug_severity['id'] ] = $bug_severity;
1928 }
1929 }
1930 }
1931
1932 return $data;
1933 }
1934
1935 /**
1936 * Upstream_media_unrestricted_roles
1937 */
1938 function upstream_media_unrestricted_roles() {
1939 $option = get_option( 'upstream_general' );
1940
1941 return isset( $option['media_unrestricted_roles'] ) ? $option['media_unrestricted_roles'] : array( 'administrator' );
1942 }
1943
1944
1945 /**
1946 * DEPRECATED
1947 */
1948
1949 /**
1950 * Retrieve a DateTimeZone object of the current WP's timezone.
1951 * This function falls back to UTC in case of an invalid/empty timezone option.
1952 *
1953 * @return \DateTimeZone
1954 * @deprecated
1955 *
1956 * @since 1.12.3
1957 */
1958 function upstreamGetTimeZone() {
1959 $tz = (string) get_option( 'timezone_string' );
1960
1961 try {
1962 $the_time_zone = new DateTimeZone( $tz );
1963 } catch ( Exception $e ) {
1964 $the_time_zone = new DateTimeZone( 'UTC' );
1965 }
1966
1967 return $the_time_zone;
1968 }
1969
1970 /**
1971 * Convert a given date (UTC)/timestamp to the instance's timezone.
1972 *
1973 * @param int|string $subject The date to be converted. If int, assume it's a timestamp.
1974 * @param bool $include_time Is include_time.
1975 *
1976 * @return string|false The converted string or false in case of failure.
1977 * @since 1.11.0
1978 * @deprecated
1979 */
1980 function upstream_convert_UTC_date_to_timezone( $subject, $include_time = true ) {
1981 try {
1982 $date_format = get_option( 'date_format' );
1983
1984 if ( true === $include_time ) {
1985 $date_format .= ' ' . get_option( 'time_format' );
1986 }
1987
1988 if ( is_numeric( $subject ) ) {
1989 $the_date = new DateTime();
1990 $the_date->setTimestamp( $subject );
1991 } else {
1992 $the_date = new DateTime( $subject );
1993 }
1994
1995 $instance_timezone = upstreamGetTimeZone();
1996 $the_date->setTimeZone( $instance_timezone );
1997
1998 return $the_date->format( $date_format );
1999 } catch ( Exception $e ) {
2000 return false;
2001 }
2002 }
2003
2004 /**
2005 * Upstream_get_users_display_name
2006 *
2007 * @param array $users Users data.
2008 *
2009 * @return string
2010 */
2011 function upstream_get_users_display_name( $users ) {
2012 return upstream_get_users_display_name_cached( $users );
2013 }
2014
2015 /**
2016 * Upstream_get_users_display_name_cached
2017 *
2018 * @param array $users Users data.
2019 */
2020 function upstream_get_users_display_name_cached( $users ) {
2021 $allusers = Upstream_Cache::get_instance()->get( 'upstream_get_users_display_name_cached' );
2022 if ( false === $allusers ) {
2023 $allusers = get_users();
2024 Upstream_Cache::get_instance()->set( 'upstream_get_users_display_name_cached', $allusers );
2025 }
2026
2027 $userhash = array();
2028 foreach ( $users as $u ) {
2029 $userhash[ $u ] = true;
2030 }
2031
2032 $allusernames = array();
2033 foreach ( $allusers as $user ) {
2034 if ( isset( $userhash[ $user->ID ] ) ) {
2035 $allusernames[] = $user->display_name;
2036 }
2037 }
2038
2039 return implode( '<br>', $allusernames );
2040 }
2041
2042 /**
2043 * Upstream_admin_get_options_milestones
2044 *
2045 * @return array
2046 * @deprecated
2047 */
2048 function upstream_admin_get_options_milestones() {
2049 return upstream_project_milestones();
2050 }
2051