PluginProbe
UpStream: a Project Management Plugin for WordPress / 1.39.1
UpStream: a Project Management Plugin for WordPress v1.39.1
trunk 1.39.0 1.39.1 1.39.2 1.39.3 2.0.7 2.1.0
upstream / includes / admin / class-up-admin-pointers.php

class-up-admin-pointers.php in UpStream: a Project Management Plugin for WordPress 1.39.1, at includes/admin/class-up-admin-pointers.php

448 lines 18.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Adds and controls pointers for contextual help/tutorials
4 *
5 */
6
7 if ( ! defined('ABSPATH')) {
8 exit;
9 }
10
11 /**
12 * UpStream_Admin_Pointers Class.
13 */
14 class UpStream_Admin_Pointers
15 {
16
17 /**
18 * Constructor.
19 */
20 public function __construct()
21 {
22 add_filter('admin_notices', [$this, 'first_project']);
23 add_filter('admin_notices', [$this, 'check_addons']);
24 add_filter('upstream_admin_pointers-project', [$this, 'register_pointers']);
25 add_filter('upstream_admin_pointers-edit-project', [$this, 'register_signup']);
26 add_action('admin_enqueue_scripts', [$this, 'enqueue_pointers']);
27 }
28
29 public function register_signup()
30 {
31
32 if (! current_user_can('administrator')) {
33 return;
34 }
35
36 global $current_user;
37
38 $content = '<p id="upstream-pointer-signup-box">';
39 $content .= __( 'Sign up for our UpStream Project Management tips and tricks newsletter and get the UpStream Customizer extension for free!', 'upstream' ) . '<br /><br />';
40 $content .= '<label>';
41 $content .= '<b>' . __( 'Email Address:', 'upstream' ) . '</b>';
42 $content .= '<br />';
43 $content .= '<input type="text" id="upstream-pointer-email" value="' . esc_attr( $current_user->user_email ) . '" />';
44 $content .= '</label>';
45 $content .= '&nbsp; <a id="upstream-pointer-b1" onclick="return window.upstream_signup(this);" data-nonce="'. wp_create_nonce('upstream_signup') .'" class="button button-primary">Sign up</a>';
46 $content .= '</p>';
47
48 $pointers = [
49 'signup-newsletter-email3' => [
50 'target' => ".wp-heading-inline",
51 'options' => [
52 'content' => '<h3>' . __('Get a FREE UpStream extension!') . '</h3>' . $content,
53 'position' => [
54 'edge' => 'top',
55 'align' => 'top',
56 ],
57 ],
58 ],
59
60 ];
61
62 return $pointers;
63 }
64
65 public function first_project()
66 {
67 // Make sure First Steps tutorial are not shown to Client Users first time they enter a project.
68 $user = wp_get_current_user();
69 if (count(array_intersect((array)$user->roles, ['administrator', 'upstream_manager'])) === 0 &&
70 ! current_user_can('edit_projects')
71 ) {
72 return;
73 }
74
75 // Get dismissed pointers. Shows whether we have done this or not already.
76 $dismissed = explode(',', (string)get_user_meta($user->ID, 'dismissed_wp_pointers', true));
77 if (in_array('upstream_title', $dismissed)) {
78 return;
79 }
80
81 $screen = get_current_screen();
82 if (isset($screen->id) && $screen->id == 'project') {
83 $class = 'notice notice-success is-dismissible';
84 $message = '<strong>' . __('Important!', 'upstream') . '</strong><br>';
85 $message .= __(
86 'As this is your first project, we have included a walkthrough guide.',
87 'upstream'
88 ) . '<br>';
89 $message .= __(
90 'We <strong>strongly recommend</strong> that you take the time to follow it. ',
91 'upstream'
92 );
93 $message .= __(
94 'There is important info in the guide and it does not take too long.',
95 'upstream'
96 ) . '<br>';
97 $message .= '<small>' . __('(you won\'t see this message or the guide again)', 'upstream') . '</small>';
98
99 printf('<div class="%1$s"><p>%2$s</p></div>', $class, $message);
100 }
101 }
102
103
104 public function check_addons()
105 {
106 $user = wp_get_current_user();
107 if (!is_admin() || !current_user_can('activate_plugins')) {
108 return;
109 }
110
111 // only check if it is set
112 if (isset($_GET['upstream_dismiss_ver'])) {
113 update_user_meta(get_current_user_id(), 'upstream_hide_incompat_notices_' . UPSTREAM_VERSION, 'yes');
114 }
115
116 if (get_user_meta(get_current_user_id(), 'upstream_hide_incompat_notices_' . UPSTREAM_VERSION, true) === 'yes') {
117 return;
118 }
119
120 $addon_problems = [];
121 global $upstream_addon_requirements;
122 $required_addon_versions = $upstream_addon_requirements;
123
124 foreach ($required_addon_versions as $r) {
125
126 $pd = null;
127 if (@is_plugin_active($r[0])) {
128 $pd = @get_plugin_data(WP_PLUGIN_DIR . '/' . $r[0]);
129 } elseif (@is_plugin_active(strtolower($r[0]))) {
130 $pd = @get_plugin_data(WP_PLUGIN_DIR . '/' . strtolower($r[0]));
131 }
132
133 if ($pd) {
134
135 $current_version = $pd['Version'];
136 $reqd_version = $r[1];
137
138 if (version_compare($current_version, $reqd_version) < 0) {
139 $addon_problems[] = __('- The installed version of ', 'upstream') .
140 '<b style="font-weight: bold">' . $pd['Name'] . '</b>' . __(' is ', 'upstream') . '<b style="font-weight: bold">' . $current_version . '</b>' .
141 __('. This version of UpStream requires version ', 'upstream') .
142 '<b style="font-weight: bold">'. $reqd_version . '</b>' . __(' or later.', 'upstream');
143 }
144 }
145
146 }
147
148
149 if (count($addon_problems) > 0) {
150 $class = 'notice';
151 $message = '<strong style="font-weight:bold;font-size:2em;color:#f00">' . __('Important!', 'upstream') . '</strong><br>';
152 $message .= __(
153 'This version of UpStream is not compatible with the following addon versions:',
154 'upstream'
155 ) . '<br><br>';
156 $message .= implode('<br>', $addon_problems);
157 $message .= '<br><br>For help with this message, <a href="https://upstreamplugin.com/docs/updating-upstream-addons/">click here</a>.';
158 $message .= '<br><br><a href="?upstream_dismiss_ver=1">' . __('Do not show this message again for this version', 'upstream') . '</a>';
159
160 printf('<div class="%1$s"><p>%2$s</p></div>', $class, $message);
161 }
162 }
163
164
165
166
167 /**
168 * Pointers for creating a Project.
169 */
170 public function register_pointers($pointers)
171 {
172
173 // These pointers will chain - they will not be shown at once.
174 $pointers = [
175 'upstream_title' => [
176 'target' => "#title",
177 'next' => 'upstream_status',
178 'next_trigger' => [
179 'target' => '#title',
180 'event' => 'input',
181 ],
182 'options' => [
183 'content' => '<h3>' . sprintf(__('%s Name', 'upstream'), upstream_project_label()) . '</h3>' .
184 '<p>' . sprintf(__(
185 'This is a required field and will be what your %s see on the frontend.',
186 'upstream'
187 ), upstream_client_label()) . '</p>',
188 'position' => [
189 'edge' => 'top',
190 'align' => 'left',
191 ],
192 ],
193 ],
194 'upstream_status' => [
195 'target' => "#_upstream_project_status",
196 'next' => 'upstream_owner',
197 'next_trigger' => [
198 'target' => "#_upstream_project_status",
199 'event' => 'change blur click',
200 ],
201 'options' => [
202 'content' => '<h3>' . sprintf(
203 __('%s Status', 'upstream'),
204 upstream_project_label()
205 ) . '</h3>' .
206 '<p>' . sprintf(
207 __('Choose a status for this %s.', 'upstream'),
208 upstream_project_label()
209 ) . '</p>' .
210 '<p>' . sprintf(
211 __('Statuses are set within the UpStream Settings.', 'upstream'),
212 upstream_project_label()
213 ) . '</p>',
214 'position' => [
215 'edge' => 'right',
216 'align' => 'left',
217 ],
218 ],
219 ],
220 'upstream_owner' => [
221 'target' => "#_upstream_project_owner",
222 'next' => 'upstream_client',
223 'next_trigger' => [
224 'target' => "#_upstream_project_owner",
225 'event' => 'change blur click',
226 ],
227 'options' => [
228 'content' => '<h3>' . sprintf(__('%s Owner', 'upstream'), upstream_project_label()) . '</h3>' .
229 '<p>' . sprintf(
230 __('Choose the owner of this %s.', 'upstream'),
231 upstream_project_label()
232 ) . '</p>' .
233 '<p>' . __(
234 'Every user who has the Role of UpStream Manager, UpStream User or Administrator appears in this dropdown.',
235 'upstream'
236 ) . '</p>' .
237 '<p>' . sprintf(__(
238 'The selected owner will have full access and control of everything within this %s, regardless of their role.',
239 'upstream'
240 ), upstream_project_label()) . '</p>',
241 'position' => [
242 'edge' => 'right',
243 'align' => 'left',
244 ],
245 ],
246 ],
247 'upstream_client' => [
248 'target' => "#_upstream_project_client",
249 'next' => 'upstream_client_users',
250 'next_trigger' => [
251 'target' => "#_upstream_project_client",
252 'event' => 'change blur click',
253 ],
254 'options' => [
255 'content' => '<h3>' . sprintf(
256 '%s %s',
257 upstream_project_label(),
258 upstream_client_label()
259 ) . '</h3>' .
260 '<p>' . sprintf(
261 __('Choose the %s of this %s.', 'upstream'),
262 upstream_client_label(),
263 upstream_project_label()
264 ) . '</p>' .
265 '<p>' . sprintf(__(
266 'If there are no %s here, you need to add one first by clicking on <strong>New Client</strong> in the sidebar.',
267 'upstream'
268 ), upstream_client_label_plural()) . '</p>',
269 'position' => [
270 'edge' => 'right',
271 'align' => 'left',
272 ],
273 ],
274 ],
275 'upstream_client_users' => [
276 'target' => ".cmb2-id--upstream-project-client-users",
277 'next' => 'upstream_project_start',
278 'next_trigger' => [
279 'target' => ".cmb2-id--upstream-project-client-users",
280 'event' => 'change blur click',
281 ],
282 'options' => [
283 'content' => '<h3>' . sprintf(__('%s Users', 'upstream'), upstream_client_label()) . '</h3>' .
284 '<p>' . sprintf(__(
285 'Tick the %s Users who will have access to this %s.',
286 'upstream'
287 ), upstream_client_label(), upstream_project_label()) . '</p>' .
288 '<p>' . sprintf(__(
289 'The selected Users can then login using their email address and the password that is set within the %s.',
290 'upstream'
291 ), upstream_client_label()) . '</p>' .
292 '<p>' . sprintf(__(
293 'If there are no %s Users here, you need to add one first by editing your %s',
294 'upstream'
295 ), upstream_client_label_plural(), upstream_client_label()) . '</p>',
296 'position' => [
297 'edge' => 'right',
298 'align' => 'left',
299 ],
300 ],
301 ],
302 'upstream_project_start' => [
303 'target' => "#_upstream_project_start",
304 'next' => 'upstream_milestones',
305 'next_trigger' => [
306 'target' => "#_upstream_project_end",
307 'event' => 'change blur click',
308 ],
309 'options' => [
310 'content' => '<h3>' . sprintf(__('%s Dates', 'upstream'), upstream_project_label()) . '</h3>' .
311 '<p>' . sprintf(__(
312 'Add the projected start and finish dates for this %s.',
313 'upstream'
314 ), upstream_project_label()) . '</p>',
315 'position' => [
316 'edge' => 'right',
317 'align' => 'left',
318 ],
319 ],
320 ],
321 'upstream_milestones' => [
322 'target' => "#_upstream_project_milestones",
323 'options' => [
324 'content' => '<h3>' . sprintf('%s', upstream_milestone_label_plural()) . '</h3>' .
325 '<p>' . sprintf(
326 __('You can now start to add your %s.', 'upstream'),
327 upstream_milestone_label_plural()
328 ) . '</p>' .
329 '<p>' . sprintf(
330 __(
331 'Once you\'ve added your %s, you should now Publish/Update the %s. This ensures that all %s will be available within the %s.',
332 'upstream'
333 ),
334 upstream_milestone_label_plural(),
335 upstream_project_label(),
336 upstream_milestone_label_plural(),
337 upstream_task_label_plural()
338 ) . '</p>' .
339 '<p>' . sprintf(__(
340 'If there are no %s in the dropdown, add them by editing the <strong>UpStream Settings</strong>.',
341 'upstream'
342 ), upstream_milestone_label_plural()) . '</p>',
343 'position' => [
344 'edge' => 'bottom',
345 'align' => 'top',
346 ],
347 ],
348 ],
349
350 ];
351
352 return $pointers;
353 }
354
355 /**
356 * Enqueue pointers and add script to page.
357 *
358 * @param array $pointers
359 */
360 public function enqueue_pointers($pointers)
361 {
362 $screen = get_current_screen();
363 $screen_id = $screen->id;
364
365 // Get pointers for this screen
366 $pointers = apply_filters('upstream_admin_pointers-' . $screen_id, []);
367
368 if ( ! $pointers || ! is_array($pointers)) {
369 return;
370 }
371
372 // Get dismissed pointers
373 $dismissed = explode(
374 ',',
375 (string)get_user_meta(get_current_user_id(), 'dismissed_wp_pointers', true)
376 );
377 $valid_pointers = [];
378
379 // Check pointers and remove dismissed ones.
380 foreach ($pointers as $pointer_id => $pointer) {
381
382 // Sanity check
383 if (in_array(
384 $pointer_id,
385 $dismissed
386 ) || empty($pointer) || empty($pointer_id) || empty($pointer['target']) || empty($pointer['options'])) {
387 continue;
388 }
389
390 $pointer['pointer_id'] = $pointer_id;
391
392 // Add the pointer to $valid_pointers array
393 $valid_pointers['pointers'][$pointer_id] = $pointer;
394 }
395
396 // No valid pointers? Stop here.
397 if (empty($valid_pointers)) {
398 return;
399 }
400
401 wp_enqueue_style('wp-pointer');
402 wp_enqueue_script('wp-pointer');
403
404 $valid_pointers = wp_json_encode($valid_pointers);
405
406 $return = wp_add_inline_script('wp-pointer', "
407 jQuery( function( $ ) {
408 var wc_pointers = {$valid_pointers};
409
410 setTimeout( init_wc_pointers, 2000 );
411
412 function init_wc_pointers() {
413 $.each( wc_pointers.pointers, function( i ) {
414 show_wc_pointer( i );
415 return false;
416 });
417 }
418
419 function show_wc_pointer( id ) {
420 var pointer = wc_pointers.pointers[ id ];
421
422 var options = $.extend( pointer.options, {
423 close: function() {
424 $.post( ajaxurl, {
425 pointer: pointer.pointer_id,
426 action: 'dismiss-wp-pointer'
427 });
428 if ( pointer.next ) {
429 show_wc_pointer( pointer.next );
430 }
431 }
432 } );
433 var this_pointer = $( pointer.target ).pointer( options );
434 this_pointer.pointer( 'open' );
435
436 if ( pointer.next_trigger ) {
437 $( pointer.next_trigger.target ).on( pointer.next_trigger.event, function() {
438 setTimeout( function() { this_pointer.pointer( 'close' ); }, 400 );
439 });
440 }
441 }
442 });
443 ");
444 }
445 }
446
447 new UpStream_Admin_Pointers();
448