Completed
Pull Request — master (#1201)
by Ravinder
23:20
created

Give_Donators_Gravatars::setup_actions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 6
rs 9.4285
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 24 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Donors Gravatars
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_Donors_Gravatars
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Give_Donors_Gravatars Class
19
 *
20
 * This class handles donors gravatars.
21
 *
22
 * @since 1.0
23
 */
24
class Give_Donors_Gravatars {
25
26
	/**
27
	 * Class Constructor
28
	 *
29
	 * Set up the Give Donors Gravatars Class.
30
	 *
31
	 * @since  1.0
32
	 * @access public
33
	 */
34
	public function __construct() {
35
		$this->setup_actions();
0 ignored issues
show
Unused Code introduced by
The call to the method Give_Donors_Gravatars::setup_actions() 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...
36
	}
37
38
	/**
39
	 * Setup the default hooks and actions
40
	 *
41
	 * @since  1.0
42
	 * @access private
43
	 *
44
	 * @return void
45
	 */
46
	private function setup_actions() {
47
		//		add_action( 'widgets_init', array( $this, 'register_widget' ) );
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
48
		//		add_shortcode( 'give_donors_gravatars', array( $this, 'shortcode' ) );
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
49
		//		add_filter( 'give_settings_display', array( $this, 'settings' ) );
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
50
		//		do_action( 'give_donors_gravatars_setup_actions' );
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
51
	}
52
53
	/**
54
	 * Utility function to check if a gravatar exists for a given email or id
55
	 *
56
	 * @see: https://gist.github.com/justinph/5197810
57
	 *
58
	 * @since  1.0
59
	 * @access public
60
	 *
61
	 * @param  int|string|object $id_or_email A user ID, email address, or comment object
62
	 *
63
	 * @return bool If the gravatar exists or not
64
	 */
65
	public function validate_gravatar( $id_or_email ) {
66
		//id or email code borrowed from wp-includes/pluggable.php
67
		$email = '';
68
		if ( is_numeric( $id_or_email ) ) {
69
			$id   = (int) $id_or_email;
70
			$user = get_userdata( $id );
71
			if ( $user ) {
72
				$email = $user->user_email;
73
			}
74
		} elseif ( is_object( $id_or_email ) ) {
75
			// No avatar for pingbacks or trackbacks
76
			$allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
77
			if ( ! empty( $id_or_email->comment_type ) && ! in_array( $id_or_email->comment_type, (array) $allowed_comment_types ) ) {
78
				return false;
79
			}
80
81
			if ( ! empty( $id_or_email->user_id ) ) {
82
				$id   = (int) $id_or_email->user_id;
83
				$user = get_userdata( $id );
84
				if ( $user ) {
85
					$email = $user->user_email;
86
				}
87
			} elseif ( ! empty( $id_or_email->comment_author_email ) ) {
88
				$email = $id_or_email->comment_author_email;
89
			}
90
		} else {
91
			$email = $id_or_email;
92
		}
93
94
		$hashkey = md5( strtolower( trim( $email ) ) );
95
		$uri     = 'http://www.gravatar.com/avatar/' . $hashkey . '?d=404';
96
97
		$data = wp_cache_get( $hashkey );
98
		if ( false === $data ) {
99
			$response = wp_remote_head( $uri );
100
			if ( is_wp_error( $response ) ) {
101
				$data = 'not200';
102
			} else {
103
				$data = $response['response']['code'];
104
			}
105
			wp_cache_set( $hashkey, $data, $group = '', $expire = 60 * 5 );
106
107
		}
108
		if ( $data == '200' ) {
109
			return true;
110
		} else {
111
			return false;
112
		}
113
	}
114
115
	/**
116
	 * Get an array of all the log IDs using the Give Logging Class
117
	 *
118
	 * @since  1.0
119
	 * @access public
120
	 *
121
	 * @param  int $form_id Donation form id
122
	 *
123
	 * @return array        IDs if logs, false otherwise
124
	 */
125
	public function get_log_ids( $form_id = '' ) {
126
127
		// get Give_Logging class
128
		global $give_logs;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
129
130
		// get log for this form
131
		$logs = $give_logs->get_logs( $form_id );
132
133
		if ( $logs ) {
134
			$log_ids = array();
135
136
			// make an array with all the donor IDs
137
			foreach ( $logs as $log ) {
138
				$log_ids[] = $log->ID;
139
			}
140
141
			return $log_ids;
142
		}
143
144
		return null;
145
146
	}
147
148
	/**
149
	 * Get payment ID
150
	 *
151
	 * @since  1.0
152
	 * @access public
153
	 *
154
	 * @param  int $form_id Donation form id
155
	 *
156
	 * @return mixed
157
	 */
158
	public function get_payment_ids( $form_id = '' ) {
159
160
		$give_options = give_get_settings();
161
162
		$log_ids = $this->get_log_ids( $form_id );
163
164
		if ( $log_ids ) {
165
166
			$payment_ids = array();
167
168
			foreach ( $log_ids as $id ) {
169
				// get the payment ID for each corresponding log ID
170
				$payment_ids[] = get_post_meta( $id, '_give_log_payment_id', true );
171
			}
172
173
			// remove donors who have donated more than once so we can have unique avatars
174
			$unique_emails = array();
175
176
			foreach ( $payment_ids as $key => $id ) {
177
178
				$email = get_post_meta( $id, '_give_payment_user_email', true );
179
180
				if ( isset ( $give_options['give_donors_gravatars_has_gravatar_account'] ) ) {
181
					if ( ! $this->validate_gravatar( $email ) ) {
182
						continue;
183
					}
184
				}
185
186
				$unique_emails[ $id ] = get_post_meta( $id, '_give_payment_user_email', true );
187
188
			}
189
190
			$unique_ids = array();
191
192
			// strip duplicate emails
193
			$unique_emails = array_unique( $unique_emails );
194
195
			// convert the unique IDs back into simple array
196
			foreach ( $unique_emails as $id => $email ) {
197
				$unique_ids[] = $id;
198
			}
199
200
			// randomize the payment IDs if enabled
201
			if ( isset( $give_options['give_donors_gravatars_random_gravatars'] ) ) {
202
				shuffle( $unique_ids );
203
			}
204
205
			// return our unique IDs
206
			return $unique_ids;
207
208
		}
209
210
	}
211
212
	/**
213
	 * Gravatars
214
	 *
215
	 * @since  1.0
216
	 * @access public
217
	 *
218
	 * @param  int    $form_id Donation form id.
219
	 * @param  string $title   Donors gravatars title.
220
	 *
221
	 * @return string
222
	 */
223
	public function gravatars( $form_id = false, $title = '' ) {
224
225
		// unique $payment_ids 
226
		$payment_ids = $this->get_payment_ids( $form_id );
227
228
		$give_options = give_get_settings();
229
230
		// return if no ID
231
		if ( ! $form_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $form_id of type false|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
232
			return;
233
		}
234
235
		// minimum amount of donations before showing gravatars
236
		// if the number of items in array is not greater or equal to the number specified, then exit
237
		if ( isset( $give_options['give_donors_gravatars_min_purchases_required'] ) && '' != $give_options['give_donors_gravatars_min_purchases_required'] ) {
238
			if ( ! ( count( $payment_ids ) >= $give_options['give_donors_gravatars_min_purchases_required'] ) ) {
239
				return;
240
			}
241
		}
242
243
		ob_start();
244
245
		$output = '';
246
		echo '<div id="give-purchase-gravatars">';
247
248
249
		if ( isset ( $title ) ) {
250
251
			if ( $title ) {
252
				echo apply_filters( 'give_donors_gravatars_title', '<h3 class="give-gravatars-title">' . esc_attr( $title ) . '</h3>' );
253
			} elseif ( isset( $give_options['give_donors_gravatars_heading'] ) ) {
254
				echo apply_filters( 'give_donors_gravatars_title', '<h3 class="give-gravatars-title">' . esc_attr( $give_options['give_donors_gravatars_heading'] ) . '</h2>' );
255
			}
256
257
		}
258
		echo '<ul class="give-purchase-gravatars-list">';
259
		$i = 0;
260
261
		if ( $payment_ids ) {
262
			foreach ( $payment_ids as $id ) {
263
264
				// Give saves a blank option even when the control is turned off, hence the extra check
265
				if ( isset( $give_options['give_donors_gravatars_maximum_number'] ) && '' != $give_options['give_donors_gravatars_maximum_number'] && $i == $give_options['give_donors_gravatars_maximum_number'] ) {
266
					continue;
267
				}
268
269
				// get the payment meta
270
				$payment_meta = get_post_meta( $id, '_give_payment_meta', true );
271
272
				// unserialize the payment meta
273
				$user_info = maybe_unserialize( $payment_meta['user_info'] );
274
275
				// get donor's first name
276
				$name = $user_info['first_name'];
277
278
				// get donor's email
279
				$email = get_post_meta( $id, '_give_payment_user_email', true );
280
281
				// set gravatar size and provide filter
282
				$size = isset( $give_options['give_donors_gravatars_gravatar_size'] ) ? apply_filters( 'give_donors_gravatars_gravatar_size', $give_options['give_donors_gravatars_gravatar_size'] ) : '';
283
284
				// default image
285
				$default_image = apply_filters( 'give_donors_gravatars_gravatar_default_image', false );
286
287
				// assemble output
288
				$output .= '<li>';
289
290
				$output .= get_avatar( $email, $size, $default_image, $name );
291
				$output .= '</li>';
292
293
				$i ++;
294
295
			} // end foreach
296
		}
297
298
		echo $output;
299
		echo '</ul>';
300
		echo '</div>';
301
302
		return apply_filters( 'give_donors_gravatars', ob_get_clean() );
303
	}
304
305
	/**
306
	 * Register widget
307
	 *
308
	 * @since  1.0
309
	 * @access public
310
	 *
311
	 * @return void
312
	 */
313
	public function register_widget() {
314
		register_widget( 'Give_Donors_Gravatars_Widget' );
315
	}
316
317
	/**
318
	 * Shortcode
319
	 *
320
	 * @since  1.0
321
	 * @access public
322
	 *
323
	 * @param  array  $atts    Shortcode attribures.
324
	 * @param  string $content Shortcode content.
325
	 *
326
	 * @return string
327
	 */
328
	public function shortcode( $atts, $content = null ) {
0 ignored issues
show
Unused Code introduced by
The parameter $content is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
329
330
		$atts = shortcode_atts( array(
331
			'id'    => '',
332
			'title' => ''
333
		), $atts, 'give_donors_gravatars' );
334
335
		// if no ID is passed on single give_forms pages, get the correct ID
336
		if ( is_singular( 'give_forms' ) ) {
337
			$id = get_the_ID();
338
		}
339
340
		$content = $this->gravatars( $atts['id'], $atts['title'] );
341
342
		return $content;
343
344
	}
345
346
	/**
347
	 * Settings
348
	 *
349
	 * @since  1.0
350
	 * @access public
351
	 *
352
	 * @param  array $settings Gravatar settings.
353
	 *
354
	 * @return array           Gravatar settings.
355
	 */
356
	public function settings( $settings ) {
357
358
		$give_gravatar_settings = array(
359
			array(
360
				'name' => esc_html__( 'Donator Gravatars', 'give' ),
361
				'desc' => '<hr>',
362
				'id'   => 'give_title',
363
				'type' => 'give_title'
364
			),
365
			array(
366
				'name' => esc_html__( 'Heading', 'give' ),
367
				'desc' => esc_html__( 'The heading to display above the Gravatars.', 'give' ),
368
				'type' => 'text',
369
				'id'   => 'give_donors_gravatars_heading'
370
			),
371
			array(
372
				'name'    => esc_html__( 'Gravatar Size', 'give' ),
373
				'desc'    => esc_html__( 'The size of each Gravatar in pixels (512px maximum).', 'give' ),
374
				'type'    => 'text_small',
375
				'id'      => 'give_donors_gravatars_gravatar_size',
376
				'default' => '64'
377
			),
378
			array(
379
				'name' => esc_html__( 'Minimum Unique Donations Required', 'give' ),
380
				'desc' => esc_html__( 'The minimum number of unique donations a form must have before the Gravatars are shown. Leave blank for no minimum.', 'give' ),
381
				'type' => 'text_small',
382
				'id'   => 'give_donors_gravatars_min_purchases_required',
383
			),
384
			array(
385
				'name'    => esc_html__( 'Maximum Gravatars To Show', 'give' ),
386
				'desc'    => esc_html__( 'The maximum number of gravatars to show. Leave blank for no limit.', 'give' ),
387
				'type'    => 'text',
388
				'id'      => 'give_donors_gravatars_maximum_number',
389
				'default' => '20',
390
			),
391
			array(
392
				'name' => esc_html__( 'Gravatar Visibility', 'give' ),
393
				'desc' => esc_html__( 'Show only donors with a Gravatar account.', 'give' ),
394
				'id'   => 'give_donors_gravatars_has_gravatar_account',
395
				'type' => 'checkbox',
396
			),
397
			array(
398
				'name' => esc_html__( 'Randomize Gravatars', 'give' ),
399
				'desc' => esc_html__( 'Randomize the Gravatars.', 'give' ),
400
				'id'   => 'give_donors_gravatars_random_gravatars',
401
				'type' => 'checkbox',
402
			),
403
		);
404
405
		return array_merge( $settings, $give_gravatar_settings );
406
	}
407
408
}
409
410
411
/**
412
 * Give_Donors_Gravatars_Widget Class
413
 *
414
 * This class handles donors gravatars
415
 *
416
 * @since 1.0
417
 */
418
class Give_Donors_Gravatars_Widget extends WP_Widget {
419
420
	/**
421
	 * Widget constructor
422
	 *
423
	 * @since  1.0
424
	 * @access public
425
	 */
426
	public function __construct() {
427
428
		// widget settings
429
		$widget_ops = array(
430
			'classname'   => 'give-donors-gravatars',
431
			'description' => esc_html__( 'Displays gravatars of people who have donated using your your form. Will only show on the single form page.', 'give' ),
432
		);
433
434
		// widget control settings
435
		$control_ops = array(
436
			'width'   => 250,
437
			'height'  => 350,
438
			'id_base' => 'give_gravatars_widget'
439
		);
440
441
		// create the widget
442
		parent::__construct(
443
			'give_donors_gravatars_widget',
444
			esc_html__( 'Give Donors Gravatars', 'give' ),
445
			$widget_ops,
446
			$control_ops
447
		);
448
449
	}
450
451
	/**
452
	 * Donors gravatars widget content
453
	 *
454
	 * Outputs the content of the widget
455
	 *
456
	 * @since  1.0
457
	 * @access public
458
	 *
459
	 * @param  array $args     Display arguments including 'before_title', 'after_title', 'before_widget', and 'after_widget'.
460
	 * @param  array $instance Settings for the current Links widget instance.
461
	 *
462
	 * @return void
463
	 */
464
	public function widget( $args, $instance ) {
465
466
		//@TODO: Don't extract it!!!
467
		extract( $args );
468
469
		if ( ! is_singular( 'give_forms' ) ) {
470
			return;
471
		}
472
473
		// Variables from widget settings
474
		$title = apply_filters( 'widget_title', $instance['title'] );
475
476
		// Used by themes. Opens the widget
477
		echo $before_widget;
478
479
		// Display the widget title
480
		if ( $title ) {
481
			echo $before_title . $title . $after_title;
482
		}
483
484
		$gravatars = new Give_Donors_Gravatars();
485
486
		echo $gravatars->gravatars( get_the_ID(), null ); // remove title
487
488
		// Used by themes. Closes the widget
489
		echo $after_widget;
490
491
	}
492
493
	/**
494
	 * Update donors gravatars
495
	 *
496
	 * Processes widget options to be saved.
497
	 *
498
	 * @since  1.0
499
	 * @access public
500
	 *
501
	 * @param  array $new_instance New settings for this instance as input by the user via WP_Widget::form().
502
	 * @param  array $old_instance Old settings for this instance.
503
	 *
504
	 * @return array Updated settings to save.
505
	 */
506
	public function update( $new_instance, $old_instance ) {
507
508
		$instance = $old_instance;
509
510
		$instance['title'] = strip_tags( $new_instance['title'] );
511
512
		return $instance;
513
514
	}
515
516
	/**
517
	 * Output donors gravatars
518
	 *
519
	 * Displays the actual form on the widget page.
520
	 *
521
	 * @since  1.0
522
	 * @access public
523
	 *
524
	 * @param  array $instance Current settings.
525
	 *
526
	 * @return void
527
	 */
528
	public function form( $instance ) {
529
530
		// Set up some default widget settings.
531
		$defaults = array(
532
			'title' => '',
533
		);
534
535
		$instance = wp_parse_args( (array) $instance, $defaults ); ?>
536
537
		<!-- Title -->
538
		<p>
539
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'give' ) ?></label>
540
			<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo $instance['title']; ?>" />
541
		</p>
542
543
		<?php
544
	}
545
546
}
547