PluginProbe
UpStream: a Project Management Plugin for WordPress / 2.0.7
UpStream: a Project Management Plugin for WordPress v2.0.7
trunk 1.39.0 1.39.1 1.39.2 1.39.3 2.0.7 2.1.0
← All changes | class-upstream.php +597 -600 trunk2.0.7 View file →
@@ -1,600 +1,597 @@
1 -<?php
2 -/**
3 - * Main UpStream Class.
4 - *
5 - * @package UpStream
6 - */
7 -
8 -use UpStream\Container;
9 -use UpStream\Comments;
10 -
11 -if ( ! defined( 'ABSPATH' ) ) {
12 - exit;
13 -}
14 -
15 -if ( ! class_exists( 'UpStream' ) ) :
16 -
17 - /**
18 - * Main UpStream Class.
19 - *
20 - * @since 1.0.0
21 - */
22 - final class UpStream {
23 -
24 - /**
25 - * The one true UpStream
26 - *
27 - * @var UpStream
28 - * @since 1.0.0
29 - */
30 - protected static $instance = null;
31 -
32 - /**
33 - * Twig Environment
34 - *
35 - * @var Twig_Environment
36 - */
37 - protected $twig;
38 -
39 - /**
40 - * Container
41 - *
42 - * @var Container
43 - */
44 - protected $container;
45 -
46 - /**
47 - * Main UpStream Instance.
48 - */
49 - public static function instance() {
50 - if ( is_null( self::$instance ) ) {
51 - self::$instance = new self();
52 - }
53 -
54 - return self::$instance;
55 - }
56 -
57 - /**
58 - * Throw error on object clone.
59 - *
60 - * The whole idea of the singleton design pattern is that there is a single
61 - * object therefore, we don't want the object to be cloned.
62 - *
63 - * @since 1.0.0
64 - */
65 - public function __clone() {
66 - _doing_it_wrong( __FUNCTION__, 'You\'re not supposed to clone this class.', esc_html( UPSTREAM_VERSION ) );
67 - }
68 -
69 - /**
70 - * Disable unserializing of the class.
71 - *
72 - * @since 1.0.0
73 - */
74 - public function __wakeup() {
75 - _doing_it_wrong( __FUNCTION__, 'You\'re not supposed to unserialize this class.', esc_html( UPSTREAM_VERSION ) );
76 - }
77 -
78 - /**
79 - * Prevent the class instance being serialized.
80 - *
81 - * @since 1.10.2
82 - */
83 - public function __sleep() {
84 - _doing_it_wrong( __FUNCTION__, 'You\'re not supposed to serialize this class.', esc_html( UPSTREAM_VERSION ) );
85 - }
86 -
87 - /**
88 - * Class constructor.
89 - */
90 - public function __construct() {
91 - $this->define_constants();
92 - $this->includes();
93 - $this->container = Container::get_instance();
94 - $this->init_framework();
95 -
96 - if ( UpStream_Debug::is_enabled() ) {
97 - UpStream_Debug::init();
98 - }
99 -
100 - $this->init_hooks();
101 -
102 - do_action( 'upstream_loaded' );
103 - }
104 -
105 - /**
106 - * Hook into actions and filters.
107 - *
108 - * @since 1.0.0
109 - */
110 - private function init_hooks() {
111 - add_action( 'init', array( $this, 'init' ) );
112 - add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
113 - add_filter( 'plugin_action_links_upstream/upstream.php', array( $this, 'handle_action_links' ) );
114 - add_filter( 'http_request_host_is_external', array( 'UpStream', 'allow_external_update_host' ), 10, 3 );
115 - add_filter( 'quicktags_settings', 'upstream_tinymce_quicktags_settings' );
116 - add_filter( 'tiny_mce_before_init', 'upstream_tinymce_before_init_setup_toolbar' );
117 - add_filter( 'tiny_mce_before_init', 'upstream_tinymce_before_init' );
118 - add_filter( 'teeny_mce_before_init', 'upstream_tinymce_before_init_setup_toolbar' );
119 - add_filter( 'comments_clauses', array( $this, 'filter_comments_on_dashboard' ), 10, 2 );
120 - add_filter( 'views_dashboard', array( 'UpStream_Admin', 'comment_status_links' ), 10, 1 );
121 - add_action( 'plugins_loaded', array( $this, 'load_plugin_textdomain' ) );
122 -
123 - if ( is_admin() ) {
124 - add_action( 'admin_init', array( $this->container['reviews'], 'init' ) );
125 - }
126 -
127 - global $pagenow;
128 -
129 - if ( 'plugins.php' === $pagenow ) {
130 - add_action(
131 - 'in_plugin_update_message-' . UPSTREAM_PLUGIN_BASENAME,
132 - array( $this, 'render_additional_update_info' ),
133 - 20,
134 - 2
135 - );
136 - }
137 - }
138 -
139 - /**
140 - * Initialize the Alledia Framework.
141 - */
142 - private function init_framework() {
143 - $this->container['framework']->init();
144 - }
145 -
146 -
147 - /**
148 - * Prevent a Client User from accessing any page other than the profile.
149 - *
150 - * @since 1.11.0
151 - *
152 - * @global $pagenow
153 - */
154 - public function limit_client_users_admin_access() {
155 - global $pagenow;
156 -
157 - $profile_age = 'profile.php';
158 - if ( $pagenow !== $profile_age && 'edit.php' !== $pagenow && ! wp_doing_ajax() ) {
159 - wp_safe_redirect( admin_url( $profile_age ) );
160 - exit();
161 - }
162 - }
163 -
164 - /**
165 - * Make sure Client Users can only see the Profile menu item.
166 - *
167 - * @since 1.11.0
168 - *
169 - * @global $menu
170 - */
171 - public function limit_client_users_menu() {
172 - global $menu;
173 -
174 - foreach ( $menu as $menu_index => $menu_data ) {
175 - $menu_file = isset( $menu_data[2] ) ? $menu_data[2] : null;
176 -
177 - if ( null !== $menu_file ) {
178 - if ( 'profile.php' === $menu_file || 'edit.php?post_type=project' === $menu_file ) {
179 - continue;
180 - }
181 -
182 - remove_menu_page( $menu_file );
183 - }
184 - }
185 - }
186 -
187 - /**
188 - * Hide some toolbar items from Client Users.
189 - *
190 - * @param \WP_Admin_Bar $wp_admin_bar WordPress admin bar.
191 - *
192 - * @since 1.11.0
193 - */
194 - public function limit_client_users_toolbar_items( $wp_admin_bar ) {
195 - $user = wp_get_current_user();
196 - $user_roles = (array) $user->roles;
197 -
198 - if ( count( array_intersect( $user_roles, array( 'administrator', 'upstream_manager' ) ) ) === 0
199 - && in_array( 'upstream_client_user', $user_roles, true )
200 - ) {
201 - $menu_items = array( 'about', 'comments', 'new-content' );
202 -
203 - if ( ! is_admin() ) {
204 - $menu_items = array_merge( $menu_items, array( 'dashboard', 'edit' ) );
205 - }
206 -
207 - foreach ( $menu_items as $menu_item ) {
208 - $wp_admin_bar->remove_menu( $menu_item );
209 - }
210 - }
211 - }
212 -
213 - /**
214 - * Get container.
215 - *
216 - * @return Container
217 - */
218 - public function get_container() {
219 - return $this->container;
220 - }
221 -
222 - /**
223 - * Define Constants.
224 - *
225 - * @since 1.0.0
226 - */
227 - private function define_constants() {
228 - $upload_dir = wp_upload_dir();
229 -
230 - $this->define( 'UPSTREAM_PLUGIN_DIR', plugin_dir_path( UPSTREAM_PLUGIN_FILE ) );
231 - $this->define( 'UPSTREAM_PLUGIN_URL', plugin_dir_url( UPSTREAM_PLUGIN_FILE ) );
232 - $this->define( 'UPSTREAM_PLUGIN_BASENAME', plugin_basename( UPSTREAM_PLUGIN_FILE ) );
233 - $this->define( 'UPSTREAM_PLUGIN_RELATIVE_PATH', 'upstream' );
234 -
235 - include_once __DIR__ . '/includes.php';
236 - }
237 -
238 - /**
239 - * Define constant if not already set.
240 - *
241 - * @param string $name Definition name.
242 - * @param string|bool $value Definition value.
243 - *
244 - * @since 1.0.0
245 - */
246 - private function define( $name, $value ) {
247 - if ( ! defined( $name ) ) {
248 - define( $name, $value );
249 - }
250 - }
251 -
252 - /**
253 - * What type of request is this?
254 - * string $type frontend or admin.
255 - *
256 - * @param string $type Request type.
257 - * @return bool
258 - * @since 1.0.0
259 - */
260 - private function is_request( $type ) {
261 - switch ( $type ) {
262 - case 'admin':
263 - return is_admin();
264 - case 'frontend':
265 - return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' );
266 - }
267 - }
268 -
269 - /**
270 - * Include required core files used in admin and on the frontend.
271 - *
272 - * @since 1.0.0
273 - */
274 - public function includes() {
275 - if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {
276 - require_once __DIR__ . '/vendor/autoload.php';
277 - }
278 -
279 - include_once __DIR__ . '/includes/class-exception.php';
280 - include_once __DIR__ . '/includes/trait-up-singleton.php';
281 - include_once __DIR__ . '/includes/trait-up-post-metadata.php';
282 - include_once __DIR__ . '/includes/class-struct.php';
283 - include_once __DIR__ . '/includes/class-upstream-debug.php';
284 - include_once __DIR__ . '/includes/class-container.php';
285 - include_once __DIR__ . '/includes/up-install.php';
286 - include_once __DIR__ . '/includes/class-upstream-autoloader.php';
287 - include_once __DIR__ . '/includes/class-upstream-roles.php';
288 - include_once __DIR__ . '/includes/class-upstream-counts.php';
289 - include_once __DIR__ . '/includes/class-upstream-counter.php';
290 - include_once __DIR__ . '/includes/class-upstream-project-activity.php';
291 - include_once __DIR__ . '/includes/up-permalinks.php';
292 - include_once __DIR__ . '/includes/up-general-functions.php';
293 - include_once __DIR__ . '/includes/up-post-types.php';
294 - include_once __DIR__ . '/includes/up-labels.php';
295 - include_once __DIR__ . '/includes/class-milestones.php';
296 - include_once __DIR__ . '/includes/class-milestone.php';
297 - include_once __DIR__ . '/includes/class-factory.php';
298 - include_once __DIR__ . '/includes/up-install.php';
299 - include_once __DIR__ . '/includes/up-filesystem.php';
300 - include_once __DIR__ . '/includes/up-register-nonce-fields.php';
301 - include_once __DIR__ . '/includes/up-wcs-helper.php';
302 - include_once __DIR__ . '/includes/class-license-checker.php';
303 - include_once __DIR__ . '/includes/up-cron-license-checker.php';
304 -
305 - $request = wp_unslash( $_REQUEST );
306 -
307 - if ( $this->is_request( 'admin' ) ) {
308 - global $pagenow;
309 -
310 - $is_multisite = (bool) is_multisite();
311 - $load_cmb2 = false;
312 - $server = wp_unslash( $_SERVER );
313 -
314 - if ( $is_multisite ) {
315 - $current_page = isset( $_SERVER['PHP_SELF'] ) ? preg_replace(
316 - '/^\/wp-admin\//i',
317 - '',
318 - sanitize_text_field( $server['PHP_SELF'] )
319 - ) : '';
320 - } else {
321 - $current_page = (string) $pagenow;
322 - }
323 -
324 - if ( in_array( $current_page, array( 'post.php', 'post-new.php' ), true ) ) {
325 - $post_type = isset( $request['post_type'] ) ? sanitize_text_field( $request['post_type'] ) : null;
326 -
327 - if ( empty( $post_type ) ) {
328 - $project_id = isset( $request['post'] ) ? absint( $request['post'] ) : 0;
329 - $post_type = get_post_type( $project_id );
330 - }
331 -
332 - if ( ! empty( $post_type ) ) {
333 - $post_types_using_cmb2 = apply_filters( 'upstream:post_types_using_cmb2', array( 'project', 'client' ) );
334 - $load_cmb2 = in_array( $post_type, $post_types_using_cmb2, true );
335 - }
336 - } elseif (
337 - 'admin.php' === $current_page
338 - && isset( $request['page'] )
339 - && preg_match( '/^upstream_/i', sanitize_text_field( $request['page'] ) )
340 - ) {
341 - $load_cmb2 = true;
342 - }
343 -
344 - if ( $load_cmb2 ) {
345 - include_once __DIR__ . '/includes/libraries/cmb2/init.php';
346 - include_once __DIR__ . '/includes/libraries/cmb2-grid/Cmb2GridPlugin.php';
347 - }
348 -
349 - include_once __DIR__ . '/includes/admin/class-upstream-admin.php';
350 - include_once __DIR__ . '/includes/admin/class-upstream-admin-tasks-page.php';
351 - include_once __DIR__ . '/includes/admin/class-upstream-admin-bugs-page.php';
352 - include_once __DIR__ . '/includes/admin/class-upstream-admin-reviews.php';
353 - }
354 -
355 - if ( $this->is_request( 'frontend' ) ) {
356 - include_once __DIR__ . '/includes/frontend/class-upstream-template-loader.php';
357 - include_once __DIR__ . '/includes/frontend/class-upstream-login.php';
358 - include_once __DIR__ . '/includes/frontend/class-upstream-style-output.php';
359 - include_once __DIR__ . '/includes/frontend/up-enqueues.php';
360 - include_once __DIR__ . '/includes/frontend/up-template-functions.php';
361 - include_once __DIR__ . '/includes/frontend/up-table-functions.php';
362 - include_once __DIR__ . '/includes/frontend/class-upstream-view.php';
363 - include_once __DIR__ . '/includes/frontend/class-upstream-ajax.php';
364 - }
365 -
366 - include_once __DIR__ . '/includes/up-project-functions.php';
367 - include_once __DIR__ . '/includes/up-client-functions.php';
368 - include_once __DIR__ . '/includes/up-permissions-functions.php';
369 - include_once __DIR__ . '/includes/class-comments-migration.php';
370 - include_once __DIR__ . '/includes/class-comments.php';
371 - include_once __DIR__ . '/includes/class-comment.php';
372 - }
373 -
374 - /**
375 - * Init UpStream when WordPress Initialises.
376 - */
377 - public function init() {
378 - UpStream\Milestones::instantiate();
379 -
380 - do_action( 'before_upstream_init' );
381 -
382 - $this->project = new UpStream_Project();
383 - $this->project_activity = new UpStream_Project_Activity();
384 -
385 - if ( version_compare( PHP_VERSION, '5.5', '<' ) ) {
386 - require_once UPSTREAM_PLUGIN_DIR . 'includes/libraries/password_compat-1.0.4/lib/password.php';
387 - }
388 -
389 - \UpStream\Migrations\Comments_Migration::run();
390 -
391 - $user = wp_get_current_user();
392 - $user_roles = (array) $user->roles;
393 -
394 - if (
395 - count( array_intersect( $user_roles, array( 'administrator', 'upstream_manager' ) ) ) === 0
396 - && in_array( 'upstream_client_user', $user_roles, true )
397 - ) {
398 - add_filter( 'admin_init', array( $this, 'limit_client_users_admin_access' ) );
399 - add_filter( 'admin_head', array( $this, 'limit_client_users_menu' ) );
400 - add_action( 'admin_bar_menu', array( $this, 'limit_client_users_toolbar_items' ), 999 );
401 - }
402 -
403 - $edit_other_projects_permission_were_removed = (bool) get_option( 'upstream:role_upstream_users:drop_edit_others_projects' );
404 -
405 - if ( ! $edit_other_projects_permission_were_removed ) {
406 - $role = get_role( 'upstream_user' );
407 -
408 - if ( $role ) {
409 - $role->remove_cap( 'edit_others_projects' );
410 - }
411 -
412 - unset( $role );
413 - update_option( 'upstream:role_upstream_users:drop_edit_others_projects', 1 );
414 - }
415 -
416 - UpStream_Options_Projects::create_projects_statuses_ids();
417 - UpStream_Options_Tasks::create_tasks_statuses_ids();
418 - UpStream_Options_Bugs::create_bugs_statuses_ids();
419 -
420 - Comments::instantiate();
421 -
422 - if ( $this->is_request( 'frontend' ) ) {
423 - UpStream_Ajax::instantiate();
424 - }
425 -
426 - do_action( 'upstream_init' );
427 - }
428 -
429 - /**
430 - * Load Localisation files.
431 - */
432 - public function load_plugin_textdomain() {
433 - load_plugin_textdomain( 'upstream', false, UPSTREAM_PLUGIN_RELATIVE_PATH . '/languages/' );
434 - }
435 -
436 -
437 - /**
438 - * Show row meta on the plugin screen.
439 - *
440 - * @param mixed $links Plugin Row Meta.
441 - * @param mixed $file Plugin Base file.
442 - *
443 - * @return array
444 - */
445 - public function plugin_row_meta( $links, $file ) {
446 - if ( UPSTREAM_PLUGIN_BASENAME === $file ) {
447 - $row_meta = array(
448 - 'docs' => sprintf(
449 - '<a href="%s" title="%s">%s</a>',
450 - esc_url( 'http://upstreamplugin.com/documentation' ),
451 - esc_attr__( 'View Documentation', 'upstream' ),
452 - esc_html__( 'Docs', 'upstream' )
453 - ),
454 - 'quick-start' => sprintf(
455 - '<a href="%s" title="%s">%s</a>',
456 - esc_url( 'http://upstreamplugin.com/quick-start-guide' ),
457 - esc_attr__( 'View Quick Start Guide', 'upstream' ),
458 - esc_html__( 'Quick Start Guide', 'upstream' )
459 - ),
460 - );
461 -
462 - return array_merge( $links, $row_meta );
463 - }
464 -
465 - return (array) $links;
466 - }
467 -
468 - /**
469 - * Callback called to setup the links to display on the plugins page, besides active/deactivate links.
470 - *
471 - * @param array $links The list of links to be displayed.
472 - *
473 - * @return array
474 - * @since 1.11.1
475 - * @static
476 - */
477 - public static function handle_action_links( $links ) {
478 - $links['settings'] = sprintf(
479 - '<a href="%s" title="%2$s" aria-label="%2$s">%3$s</a>',
480 - esc_url( admin_url( 'admin.php?page=upstream_general' ) ),
481 - esc_attr__( 'Open Settings Page', 'upstream' ),
482 - esc_html__( 'Settings', 'upstream' )
483 - );
484 -
485 - return $links;
486 - }
487 -
488 - /**
489 - * Ensures the plugins update API's host is whitelisted to WordPress external requests.
490 - *
491 - * @param boolean $is_allowed Is allowed or not.
492 - * @param string $host Host.
493 - * @param string $url Url.
494 - *
495 - * @return boolean
496 - * @since 1.11.1
497 - * @static
498 - */
499 - public static function allow_external_update_host( $is_allowed, $host, $url ) {
500 - if ( 'upstreamplugin.com' === $host ) {
501 - return true;
502 - }
503 -
504 - return $is_allowed;
505 - }
506 -
507 - /**
508 - * Render additional update info if needed.
509 - *
510 - * @param array $plugin_data Plugin metadata.
511 - * @param object $response Metadata about the available plugin update.
512 - *
513 - * @since 1.12.5
514 - * @static
515 - *
516 - * @see https://developer.wordpress.org/reference/hooks/in_plugin_update_message-file
517 - */
518 - public static function render_additional_update_info( $plugin_data, $response ) {
519 - $update_notice_title_html = sprintf(
520 - '<strong style="font-size: 1.25em; display: block; margin-top: 10px;">%s</strong>',
521 - esc_html__( 'Update notice:', 'upstream' )
522 - );
523 -
524 - if ( version_compare( UPSTREAM_VERSION, '1.12.5', '<' ) ) {
525 - printf(
526 - esc_html( $update_notice_title_html ) .
527 - // translators: '%1$s: plugin version, %2$s: capability name, %3$s: UpStream User role'.
528 - esc_html__(
529 - 'Starting from <strong>%1$s</strong> <code>%2$s</code> capability was removed from <code>%3$s</code> users role.',
530 - 'upstream'
531 - ),
532 - 'v1.12.5',
533 - 'edit_others_projects',
534 - esc_html__( 'UpStream User', 'upstream' )
535 - );
536 - }
537 - }
538 -
539 - /**
540 - * Make sure Recent Comments section on admin Dashboard display only comments
541 - * current user is allowed to see from projects he's allowed to access.
542 - *
543 - * @param array $query_args Query clauses.
544 - * @param WP_Comment_Query $query Current query instance.
545 - *
546 - * @return array $queryArgs
547 - * @global $pagenow, $wpdb
548 - *
549 - * @since 1.13.0
550 - * @static
551 - */
552 - public static function filter_comments_on_dashboard( $query_args, $query ) {
553 - global $pagenow;
554 -
555 - if ( is_admin() && 'index.php' === $pagenow && ! upstream_is_user_either_manager_or_admin() ) {
556 - global $wpdb;
557 -
558 - $query_args['join'] = 'LEFT JOIN ' . $wpdb->prefix . 'posts AS post ON post.ID = ' . $wpdb->prefix . 'comments.comment_post_ID';
559 - $user = wp_get_current_user();
560 -
561 - if ( in_array( 'upstream_user', $user->roles, true ) || in_array( 'upstream_client_user', $user->roles, true ) ) {
562 - $projects = (array) upstream_get_users_projects( $user );
563 -
564 - if ( count( $projects ) === 0 ) {
565 - $query_args['where'] = '(post.ID = -1)';
566 - } else {
567 - $query_args['where'] = "(post.post_type = 'project' AND post.ID IN (" . implode( ', ', array_keys( $projects ) ) . '))';
568 - $user_can_moderate_comments = user_can( $user, 'moderate_comments' );
569 -
570 - if ( ! $user_can_moderate_comments ) {
571 - $query_args['where'] .= " AND ( comment_approved = '1' )";
572 - } else {
573 - $query_args['where'] .= " AND ( comment_approved = '1' OR comment_approved = '0' )";
574 - }
575 - }
576 - } else {
577 - $query_args['where'] .= " AND (post.post_type != 'project')";
578 - }
579 - }
580 -
581 - return $query_args;
582 - }
583 - }
584 -endif;
585 -
586 -
587 -/**
588 - * Main instance of UpStream.
589 - *
590 - * Returns the main instance of UpStream to prevent the need to use globals.
591 - *
592 - * @return UpStream
593 - * @since 1.0.0
594 - */
595 -function upstream() {
596 - return UpStream::instance();
597 -}
598 -
599 -upstream();
600 -do_action( 'upstream_run' );
1 +<?php
2 +/**
3 + * Main UpStream Class.
4 + *
5 + * @package UpStream
6 + */
7 +
8 +use UpStream\Comments;
9 +
10 +if ( ! defined( 'ABSPATH' ) ) {
11 + exit;
12 +}
13 +
14 +if ( ! class_exists( 'UpStream' ) ) :
15 +
16 + /**
17 + * Main UpStream Class.
18 + *
19 + * @since 1.0.0
20 + */
21 + final class UpStream {
22 +
23 + /**
24 + * The one true UpStream
25 + *
26 + * @var UpStream
27 + * @since 1.0.0
28 + */
29 + protected static $instance = null;
30 +
31 + /**
32 + * Twig Environment
33 + *
34 + * @var Twig_Environment
35 + */
36 + protected $twig;
37 +
38 + /**
39 + * Container
40 + *
41 + * @var Container
42 + */
43 + protected $container;
44 +
45 + /**
46 + * Main UpStream Instance.
47 + */
48 + public static function instance() {
49 + if ( is_null( self::$instance ) ) {
50 + self::$instance = new self();
51 + }
52 +
53 + return self::$instance;
54 + }
55 +
56 + /**
57 + * Throw error on object clone.
58 + *
59 + * The whole idea of the singleton design pattern is that there is a single
60 + * object therefore, we don't want the object to be cloned.
61 + *
62 + * @since 1.0.0
63 + */
64 + public function __clone() {
65 + _doing_it_wrong( __FUNCTION__, 'You\'re not supposed to clone this class.', esc_html( UPSTREAM_VERSION ) );
66 + }
67 +
68 + /**
69 + * Disable unserializing of the class.
70 + *
71 + * @since 1.0.0
72 + */
73 + public function __wakeup() {
74 + _doing_it_wrong( __FUNCTION__, 'You\'re not supposed to unserialize this class.', esc_html( UPSTREAM_VERSION ) );
75 + }
76 +
77 + /**
78 + * Prevent the class instance being serialized.
79 + *
80 + * @since 1.10.2
81 + */
82 + public function __sleep() {
83 + _doing_it_wrong( __FUNCTION__, 'You\'re not supposed to serialize this class.', esc_html( UPSTREAM_VERSION ) );
84 + }
85 +
86 + /**
87 + * Class constructor.
88 + */
89 + public function __construct() {
90 + $this->define_constants();
91 + $this->includes();
92 + $this->container = Container::get_instance();
93 + $this->init_framework();
94 +
95 + if ( UpStream_Debug::is_enabled() ) {
96 + UpStream_Debug::init();
97 + }
98 +
99 + $this->init_hooks();
100 +
101 + do_action( 'upstream_loaded' );
102 + }
103 +
104 + /**
105 + * Hook into actions and filters.
106 + *
107 + * @since 1.0.0
108 + */
109 + private function init_hooks() {
110 + add_action( 'init', array( $this, 'init' ) );
111 + add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
112 + add_filter( 'plugin_action_links_upstream/upstream.php', array( $this, 'handle_action_links' ) );
113 + add_filter( 'http_request_host_is_external', array( 'UpStream', 'allow_external_update_host' ), 10, 3 );
114 + add_filter( 'quicktags_settings', 'upstream_tinymce_quicktags_settings' );
115 + add_filter( 'tiny_mce_before_init', 'upstream_tinymce_before_init_setup_toolbar' );
116 + add_filter( 'tiny_mce_before_init', 'upstream_tinymce_before_init' );
117 + add_filter( 'teeny_mce_before_init', 'upstream_tinymce_before_init_setup_toolbar' );
118 + add_filter( 'comments_clauses', array( $this, 'filter_comments_on_dashboard' ), 10, 2 );
119 + add_filter( 'views_dashboard', array( 'UpStream_Admin', 'comment_status_links' ), 10, 1 );
120 + add_action( 'plugins_loaded', array( $this, 'load_plugin_textdomain' ) );
121 +
122 + if ( is_admin() ) {
123 + add_action( 'admin_init', array( $this->container['reviews'], 'init' ) );
124 + }
125 +
126 + global $pagenow;
127 +
128 + if ( 'plugins.php' === $pagenow ) {
129 + add_action(
130 + 'in_plugin_update_message-' . UPSTREAM_PLUGIN_BASENAME,
131 + array( $this, 'render_additional_update_info' ),
132 + 20,
133 + 2
134 + );
135 + }
136 + }
137 +
138 + /**
139 + * Initialize the Alledia Framework.
140 + */
141 + private function init_framework() {
142 + $this->container['framework']->init();
143 + }
144 +
145 +
146 + /**
147 + * Prevent a Client User from accessing any page other than the profile.
148 + *
149 + * @since 1.11.0
150 + *
151 + * @global $pagenow
152 + */
153 + public function limit_client_users_admin_access() {
154 + global $pagenow;
155 +
156 + $profile_age = 'profile.php';
157 + if ( $pagenow !== $profile_age && 'edit.php' !== $pagenow && ! wp_doing_ajax() ) {
158 + wp_safe_redirect( admin_url( $profile_age ) );
159 + exit();
160 + }
161 + }
162 +
163 + /**
164 + * Make sure Client Users can only see the Profile menu item.
165 + *
166 + * @since 1.11.0
167 + *
168 + * @global $menu
169 + */
170 + public function limit_client_users_menu() {
171 + global $menu;
172 +
173 + foreach ( $menu as $menu_index => $menu_data ) {
174 + $menu_file = isset( $menu_data[2] ) ? $menu_data[2] : null;
175 +
176 + if ( null !== $menu_file ) {
177 + if ( 'profile.php' === $menu_file || 'edit.php?post_type=project' === $menu_file ) {
178 + continue;
179 + }
180 +
181 + remove_menu_page( $menu_file );
182 + }
183 + }
184 + }
185 +
186 + /**
187 + * Hide some toolbar items from Client Users.
188 + *
189 + * @param \WP_Admin_Bar $wp_admin_bar WordPress admin bar.
190 + *
191 + * @since 1.11.0
192 + */
193 + public function limit_client_users_toolbar_items( $wp_admin_bar ) {
194 + $user = wp_get_current_user();
195 + $user_roles = (array) $user->roles;
196 +
197 + if ( count( array_intersect( $user_roles, array( 'administrator', 'upstream_manager' ) ) ) === 0
198 + && in_array( 'upstream_client_user', $user_roles, true )
199 + ) {
200 + $menu_items = array( 'about', 'comments', 'new-content' );
201 +
202 + if ( ! is_admin() ) {
203 + $menu_items = array_merge( $menu_items, array( 'dashboard', 'edit' ) );
204 + }
205 +
206 + foreach ( $menu_items as $menu_item ) {
207 + $wp_admin_bar->remove_menu( $menu_item );
208 + }
209 + }
210 + }
211 +
212 + /**
213 + * Get container.
214 + *
215 + * @return Container
216 + */
217 + public function get_container() {
218 + return $this->container;
219 + }
220 +
221 + /**
222 + * Define Constants.
223 + *
224 + * @since 1.0.0
225 + */
226 + private function define_constants() {
227 + $upload_dir = wp_upload_dir();
228 +
229 + $this->define( 'UPSTREAM_PLUGIN_DIR', plugin_dir_path( UPSTREAM_PLUGIN_FILE ) );
230 + $this->define( 'UPSTREAM_PLUGIN_URL', plugin_dir_url( UPSTREAM_PLUGIN_FILE ) );
231 + $this->define( 'UPSTREAM_PLUGIN_BASENAME', plugin_basename( UPSTREAM_PLUGIN_FILE ) );
232 + $this->define( 'UPSTREAM_PLUGIN_RELATIVE_PATH', 'upstream' );
233 +
234 + include_once __DIR__ . '/includes.php';
235 + }
236 +
237 + /**
238 + * Define constant if not already set.
239 + *
240 + * @param string $name Definition name.
241 + * @param string|bool $value Definition value.
242 + *
243 + * @since 1.0.0
244 + */
245 + private function define( $name, $value ) {
246 + if ( ! defined( $name ) ) {
247 + define( $name, $value );
248 + }
249 + }
250 +
251 + /**
252 + * What type of request is this?
253 + * string $type frontend or admin.
254 + *
255 + * @param string $type Request type.
256 + * @return bool
257 + * @since 1.0.0
258 + */
259 + private function is_request( $type ) {
260 + switch ( $type ) {
261 + case 'admin':
262 + return is_admin();
263 + case 'frontend':
264 + return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' );
265 + }
266 + }
267 +
268 + /**
269 + * Include required core files used in admin and on the frontend.
270 + *
271 + * @since 1.0.0
272 + */
273 + public function includes() {
274 + if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {
275 + require_once __DIR__ . '/vendor/autoload.php';
276 + }
277 +
278 + include_once __DIR__ . '/includes/class-exception.php';
279 + include_once __DIR__ . '/includes/trait-up-singleton.php';
280 + include_once __DIR__ . '/includes/trait-up-post-metadata.php';
281 + include_once __DIR__ . '/includes/class-struct.php';
282 + include_once __DIR__ . '/includes/class-upstream-debug.php';
283 + include_once __DIR__ . '/includes/class-container.php';
284 + include_once __DIR__ . '/includes/up-install.php';
285 + include_once __DIR__ . '/includes/class-upstream-autoloader.php';
286 + include_once __DIR__ . '/includes/class-upstream-roles.php';
287 + include_once __DIR__ . '/includes/class-upstream-counts.php';
288 + include_once __DIR__ . '/includes/class-upstream-counter.php';
289 + include_once __DIR__ . '/includes/class-upstream-project-activity.php';
290 + include_once __DIR__ . '/includes/up-permalinks.php';
291 + include_once __DIR__ . '/includes/up-general-functions.php';
292 + include_once __DIR__ . '/includes/up-post-types.php';
293 + include_once __DIR__ . '/includes/up-labels.php';
294 + include_once __DIR__ . '/includes/class-milestones.php';
295 + include_once __DIR__ . '/includes/class-milestone.php';
296 + include_once __DIR__ . '/includes/class-factory.php';
297 + include_once __DIR__ . '/includes/up-install.php';
298 + include_once __DIR__ . '/includes/up-filesystem.php';
299 + include_once __DIR__ . '/includes/up-register-nonce-fields.php';
300 + include_once __DIR__ . '/includes/up-wcs-helper.php';
301 +
302 + $request = wp_unslash( $_REQUEST );
303 +
304 + if ( $this->is_request( 'admin' ) ) {
305 + global $pagenow;
306 +
307 + $is_multisite = (bool) is_multisite();
308 + $load_cmb2 = false;
309 + $server = wp_unslash( $_SERVER );
310 +
311 + if ( $is_multisite ) {
312 + $current_page = isset( $_SERVER['PHP_SELF'] ) ? preg_replace(
313 + '/^\/wp-admin\//i',
314 + '',
315 + sanitize_text_field( $server['PHP_SELF'] )
316 + ) : '';
317 + } else {
318 + $current_page = (string) $pagenow;
319 + }
320 +
321 + if ( in_array( $current_page, array( 'post.php', 'post-new.php' ), true ) ) {
322 + $post_type = isset( $request['post_type'] ) ? sanitize_text_field( $request['post_type'] ) : null;
323 +
324 + if ( empty( $post_type ) ) {
325 + $project_id = isset( $request['post'] ) ? absint( $request['post'] ) : 0;
326 + $post_type = get_post_type( $project_id );
327 + }
328 +
329 + if ( ! empty( $post_type ) ) {
330 + $post_types_using_cmb2 = apply_filters( 'upstream:post_types_using_cmb2', array( 'project', 'client' ) );
331 + $load_cmb2 = in_array( $post_type, $post_types_using_cmb2, true );
332 + }
333 + } elseif (
334 + 'admin.php' === $current_page
335 + && isset( $request['page'] )
336 + && preg_match( '/^upstream_/i', sanitize_text_field( $request['page'] ) )
337 + ) {
338 + $load_cmb2 = true;
339 + }
340 +
341 + if ( $load_cmb2 ) {
342 + include_once __DIR__ . '/includes/libraries/cmb2/init.php';
343 + include_once __DIR__ . '/includes/libraries/cmb2-grid/Cmb2GridPlugin.php';
344 + }
345 +
346 + include_once __DIR__ . '/includes/admin/class-upstream-admin.php';
347 + include_once __DIR__ . '/includes/admin/class-upstream-admin-tasks-page.php';
348 + include_once __DIR__ . '/includes/admin/class-upstream-admin-bugs-page.php';
349 + include_once __DIR__ . '/includes/admin/class-upstream-admin-reviews.php';
350 + }
351 +
352 + if ( $this->is_request( 'frontend' ) ) {
353 + include_once __DIR__ . '/includes/frontend/class-upstream-template-loader.php';
354 + include_once __DIR__ . '/includes/frontend/class-upstream-login.php';
355 + include_once __DIR__ . '/includes/frontend/class-upstream-style-output.php';
356 + include_once __DIR__ . '/includes/frontend/up-enqueues.php';
357 + include_once __DIR__ . '/includes/frontend/up-template-functions.php';
358 + include_once __DIR__ . '/includes/frontend/up-table-functions.php';
359 + include_once __DIR__ . '/includes/frontend/class-upstream-view.php';
360 + include_once __DIR__ . '/includes/frontend/class-upstream-ajax.php';
361 + }
362 +
363 + include_once __DIR__ . '/includes/up-project-functions.php';
364 + include_once __DIR__ . '/includes/up-client-functions.php';
365 + include_once __DIR__ . '/includes/up-permissions-functions.php';
366 + include_once __DIR__ . '/includes/class-comments-migration.php';
367 + include_once __DIR__ . '/includes/class-comments.php';
368 + include_once __DIR__ . '/includes/class-comment.php';
369 + }
370 +
371 + /**
372 + * Init UpStream when WordPress Initialises.
373 + */
374 + public function init() {
375 + UpStream\Milestones::instantiate();
376 +
377 + do_action( 'before_upstream_init' );
378 +
379 + $this->project = new UpStream_Project();
380 + $this->project_activity = new UpStream_Project_Activity();
381 +
382 + if ( version_compare( PHP_VERSION, '5.5', '<' ) ) {
383 + require_once UPSTREAM_PLUGIN_DIR . 'includes/libraries/password_compat-1.0.4/lib/password.php';
384 + }
385 +
386 + \UpStream\Migrations\Comments_Migration::run();
387 +
388 + $user = wp_get_current_user();
389 + $user_roles = (array) $user->roles;
390 +
391 + if (
392 + count( array_intersect( $user_roles, array( 'administrator', 'upstream_manager' ) ) ) === 0
393 + && in_array( 'upstream_client_user', $user_roles, true )
394 + ) {
395 + add_filter( 'admin_init', array( $this, 'limit_client_users_admin_access' ) );
396 + add_filter( 'admin_head', array( $this, 'limit_client_users_menu' ) );
397 + add_action( 'admin_bar_menu', array( $this, 'limit_client_users_toolbar_items' ), 999 );
398 + }
399 +
400 + $edit_other_projects_permission_were_removed = (bool) get_option( 'upstream:role_upstream_users:drop_edit_others_projects' );
401 +
402 + if ( ! $edit_other_projects_permission_were_removed ) {
403 + $role = get_role( 'upstream_user' );
404 +
405 + if ( $role ) {
406 + $role->remove_cap( 'edit_others_projects' );
407 + }
408 +
409 + unset( $role );
410 + update_option( 'upstream:role_upstream_users:drop_edit_others_projects', 1 );
411 + }
412 +
413 + UpStream_Options_Projects::create_projects_statuses_ids();
414 + UpStream_Options_Tasks::create_tasks_statuses_ids();
415 + UpStream_Options_Bugs::create_bugs_statuses_ids();
416 +
417 + Comments::instantiate();
418 +
419 + if ( $this->is_request( 'frontend' ) ) {
420 + UpStream_Ajax::instantiate();
421 + }
422 +
423 + do_action( 'upstream_init' );
424 + }
425 +
426 + /**
427 + * Load Localisation files.
428 + */
429 + public function load_plugin_textdomain() {
430 + load_plugin_textdomain( 'upstream', false, UPSTREAM_PLUGIN_RELATIVE_PATH . '/languages/' );
431 + }
432 +
433 +
434 + /**
435 + * Show row meta on the plugin screen.
436 + *
437 + * @param mixed $links Plugin Row Meta.
438 + * @param mixed $file Plugin Base file.
439 + *
440 + * @return array
441 + */
442 + public function plugin_row_meta( $links, $file ) {
443 + if ( UPSTREAM_PLUGIN_BASENAME === $file ) {
444 + $row_meta = array(
445 + 'docs' => sprintf(
446 + '<a href="%s" title="%s">%s</a>',
447 + esc_url( 'http://upstreamplugin.com/documentation' ),
448 + esc_attr__( 'View Documentation', 'upstream' ),
449 + esc_html__( 'Docs', 'upstream' )
450 + ),
451 + 'quick-start' => sprintf(
452 + '<a href="%s" title="%s">%s</a>',
453 + esc_url( 'http://upstreamplugin.com/quick-start-guide' ),
454 + esc_attr__( 'View Quick Start Guide', 'upstream' ),
455 + esc_html__( 'Quick Start Guide', 'upstream' )
456 + ),
457 + );
458 +
459 + return array_merge( $links, $row_meta );
460 + }
461 +
462 + return (array) $links;
463 + }
464 +
465 + /**
466 + * Callback called to setup the links to display on the plugins page, besides active/deactivate links.
467 + *
468 + * @param array $links The list of links to be displayed.
469 + *
470 + * @return array
471 + * @since 1.11.1
472 + * @static
473 + */
474 + public static function handle_action_links( $links ) {
475 + $links['settings'] = sprintf(
476 + '<a href="%s" title="%2$s" aria-label="%2$s">%3$s</a>',
477 + esc_url( admin_url( 'admin.php?page=upstream_general' ) ),
478 + esc_attr__( 'Open Settings Page', 'upstream' ),
479 + esc_html__( 'Settings', 'upstream' )
480 + );
481 +
482 + return $links;
483 + }
484 +
485 + /**
486 + * Ensures the plugins update API's host is whitelisted to WordPress external requests.
487 + *
488 + * @param boolean $is_allowed Is allowed or not.
489 + * @param string $host Host.
490 + * @param string $url Url.
491 + *
492 + * @return boolean
493 + * @since 1.11.1
494 + * @static
495 + */
496 + public static function allow_external_update_host( $is_allowed, $host, $url ) {
497 + if ( 'upstreamplugin.com' === $host ) {
498 + return true;
499 + }
500 +
501 + return $is_allowed;
502 + }
503 +
504 + /**
505 + * Render additional update info if needed.
506 + *
507 + * @param array $plugin_data Plugin metadata.
508 + * @param object $response Metadata about the available plugin update.
509 + *
510 + * @since 1.12.5
511 + * @static
512 + *
513 + * @see https://developer.wordpress.org/reference/hooks/in_plugin_update_message-file
514 + */
515 + public static function render_additional_update_info( $plugin_data, $response ) {
516 + $update_notice_title_html = sprintf(
517 + '<strong style="font-size: 1.25em; display: block; margin-top: 10px;">%s</strong>',
518 + esc_html__( 'Update notice:', 'upstream' )
519 + );
520 +
521 + if ( version_compare( UPSTREAM_VERSION, '1.12.5', '<' ) ) {
522 + printf(
523 + esc_html( $update_notice_title_html ) .
524 + // translators: '%1$s: plugin version, %2$s: capability name, %3$s: UpStream User role'.
525 + esc_html__(
526 + 'Starting from <strong>%1$s</strong> <code>%2$s</code> capability was removed from <code>%3$s</code> users role.',
527 + 'upstream'
528 + ),
529 + 'v1.12.5',
530 + 'edit_others_projects',
531 + esc_html__( 'UpStream User', 'upstream' )
532 + );
533 + }
534 + }
535 +
536 + /**
537 + * Make sure Recent Comments section on admin Dashboard display only comments
538 + * current user is allowed to see from projects he's allowed to access.
539 + *
540 + * @param array $query_args Query clauses.
541 + * @param WP_Comment_Query $query Current query instance.
542 + *
543 + * @return array $queryArgs
544 + * @global $pagenow, $wpdb
545 + *
546 + * @since 1.13.0
547 + * @static
548 + */
549 + public static function filter_comments_on_dashboard( $query_args, $query ) {
550 + global $pagenow;
551 +
552 + if ( is_admin() && 'index.php' === $pagenow && ! upstream_is_user_either_manager_or_admin() ) {
553 + global $wpdb;
554 +
555 + $query_args['join'] = 'LEFT JOIN ' . $wpdb->prefix . 'posts AS post ON post.ID = ' . $wpdb->prefix . 'comments.comment_post_ID';
556 + $user = wp_get_current_user();
557 +
558 + if ( in_array( 'upstream_user', $user->roles, true ) || in_array( 'upstream_client_user', $user->roles, true ) ) {
559 + $projects = (array) upstream_get_users_projects( $user );
560 +
561 + if ( count( $projects ) === 0 ) {
562 + $query_args['where'] = '(post.ID = -1)';
563 + } else {
564 + $query_args['where'] = "(post.post_type = 'project' AND post.ID IN (" . implode( ', ', array_keys( $projects ) ) . '))';
565 + $user_can_moderate_comments = user_can( $user, 'moderate_comments' );
566 +
567 + if ( ! $user_can_moderate_comments ) {
568 + $query_args['where'] .= " AND ( comment_approved = '1' )";
569 + } else {
570 + $query_args['where'] .= " AND ( comment_approved = '1' OR comment_approved = '0' )";
571 + }
572 + }
573 + } else {
574 + $query_args['where'] .= " AND (post.post_type != 'project')";
575 + }
576 + }
577 +
578 + return $query_args;
579 + }
580 + }
581 +endif;
582 +
583 +
584 +/**
585 + * Main instance of UpStream.
586 + *
587 + * Returns the main instance of UpStream to prevent the need to use globals.
588 + *
589 + * @return UpStream
590 + * @since 1.0.0
591 + */
592 +function upstream() {
593 + return UpStream::instance();
594 +}
595 +
596 +upstream();
597 +do_action( 'upstream_run' );