<?php
/**
 * Plugin Name: Easy Digital Downloads - Purchase Gravatars
 * Plugin URI: https://easydigitaldownloads.com/downloads/edd-purchase-gravatars/
 * Description: Displays gravatars of customers who have purchased your product.
 * Version: 1.0.5
 * Author: Sandhills Development, LLC
 * Author URI: https://sandhillsdev.com
 * Text Domain: edd-pg
 * Domain Path: languages
 * License: GPL-2.0+
 * License URI: http://www.opensource.org/licenses/gpl-license.php
 * Requires at least: 4.2
 * Tested up to: 5.8
 */

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'EDD_Purchase_Gravatars' ) ) {

	class EDD_Purchase_Gravatars {

		private static $instance;

		/**
		 * Main Instance
		 *
		 * Ensures that only one instance exists in memory at any one
		 * time. Also prevents needing to define globals all over the place.
		 *
		 * @since 1.0
		 *
		 */
		public static function instance() {
			if ( ! isset ( self::$instance ) ) {
				self::$instance = new self;
			}

			return self::$instance;
		}


		/**
		 * Start your engines
		 *
		 * @since 1.0
		 *
		 * @return void
		 */
		public function __construct() {
			$this->setup_actions();
		}

		/**
		 * Setup the default hooks and actions
		 *
		 * @since 1.0
		 *
		 * @return void
		 */
		private function setup_actions() {
			add_action( 'init', array( $this, 'textdomain' ) );
			add_action( 'widgets_init',  array( $this, 'register_widget' ) );
			add_shortcode( 'edd_purchase_gravatars', array( $this, 'shortcode' ) );
			add_filter( 'edd_settings_extensions', array( $this, 'settings' ) );
			add_filter( 'edd_settings_sections_extensions', array( $this, 'register_section' ) );

			do_action( 'edd_pg_setup_actions' );
		}

		/**
		 * Internationalization
		 *
		 * @since 1.0
		 */
		public function textdomain() {
			load_plugin_textdomain( 'edd-pg', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
		}

		/**
		 * Utility function to check if a gravatar exists for a given email or id
		 * @param int|string|object $id_or_email A user ID, email address, or comment object
		 * @return bool if the gravatar exists or not
		 */

		// https://gist.github.com/justinph/5197810
		public function validate_gravatar( $id_or_email ) {
		  //id or email code borrowed from wp-includes/pluggable.php
			$email = '';
			if ( is_numeric( $id_or_email ) ) {
				$id = (int) $id_or_email;
				$user = get_userdata( $id );
				if ( $user )
					$email = $user->user_email;
			} elseif ( is_object( $id_or_email ) ) {
				// No avatar for pingbacks or trackbacks
				$allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
				if ( ! empty( $id_or_email->comment_type ) && ! in_array( $id_or_email->comment_type, (array) $allowed_comment_types ) )
					return false;

				if ( !empty( $id_or_email->user_id ) ) {
					$id = (int) $id_or_email->user_id;
					$user = get_userdata( $id );
					if ( $user )
						$email = $user->user_email;
				} elseif ( !empty( $id_or_email->comment_author_email ) ) {
					$email = $id_or_email->comment_author_email;
				}
			} else {
				$email = $id_or_email;
			}

			$hashkey = md5( strtolower( trim( $email ) ) );
			$uri = 'http://www.gravatar.com/avatar/' . $hashkey . '?d=404';

			$data = wp_cache_get( $hashkey );
			if ( false === $data ) {
				$response = wp_remote_head( $uri );
				if( is_wp_error( $response ) ) {
					$data = 'not200';
				} else {
					$data = $response['response']['code'];
				}
			    wp_cache_set( $hashkey, $data, $group = '', $expire = 60*5 );

			}
			if ( $data == '200' ) {
				return true;
			} else {
				return false;
			}
		}

		/**
		 * Get an array of all the log IDs using the EDD Logging Class
		 *
		 * @since 1.0
		 * @param $download_id Download's ID
		 * @return array $log_ids
		*/
		public function get_log_ids( $download_id = '' ) {

			// Instantiate a new instance of the class
			$edd_logging = new EDD_Logging();

			// get log for this download
			$logs = $edd_logging->get_connected_logs(
				array(
					'post_parent'    => $download_id,
					'log_type'       => 'sale',
					'posts_per_page' => -1,
					'fields'         => 'ids',
				)
			);

			return $logs ? $logs : null;
		}


		/**
		 * Get array of unique payment IDs
		 *
		 * @since 1.0
		 * @param int $download_id Download ID
		 * @return array $unique_ids
		*/
		public function get_payment_ids( $download_id = '' ) {

			global $edd_options;

			$payment_ids = array();

			if ( function_exists( 'edd_get_orders' ) ) {

				$payment_ids = edd_get_orders( array(
					'type'       => 'sale',
					'status'     => 'complete',
					'product_id' => $download_id,
					'fields'     => 'ids',
					'number'     => 999999,
				) );

			} else {

				$log_ids = $this->get_log_ids( $download_id );

				if ( $log_ids ) {

					foreach ( $log_ids as $id ) {
						// get the payment ID for each corresponding log ID
						$payment_ids[] = get_post_meta( $id, '_edd_log_payment_id', true );
					}

				}

			}

			// remove customers who have purchased more than once so we can have unique gravatar imagesw
			$unique_emails = array();
			$unique_ids    = array();

			foreach ( $payment_ids as $key => $id ) {

				$email = edd_get_payment_meta( $id, '_edd_payment_user_email', true );

				if ( isset ( $edd_options['edd_pg_has_gravatar_account'] ) ) {
					if ( ! $this->validate_gravatar( $email ) ) {
						continue;
					}
				}

				$unique_emails[$id] = $email;

			}

			// strip duplicate emails
			$unique_emails = array_unique( $unique_emails );

			// convert the unique IDs back into simple array
			foreach ( $unique_emails as $id => $email ) {
				$unique_ids[] = $id;
			}

			// randomize the payment IDs if enabled
			if ( isset( $edd_options['edd_pg_random_gravatars'] ) ) {
				shuffle( $unique_ids );
			}

			// return our unique IDs
			return $unique_ids;

		}


		/**
		 * Gravatars
		 *
		 * @since 1.0
		*/
		public function gravatars( $download_id = false, $title = '' ) {

			// Return if no ID.
			if ( ! $download_id ) {
				return '';
			}

			// unique $payment_ids
			$payment_ids = $this->get_payment_ids( $download_id );
			if ( empty( $payment_ids ) ) {
				return '';
			}

			global $edd_options;

			// minimum amount of purchases before showing gravatars
			// if the number of items in array is not greater or equal to the number specified, then exit
			if ( isset( $edd_options['edd_pg_min_purchases_required'] ) && '' != $edd_options['edd_pg_min_purchases_required'] ) {
				if ( ! ( count( $payment_ids ) >= $edd_options['edd_pg_min_purchases_required'] ) ) {
					return '';
				}
			}

			ob_start();

			echo '<div class="edd-purchase-gravatars">';

			if ( isset ( $title ) ) {

				if ( $title ) {
					echo apply_filters( 'edd_pg_title', '<h2>' . esc_attr( $title ) .'</h2>' );
				}
				elseif ( isset( $edd_options['edd_pg_heading'] ) ) {
					echo apply_filters( 'edd_pg_title', '<h2>' . esc_attr( $edd_options['edd_pg_heading'] ) .'</h2>' );
				}

			}

			$i       = 0;
			$maximum = edd_get_option( 'edd_pg_maximum_number' );

			if ( $payment_ids ) {
				foreach ( $payment_ids as $id ) {

					// EDD saves a blank option even when the control is turned off, hence the extra check
					if ( ! empty( $maximum ) && $i >= (int) $maximum ) {
						break;
					}

					$payment = edd_get_payment( $id );

					// get customer's first name
					$name = apply_filters( 'edd_pg_name', $payment->first_name );

					// get customer's email
					$email = $payment->email;

					// set gravatar size and provide filter
					$size = isset( $edd_options['edd_pg_gravatar_size'] ) ? apply_filters( 'edd_pg_gravatar_size', $edd_options['edd_pg_gravatar_size'] ) : '';

					// default image
					$default_image = apply_filters( 'edd_pg_gravatar_default_image', false );

					// $data is compiled to be available to the `edd_pg_gravatar_args` filter and is not otherwise used.
					$data = array(
						'email'         => $email,
						'size'          => $size,
						'default_image' => $default_image,
						'name'          => $name,
					);

					/**
					 * Filters the optional $args parameter for get_avatar.
					 *
					 * @since 1.0.5
					 * @param array $args The array of args to pass to the function. Default empty array.
					 * @param array $data The array of data about the current gravatar/email.
					 */
					$args = apply_filters( 'edd_pg_gravatar_args', array(), $data );

					echo '<span class="edd-purchase-gravatar">';

					// Output the gravatar.
					echo get_avatar( $email, $size, $default_image, $name, $args );

					do_action( 'edd_purchase_gravatars' );

					echo '</span>';

					$i++;

				} // end foreach
			}

			echo '</div>';

			?>

		<?php
			return apply_filters( 'edd_pg_gravatars', ob_get_clean() );
		}

		/**
		 * Register widget
		 *
		 * @since 1.0
		*/
		public function register_widget() {
			register_widget( 'EDD_Purchase_Gravatars_Widget' );
		}

		/**
		 * Outputs the customer gravatars for a specific download.
		 *
		 * @since 1.0
		 * @param array $atts The array of attributes passed to the shortcode.
		 */
		public function shortcode( $atts ) {

			$atts = shortcode_atts(
				array(
					'id'    => '',
					'title' => '',
				),
				$atts,
				'edd_purchase_gravatars'
			);

			// On a singular download, get the current ID.
			if ( is_singular( 'download' ) ) {
				$atts['id'] = get_the_ID();
			}

			$download = new EDD_Download( $atts['id'] );
			if ( ! $download instanceof EDD_Download ) {
				return '';
			}
			$sales = $download->get_sales();
			if ( empty( $sales ) ) {
				return '';
			}

			return $this->gravatars( $atts['id'], $atts['title'] );
		}

		/**
		 * Register section for settings.
		 *
		 * @since 1.0.4
		 * @access public
		 * @return array $sections Settings sections
		 */
		public function register_section( $sections ) {
			$sections['purchase_gravatars'] = __( 'Purchase Gravatars', 'edd-pg' );
			return $sections;
		}

		/**
		 * Settings
		 *
		 * @since 1.0
		*/
		public function settings( $sections ) {

		  $edd_pg_settings = array(
				array(
					'id' => 'edd_pg_header',
					'name' => '<strong>' . __( 'Purchase Gravatars', 'edd-pg' ) . '</strong>',
					'type' => 'header'
				),

				array(
					'id' => 'edd_pg_heading',
					'name' => __( 'Heading', 'edd-pg' ),
					'desc' => __( 'The heading to display above the Gravatars', 'edd-pg' ),
					'type' => 'text',
					'std' => ''
				),
				array(
					'id' => 'edd_pg_gravatar_size',
					'name' => __( 'Gravatar Size', 'edd-pg' ),
					'desc' => __( 'The size of each Gravatar in pixels (512px maximum)', 'edd-pg' ),
					'type' => 'text',
					'std' => '48'
				),
				array(
					'id' => 'edd_pg_min_purchases_required',
					'name' => __( 'Minimum Unique Purchases Required', 'edd-pg' ),
					'desc' => sprintf( __( 'The minimum number of unique purchases a %s must have before the Gravatars are shown. Leave blank for no minimum.', 'edd-pg' ), strtolower( edd_get_label_singular() ) ),
					'type' => 'text',
					'std' => ''
				),
				array(
					'id' => 'edd_pg_maximum_number',
					'name' => __( 'Maximum Gravatars To Show', 'edd-pg' ),
					'desc' => __( 'The maximum number of gravatars to show. Leave blank for no limit.', 'edd-pg' ),
					'type' => 'text',
					'std' => ''
				),
				array(
					'id' => 'edd_pg_has_gravatar_account',
					'name' => __( 'Gravatar Visibility', 'edd-pg' ),
					'desc' => __( 'Only show customers with a Gravatar account', 'edd-pg' ),
					'type' => 'checkbox',
				),
				array(
					'id' => 'edd_pg_random_gravatars',
					'name' => __( 'Randomize Gravatars', 'edd-pg' ),
					'desc' => __( 'Randomize the Gravatars', 'edd-pg' ),
					'type' => 'checkbox',
				),
			);

			// If EDD is at version 2.5 or later...
			if ( version_compare( EDD_VERSION, 2.5, '>=' ) ) {
				// Use the previously noted array key as an array key again and next your settings
				$edd_pg_settings = array( 'purchase_gravatars' => $edd_pg_settings );
			}

			return array_merge( $sections, $edd_pg_settings );
		}

	}

}


/**
 * Get everything running
 *
 * @since 1.0
 *
 * @access private
 * @return void
 */
function edd_purchase_gravatars_load() {
	$edd_purchase_gravatars = new EDD_Purchase_Gravatars();
}
add_action( 'plugins_loaded', 'edd_purchase_gravatars_load' );

/**
 * Widget
 *
 * @since 1.0
*/

if ( ! class_exists( 'EDD_Purchase_Gravatars_Widget' ) ) {

	class EDD_Purchase_Gravatars_Widget extends WP_Widget {

		/*
		 * widget constructor
		 */
		function __construct() {

			$edd_label_singular = function_exists('edd_get_label_singular') ? strtolower( edd_get_label_singular() ) : null;

			// widget settings
			$widget_ops = array(
				'classname' => 'purchase-gravatars',
				'description' => sprintf( __( 'Displays gravatars of customers who have purchased your %s. Will only show on the single %s page.', 'edd-pg' ), $edd_label_singular, $edd_label_singular )
			);

			// widget control settings
			$control_ops = array(
				'width'   => 250,
				'height'  => 350,
				'id_base' => 'edd_pg_widget',
			);

			// create the widget
			parent::__construct( 'edd_pg_widget', __( 'EDD Purchase Gravatars', 'edd-pg' ), $widget_ops, $control_ops );

		} // end constructor

		/*
		 * Outputs the content of the widget
		 */
		function widget( $args, $instance ) {
			global $edd_options;

			extract( $args );

			if ( ! is_singular( 'download' ) ) {
				return;
			}

			// Variables from widget settings
			$title = apply_filters( 'widget_title', $instance['title'] );

			// Used by themes. Opens the widget
			echo $before_widget;

			// Display the widget title
			if ( $title ) {
				echo $before_title . $title . $after_title;
			}

			$gravatars = new EDD_Purchase_Gravatars();

			echo $gravatars->gravatars( get_the_ID(), null ); // remove title

			// Used by themes. Closes the widget
			echo $after_widget;

		} // end WIDGET function

		/*
		 * Update function. Processes widget options to be saved
		 */
		function update( $new_instance, $old_instance ) {

			$instance = $old_instance;

			$instance['title'] = strip_tags( $new_instance['title'] );

			return $instance;

		} // end UPDATE function

		/*
		 * Form function. Displays the actual form on the widget page
		 */
		function form( $instance ) {

			// Set up some default widget settings.
			$defaults = array(
				'title' => '',
			);

			$instance = wp_parse_args( (array) $instance, $defaults ); ?>

			<!-- Title -->
			<p>
				<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:', 'edd-pg' ) ?></label>
				<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']; ?>" />
			</p>


		<?php } // end FORM function

	}
}
