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