Test Failed
Push — issues/2980 ( 6931f9 )
by Ravinder
05:32
created

is_banner_notice_hooked()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 3
nop 0
dl 0
loc 20
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * Give Activation Banner
4
 *
5
 * @author  WordImpress
6
 * @version 1.0
7
 */
8
9
// Exit if accessed directly.
10
if ( ! defined( 'ABSPATH' ) ) {
11
	exit;
12
}
13
14
global $give_addons;
15
16
/**
17
 * Class Give_Addon_Activation_Banner
18
 *
19
 * @since  2.1.0 Added pleasing interface when multiple add-ons are activated.
20
 */
21
class Give_Addon_Activation_Banner {
22
23
	/**
24
	 * Class constructor.
25
	 *
26
	 * @since  1.0
27
	 * @access public
28
	 *
29
	 * @param array $_banner_details {
30
	 *                               'file'              => __FILE__, // (required) Directory path to the main plugin file
31
	 *                               'name'              => __( 'Authorize.net Gateway', 'give-authorize' ), // (required) Name of the Add-on
32
	 *                               'version'           => GIVE_AUTHORIZE_VERSION, // (required)The most current version
33
	 *                               'documentation_url' => 'http://docs.givewp.com/addon-authorize',// (required)
34
	 *                               'support_url'       => 'https://givewp.com/support/', // (required)Location of Add-on settings page, leave blank to hide
35
	 *                               'testing'           => false, // (required) Never leave as "true" in production!!!
36
	 *                               }
37
	 */
38
	function __construct( $_banner_details ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
39
		global $give_addons;
40
41
		// Append add-on information to the global variable.
42
		$give_addons[] = $_banner_details;
43
44
		// Get the current user.
45
		$current_user  = wp_get_current_user();
46
		$this->user_id = $current_user->ID;
47
48
		// Set up hooks.
49
		$this->init();
50
51
		// Store user id who activated plugin.
52
		$this->add_addon_activate_meta();
53
54
		// Check if notice callback is already hooked.
55
		if ( ! $this->is_banner_notice_hooked() ) {
56
			// If multiple add-on are activated then show activation banner in tab view.
57
			add_action( 'admin_notices', array( $this, 'addon_activation_banner_notices' ), 10 );
58
		}
59
	}
60
61
	/**
62
	 * Set up WordPress filters to hook into WP's update process.
63
	 *
64
	 * @since  1.0
65
	 * @access public
66
	 *
67
	 * @return void
68
	 */
69
	public function init() {
70
		// Get the current page to add the notice to
71
		add_action( 'current_screen', array( $this, 'give_addon_notice_ignore' ) );
72
73
		// Get the Give add-ons.
74
		$give_addons = $this->get_plugin_file_names();
75
76
		if ( ! empty( $give_addons ) ) {
77
78
			// Go through each of the add-on and hook deactivate action.
79
			foreach ( $give_addons as $addon_name => $give_addon ) {
80
81
				// Testing?
82
				if ( true === $give_addon['testing'] ) {
83
					$nag_meta_key = 'give_addon_activation_ignore_' . $addon_name;
84
					delete_user_meta( $this->user_id, $nag_meta_key );
0 ignored issues
show
introduced by
delete_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
85
				}
86
87
				// Add deactivate hook.
88
				add_action( 'deactivate_' . $give_addon['plugin_main_file'], array( $this, 'remove_addon_activate_meta' ) );
89
			}
90
		}
91
	}
92
93
	/**
94
	 * Get plugin file name.
95
	 *
96
	 * @since   1.8
97
	 * @access  private
98
	 * @return mixed
99
	 */
100
	private function get_plugin_file_names() {
101
		global $give_addons;
102
103
		// Get recently activated plugins.
104
		$active_plugins = get_option( 'active_plugins' );
105
106
		$file_names = array();
107
108
		if ( empty( $give_addons ) ) {
109
			return $file_names;
110
		}
111
112
		// Go through each addon and get the plugin file url.
113
		foreach ( $give_addons as $give_addon ) {
114
			$file_name = '';
115
			if ( $file_path = explode( '/plugins/', $give_addon['file'] ) ) {
116
				$file_path = array_pop( $file_path );
117
				$file_name = current( explode( '/', $file_path ) );
118
			}
119
120
			if ( ! empty( $file_name ) ) {
121
				foreach ( $active_plugins as $plugin ) {
122
					if ( false !== strpos( $plugin, $file_name ) ) {
123
						$add_on_key                     = sanitize_title( $give_addon['name'] );
124
						$give_addon['plugin_main_file'] = $plugin; // Include plugin file.
125
						$file_names[ $add_on_key ]      = $give_addon;
126
						break;
127
					}
128
				}
129
			}
130
		}
131
132
		return $file_names;
133
	}
134
135
	/**
136
	 * Setup user id to option
137
	 *
138
	 * @since  1.8
139
	 * @access private
140
	 */
141
	private function add_addon_activate_meta() {
142
		// Get all activated add-ons.
143
		$give_addons = $this->get_plugin_file_names();
144
145
		if ( ! empty( $give_addons ) ) {
146
147
			// Go through rach add-ons and add meta data.
148
			foreach ( $give_addons as $banner_addon_name => $addon ) {
149
				// User meta key.
150
				$activate_by_meta_key = "give_addon_{$banner_addon_name}_active_by_user";
151
				$user_id              = get_option( $activate_by_meta_key );
152
153
				if ( ! $user_id ) {
154
					update_option( $activate_by_meta_key, $this->user_id, '' );
155
				}
156
			}
157
		}
158
	}
159
160
	/**
161
	 * Check if the addon_activation_banner_notices function has already been hooked to admin_notice.
162
	 *
163
	 * @since 2.1.0
164
	 *
165
	 * @return bool
166
	 */
167
	public function is_banner_notice_hooked() {
168
		global $wp_filter;
169
		$notice_already_hooked = false;
170
171
		if ( isset( $wp_filter['admin_notices']->callbacks[10] ) ) {
172
			// Get all of the hooks.
173
			$admin_notice_callbacks = array_keys( $wp_filter['admin_notices']->callbacks[10] );
174
175
			if ( ! empty( $admin_notice_callbacks ) ) {
176
				foreach ( $admin_notice_callbacks as $key ) {
177
					//If the key is found in your string, set $found to true
178
					if ( false !== strpos( $key, 'addon_activation_banner_notices' ) ) {
179
						$notice_already_hooked = true;
180
					}
181
				}
182
			}
183
		}
184
185
		return $notice_already_hooked;
186
	}
187
188
	/**
189
	 * Get the add-on banner notices.
190
	 *
191
	 * @since 2.1.0
192
	 */
193
	public function addon_activation_banner_notices() {
194
		global $pagenow, $give_addons;
195
196
		// Bailout.
197
		if ( 'plugins.php' !== $pagenow ) {
198
			return false;
199
		}
200
201
		// Store the add-ons of which activation banner should be shown.
202
		$addon_to_display = array();
203
204
		// Get recently activated add-ons.
205
		$recent_activated = $this->get_recently_activated_addons();
206
		$latest_addon     = array();
207
208
		// Get the plugin folder name, because many give-addon not sending proper plugin_file.
209
		if ( ! empty( $recent_activated ) ) {
210
			foreach ( $recent_activated as $recent_addon ) {
211
				// Get the add-on folder name.
212
				$latest_addon[] = substr( $recent_addon, 0, strpos( $recent_addon, '/' ) );
213
			}
214
		}
215
216
		// Go through each of the give add-on.
217
		foreach ( $give_addons as $addon ) {
218
			$addon_sanitized_name = sanitize_title( $addon['name'] );
219
220
			// Get the add-on dismiss status.
221
			$add_on_state = get_user_meta( $this->user_id, "give_addon_activation_ignore_{$addon_sanitized_name}", true );
0 ignored issues
show
introduced by
get_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
222
223
			// Get the option key.
224
			$activate_by_meta_key = "give_addon_{$addon_sanitized_name}_active_by_user";
225
			$activate_by_user     = (int) get_option( $activate_by_meta_key );
226
227
			// Remove plugin file and get the Add-on's folder name only.
228
			$file_path = $this->get_plugin_folder_name( $addon['file'] );
229
230
			// If add-on were never dismissed.
231
			if ( 'true' !== $add_on_state && $this->user_id === $activate_by_user ) {
232
				if ( ! empty( $latest_addon ) && ( in_array( $file_path, $latest_addon, true ) || empty( $latest_addon ) ) ) {
233
					$addon_to_display[] = $addon;
234
				}
235
			}
236
		}
237
238
		if ( ! empty( $addon_to_display ) ) {
239
			ob_start();
240
241
			// Output inline styles here because there's no reason
242
			// to enqueued them after the alert is dismissed.
243
			$this->print_css_js();
0 ignored issues
show
Unused Code introduced by
The call to the method Give_Addon_Activation_Banner::print_css_js() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
244
			?>
245
			<div class="<?php echo ( 1 !== count( $addon_to_display ) ) ? 'give-alert-tab-wrapper' : ''; ?> updated give-addon-alert give-notice">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '('
Loading history...
246
				<?php
247
				// If multiple add-on are activated.
248
				if ( 1 !== count( $addon_to_display ) ) {
249
					?>
250
					<div class="give-vertical-tab">
251
						<div class="give-addon-tab-list">
252
							<ul class="give-alert-addon-list">
253
								<?php
254
								$is_first = true;
255 View Code Duplication
								foreach ( $addon_to_display as $banner ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
256
									?>
257
									<li class="give-tab-list<?php echo ( true === $is_first ) ? ' active' : ''; ?>"
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '('
Loading history...
258
									    id="give-addon-<?php echo esc_html( basename( $banner['file'], '.php' ) ); ?>">
259
										<a href="#"><?php echo esc_html( $banner['name'] ); ?></a>
260
									</li>
261
									<?php
262
									$is_first = false;
263
								}
264
								$is_first = true;
265
								?>
266
							</ul>
267
						</div>
268
						<div class="give-right-side-block">
269
							<?php
270 View Code Duplication
							foreach ( $addon_to_display as $banner ) { ?>
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
271
								<div class="give-tab-details <?php echo ( true === $is_first ) ? ' active' : ''; ?> "
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '('
Loading history...
272
								     id="give-addon-<?php echo esc_html( basename( $banner['file'], '.php' ) ); ?>">
273
									<?php
274
									// Render single add banner.
275
									$this->render_single_addon_banner( $banner, false );
276
									?>
277
								</div>
278
								<?php
279
								$is_first = false;
280
							}
281
							?>
282
						</div>
283
					</div>
284
					<?php
285
				} else {
286
					$this->render_single_addon_banner( $addon_to_display[0], true );
287
				}
288
				?>
289
			</div>
290
			<?php
291
			$notice_html = ob_get_clean();
292
293
			// Register notice.
294
			Give()->notices->register_notice( array(
295
				'id'               => 'give_add_on_activation_notice',
296
				'type'             => 'updated',
297
				'description_html' => $notice_html,
298
				'show'             => true,
299
			) );
300
		}
301
	}
302
303
	/**
304
	 * Render single banner activation
305
	 *
306
	 * @since 2.1.0
307
	 *
308
	 * @param array $banner_arr Banner options.
309
	 * @param bool  $is_single  Is single.
310
	 */
311
	private function render_single_addon_banner( $banner_arr, $is_single ) {
312
		// Get all give add-on.
313
		$give_addons = give_get_plugins();
314
315
		// Plugin main file.
316
		$plugin_file = $banner_arr['file'];
317
318
		// Get the plugin main file.
319
		foreach ( $give_addons as $main_file => $addon ) {
320
			// Plugin should be activated.
321
			if ( ! is_plugin_active( $main_file ) ) {
322
				continue;
323
			}
324
325
			if (
326
				isset( $banner_arr['name'] )
327
				&& 'add-on' === $addon['Type']
328
				&& $this->get_plugin_folder_name( $main_file ) === $this->get_plugin_folder_name( $plugin_file )
329
			) {
330
				$plugin_file = WP_PLUGIN_DIR . '/' . $main_file;
331
				break;
332
			}
333
		}
334
335
		// Create dismiss URL.
336
		$dismiss_url = $is_single
337
			? admin_url( 'plugins.php?give_addon_activation_ignore=1&give_addon=' . sanitize_title( $banner_arr['name'] ) )
338
			: admin_url( 'plugins.php?give_addon_activation_ignore=1&give_addon=all' );
339
340
		// Get the add-on details.
341
		$plugin_data = get_plugin_data( $plugin_file );
342
		?>
343
		<img src="<?php echo GIVE_PLUGIN_URL; ?>assets/dist/images/give-icon-full-circle.svg" class="give-logo" />
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'GIVE_PLUGIN_URL'
Loading history...
344
		<div class="give-alert-message">
345
			<h3>
346
				<?php
347
				printf(
348
				/* translators: %s: Add-on name */
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 20 spaces, but found 16.
Loading history...
349
					esc_html__( "New Give Add-on Activated: %s", 'give' ),
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal New Give Add-on Activated: %s does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
350
					'<span>' . $banner_arr['name'] . '</span>'
351
				);
352
				?>
353
			</h3>
354
			<a href="<?php echo esc_url( $dismiss_url ); ?>" class="dismiss">
355
				<span class="dashicons dashicons-dismiss"></span>
356
			</a>
357
			<div class="alert-actions">
358
				<?php //Point them to your settings page.
359
				if ( ! empty( $plugin_data['Description'] ) ) {
360
					?><span class="give-addon-description">
361
					<em><?php echo strip_tags( $plugin_data['Description'] ); ?></em></span><br />
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'strip_tags'
Loading history...
362
					<?php
363
				}
364
				if ( isset( $banner_arr['settings_url'] ) ) { ?>
365
					<a href="<?php echo $banner_arr['settings_url']; ?>"><span
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$banner_arr'
Loading history...
366
								class="dashicons dashicons-admin-settings"></span><?php esc_html_e( 'Go to Settings', 'give' ); ?>
367
					</a>
368
					<?php
369
				}
370
				// Show them how to configure the Addon.
371
				if ( isset( $banner_arr['documentation_url'] ) ) { ?>
372
					<a href="<?php echo $banner_arr['documentation_url'] ?>" target="_blank">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$banner_arr'
Loading history...
373
						<span class="dashicons dashicons-media-text"></span><?php
374
						printf(
375
						/* translators: %s: Add-on name */
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 28 spaces, but found 24.
Loading history...
376
							esc_html__( 'Documentation: %s Add-on', 'give' ),
377
							$banner_arr['name']
378
						);
379
						?></a>
380
				<?php } ?>
381
				<?php
382
				//Let them signup for plugin updates
383
				if ( isset( $banner_arr['support_url'] ) ) { ?>
384
					<a href="<?php echo $banner_arr['support_url'] ?>" target="_blank">
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$banner_arr'
Loading history...
385
						<span class="dashicons dashicons-sos"></span><?php esc_html_e( 'Get Support', 'give' ); ?>
386
					</a>
387
				<?php } ?>
388
			</div>
389
		</div>
390
		<?php
391
	}
392
393
	/**
394
	 * Ignore Nag.
395
	 *
396
	 * This is the action that allows the user to dismiss the banner it basically sets a tag to their user meta data
397
	 *
398
	 * @since  1.0
399
	 * @access public
400
	 */
401
	public function give_addon_notice_ignore() {
402
		/**
403
		 * If user clicks to ignore the notice, add that to their user meta the banner then checks whether this tag exists already or not.
404
		 * See here: http://codex.wordpress.org/Function_Reference/add_user_meta
405
		 */
406
		if (
407
			isset( $_GET['give_addon'], $_GET['give_addon_activation_ignore'] )
408
			&& '1' === $_GET['give_addon_activation_ignore']
409
		) {
410
			// Get the value of the 'give_addon' query string.
411
			$addon_query_arg    = sanitize_text_field( $_GET['give_addon'] );
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
412
			$deactivated_addons = array();
413
414
			// If All add-on requested to dismiss.
415
			if ( 'all' === $addon_query_arg ) {
416
				// Get all activated add-ons.
417
				$give_addons = $this->get_plugin_file_names();
418
419
				if ( ! empty( $give_addons ) ) {
420
					$deactivated_addons = array_keys( $give_addons );
421
				}
422
			} else {
423
				// Store the addon to deactivate.
424
				$deactivated_addons[] = $addon_query_arg;
425
			}
426
427
			if ( ! empty( $deactivated_addons ) ) {
428
				foreach ( $deactivated_addons as $addon ) {
429
					// Record it user meta.
430
					add_user_meta( $this->user_id, "give_addon_activation_ignore_{$addon}", 'true', true );
0 ignored issues
show
introduced by
add_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
431
				}
432
			}
433
		}
434
	}
435
436
	/**
437
	 * Delete user id from option if plugin deactivated.
438
	 *
439
	 * @since  1.8
440
	 * @since  2.1.0 Added support for multiple addons.
441
	 * @access public
442
	 */
443
	public function remove_addon_activate_meta() {
444
		// Get the hook name and then grab the plugin file from it.
445
		$plugin_file = str_replace( 'deactivate_', '', current_action() );
446
447
		// Get all activated add-ons.
448
		$give_addons = $this->get_plugin_file_names();
449
450
		if ( ! empty( $give_addons ) ) {
451
			foreach ( $give_addons as $banner_addon_name => $addon ) {
452
				if ( $plugin_file === $addon['plugin_main_file'] ) {
453
					// Get the option key.
454
					$activate_by_meta_key = "give_addon_{$banner_addon_name}_active_by_user";
455
456
					// Get the user meta key.
457
					$user_id = get_option( $activate_by_meta_key );
458
459
					if ( $user_id ) {
460
						// Get user meta for this add-on.
461
						$nag_meta_key = "give_addon_activation_ignore_{$banner_addon_name}";
462
463
						// Delete plugin activation option key.
464
						delete_option( $activate_by_meta_key );
465
						// Delete user meta of plugin activation.
466
						delete_user_meta( $user_id, $nag_meta_key );
0 ignored issues
show
introduced by
delete_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
467
					}
468
				}
469
			}
470
		}
471
	}
472
473
	/**
474
	 * Get list of add-on last activated.
475
	 *
476
	 * @since 2.1.0
477
	 * @return mixed|array
478
	 */
479
	public function get_recently_activated_addons() {
480
		return get_option( 'give_recently_activated_addons', array() );
481
	}
482
483
	/**
484
	 * Get the addon's folder name.
485
	 *
486
	 * @since 2.1.0
487
	 *
488
	 * @param string $main_file Plugin Main File.
489
	 *
490
	 * @return bool|mixed|string
491
	 */
492
	public function get_plugin_folder_name( $main_file ) {
493
		// Remove plugin file and get the Add-on's folder name only.
494
		$file_path       = explode( '/plugins/', $main_file );
495
		$addon_file_path = array_pop( $file_path );
496
		$addon_file_path = substr( $addon_file_path, 0, strpos( $addon_file_path, '/' ) );
497
498
		return $addon_file_path;
499
	}
500
501
	/**
502
	 * Add activation banner css and js .
503
	 *
504
	 * @since  1.8.16
505
	 * @since  2.1.0 Added JS code for multiple add-on.
506
	 * @access private
507
	 */
508
	private function print_css_js() {
509
		?>
510
		<style>
511
			div.give-addon-alert.updated {
512
				padding: 20px;
513
				position: relative;
514
				border-color: #66BB6A;
515
				min-height: 85px;
516
			}
517
518
			div.give-alert-message {
519
				margin-left: 108px;
520
			}
521
522
			div.give-addon-alert img.give-logo {
523
				max-width: 85px;
524
				float: left;
525
			}
526
527
			div.give-addon-alert h3 {
528
				margin: -5px 0 10px;
529
				font-size: 22px;
530
				font-weight: 400;
531
				line-height: 30px;
532
			}
533
534
			div.give-addon-alert h3 span {
535
				font-weight: 700;
536
				color: #66BB6A;
537
			}
538
539
			div.give-addon-alert a {
540
				color: #66BB6A;
541
			}
542
543
			div.give-addon-alert .alert-actions a {
544
				margin-right: 2em;
545
			}
546
547
			div.give-addon-alert .alert-actions a {
548
				text-decoration: underline;
549
			}
550
551
			div.give-addon-alert .alert-actions a:hover {
552
				color: #555555;
553
			}
554
555
			div.give-addon-alert .alert-actions a span {
556
				text-decoration: none;
557
				margin-right: 5px;
558
			}
559
560
			div.give-addon-alert .dismiss {
561
				position: absolute;
562
				right: 0px;
563
				height: 99%;
564
				top: 23%;
565
				margin-top: -10px;
566
				outline: none;
567
				box-shadow: none;
568
				text-decoration: none;
569
				color: #AAA;
570
			}
571
572
			div.give-addon-alert .dismiss {
573
				position: absolute;
574
				right: 20px;
575
				height: 100%;
576
				top: 50%;
577
				margin-top: -10px;
578
				outline: none;
579
				box-shadow: none;
580
				text-decoration: none;
581
				color: #AAA;
582
			}
583
584
			div.give-alert-tab-wrapper .dismiss {
585
				right: 0px !important;
586
				height: 99% !important;
587
				top: 23% !important;
588
			}
589
590
			div.give-addon-alert .dismiss:hover {
591
				color: #333;
592
			}
593
594
			ul.give-alert-addon-list {
595
				min-width: 220px;
596
				display: inline-block;
597
				float: left;
598
				max-width: 250px;
599
				padding: 0;
600
				margin: 0;
601
				max-height: 146px;
602
				overflow: hidden;
603
			}
604
605
			div.give-addon-alert .give-addon-description {
606
				padding: 1px;
607
				display: inline-block;
608
				color: #777;
609
				margin-bottom: 12px;
610
			}
611
612
			div.give-alert-tab-wrapper .give-right-side-block {
613
				width: calc(100% - 250px);
614
				display: inline-block;
615
				float: left;
616
				background: #fff;
617
				height: 100%;
618
				position: relative;
619
			}
620
621
			div.give-vertical-tab {
622
				width: 100%;
623
			}
624
625
			ul.give-alert-addon-list li {
626
				display: block;
627
				border: 1px solid #d1d1d18f;
628
				border-width: 1px 0px 0px 0px;
629
				margin: 0;
630
			}
631
632
			ul.give-alert-addon-list li a.inactivate {
633
				cursor: default;
634
			}
635
636
			ul.give-alert-addon-list li a {
637
				display: block;
638
				font-weight: bold;
639
				color: #a3a3a3;
640
				text-decoration: none;
641
				padding: 15px 10px 15px;
642
				box-shadow: inset -6px 0px 18px 0px rgba(204, 204, 204, 0.36);
643
				-moz-box-shadow: inset -6px 0px 18px 0px rgba(204, 204, 204, 0.36);
644
				-webkit-box-shadow: inset -6px 0px 18px 0px rgba(204, 204, 204, 0.36);
645
				-ms-box-shadow: inset -6px 0px 18px 0px rgba(204, 204, 204, 0.36);
646
				-o-box-shadow: inset -6px 0px 18px 0px rgba(204, 204, 204, 0.36);
647
			}
648
649
			ul.give-alert-addon-list li.give-tab-list.active a {
650
				color: #5f6c74;
651
				box-shadow: none;
652
			}
653
654
			div.updated.give-addon-alert.give-notice.give-alert-tab-wrapper {
655
				display: inline-block;
656
				width: 100%;
657
			}
658
659
			.give-alert-tab-wrapper .give-tab-details {
660
				display: none;
661
				min-height: 100px;
662
				position: absolute;
663
				top: 0;
664
				left: 0;
665
				padding: 20px 20px 20px 40px;
666
			}
667
668
			.give-alert-tab-wrapper .give-tab-details.active {
669
				display: block;
670
				z-index: 1;
671
				position: relative;
672
			}
673
674
			.give-alert-tab-wrapper.give-addon-alert img.give-logo {
675
				max-width: 80px;
676
			}
677
678
			.give-alert-tab-wrapper .give-alert-message {
679
				margin-left: 100px;
680
				padding-top: 10px;
681
			}
682
683
			ul.give-alert-addon-list li.give-tab-list.active {
684
				background: #fff;
685
			}
686
687
			ul.give-alert-addon-list li.give-tab-list:last-child {
688
				border-bottom: 0px solid #ccc;
689
			}
690
691
			ul.give-alert-addon-list li.give-tab-list:first-child {
692
				border-top: 0 none;
693
			}
694
695
			.give-alert-tab-wrapper {
696
				padding: 0 !important;
697
			}
698
699
			ul.give-alert-addon-list::-webkit-scrollbar {
700
				height: 10px;
701
				width: 10px;
702
				border-radius: 4px;
703
				transition: all 0.3s ease;
704
				background: rgba(158, 158, 158, 0.15);
705
			}
706
707
			ul.give-alert-addon-list::-webkit-scrollbar-thumb {
708
				background: #939395;
709
				border-radius: 4px;
710
			}
711
712
			/** Responsiveness */
713
			@media screen and (max-width: 767px) {
714
				.give-alert-tab-wrapper .give-tab-details {
715
					padding: 20px 40px 20px 20px;
716
				}
717
718
				.give-alert-tab-wrapper .give-right-side-block {
719
					width: 100%;
720
				}
721
722
				.give-alert-tab-wrapper ul.give-alert-addon-list {
723
					min-width: 100%;
724
				}
725
			}
726
		</style>
727
728
		<!-- Start of the Give Add-on tab JS -->
729
		<script type="text/javascript">
730
					jQuery( document ).ready( function( $ ) {
731
						$( '.give-alert-tab-wrapper' ).on( 'click', '.give-tab-list', function() {
732
							if ( $( this ).find( 'a' ).hasClass( 'inactivate' ) ) {
733
								return false;
734
							}
735
736
							var
737
								clicked_tab = $( this ).attr( 'id' ),
738
								addon_tab_wrapper = $( this ).closest( '.give-alert-tab-wrapper' );
739
740
							// Remove 'active' class from all tab list.
741
							$( '.give-alert-addon-list li' ).removeClass( 'active' );
742
							// Add active class to the selected tab.
743
							$( this ).addClass( 'active' );
744
							// Remove 'active' class from the details.
745
							addon_tab_wrapper.find( '.give-tab-details' ).removeClass( 'active' );
746
							addon_tab_wrapper.find( '.give-right-side-block .give-tab-details#' + clicked_tab ).addClass( 'active' );
747
748
							return false;
749
						} );
750
751
						var add_on_tabs = $( '.give-alert-addon-list' );
752
753
						add_on_tabs
754
							.mouseout( function() {
755
								$( this ).css( 'overflow', 'hidden' );
756
							} )
757
							.mouseover( function() {
758
								$( this ).css( 'overflow', 'auto' );
759
							} );
760
761
						// Prevent default click event of the add-on.
762
						add_on_tabs.find( 'li a' ).on( 'click', function( e ) {
763
							e.preventDefault();
764
						} );
765
766
						// If total length of the add-on is 2.
767
						if ( 2 === add_on_tabs.find( 'li' ).length ) {
768
							var li = $( 'li.give-tab-list' );
769
							li.last().clone().prependTo( 'ul.give-alert-addon-list' );
770
							li.last().removeAttr( 'id' ).find( 'a' ).addClass( 'inactivate' ).html( '&nbsp;' );
771
							$( '.give-tab-list:first' ).trigger( 'click' );
772
						}
773
					} );
774
		</script>
775
		<!-- End of the Give Add-on tab JS -->
776
		<?php
777
	}
778
}
779