Completed
Pull Request — master (#1055)
by Rami
19:01
created

Give_Donors_Gravatars::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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