MOON
Server: Apache
System: Linux server.royaltuning.hu 4.18.0-425.13.1.el8_7.x86_64 #1 SMP Tue Feb 21 04:20:52 EST 2023 x86_64
User: royaltuning (1001)
PHP: 8.2.31
Disabled: exec,passthru,shell_exec,system
Upload Files
File: /home/royaltuning/www/public/wp-content/plugins/vp-woo-review-reminder/index.php
<?php
/*
Plugin Name: VP Review Reminder E-mails for WooCommerce
Plugin URI: http://visztpeter.me
Description: Send automatic e-mails to your customers to collect reviews
Author: Viszt Péter
Version: 1.0.3
Text Domain: vp-woo-review-reminder
Domain Path: /languages/
Update URI: vp-woo-review-reminder
*/

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

class VP_Woo_Review_Reminder {
	protected static $_instance = null;
	public static $version;
	public static $plugin_path;

	//Get main instance
	public static function instance() {
		if ( is_null( self::$_instance ) ) {
			self::$_instance = new self();
		}
		return self::$_instance;
	}

	//Construct
	public function __construct() {

		//Check for updates
		self::$version = '1.0.3';
		self::$plugin_path = trailingslashit(dirname(__FILE__));
		require_once( plugin_dir_path( __FILE__ ) . 'class-vp.php' );
		$update = new VP_Update_Checker('vp-woo-review-reminder', 'admin.php?page=wc-settings&tab=email&section=vp_woo_review_reminder_email');

		//Add settings field
		add_filter( 'woocommerce_get_settings_products', array( $this, 'add_settings' ), 10, 2 );

		//Load plugin
		add_action( 'plugins_loaded', array( $this, 'init' ) );
		add_filter( 'woocommerce_email_classes', array( $this, 'register_email' ), 90, 1 );

		//Create action to send review reminder manually from order actions dropdown
		add_filter( 'woocommerce_order_actions', array($this, 'send_email_manually'));
		add_action( 'woocommerce_order_action_send_review_reminder', array($this, 'send_reminder_manually'));

		//Process submitted review(from the e-mail embedded form and on-site)
		add_action( 'template_redirect', array($this, 'process_email_review') );
		add_action( 'template_redirect', array($this, 'process_product_page_review') );

		//Schedule e-mail
		add_action( 'woocommerce_order_status_completed', array($this, 'schedule_email'), 10, 1 );

		//Function to run for scheduled async jobs
		add_action('vp_woo_review_reminder_email', array($this, 'send_reminder_email'), 10, 2);

		//Frontend assets
		add_action( 'wp_enqueue_scripts', array( $this, 'frontend_assets' ));

		//Show image upload form
		add_shortcode( 'vp_review_image', array($this, 'image_uploader_shortcode') );

		//Handle image upload via ajax
		add_action( 'wp_ajax_vp_woo_review_reminder_upload_image', array($this, 'file_upload_callback'));
		add_action( 'wp_ajax_nopriv_vp_woo_review_reminder_upload_image', array($this, 'file_upload_callback'));

		//Redirect normal review to thank you page
		add_action( 'comment_post', array( $this, 'add_review_token' ), 1 );
		add_filter( 'comment_post_redirect', array($this, 'redirect_after_normal_review'), 10, 2 );

		//Show image in admin
		add_filter( 'woocommerce_product_reviews_table_column_comment_content', array($this, 'show_image_in_reviews_admin'), 10, 2 );

		//Display image on product page review
		add_action( 'woocommerce_review_after_comment_text', array( $this, 'show_image_in_product_page'));

		//Custom shortcode to display reviews
		add_shortcode( 'vp_reviews_grid', array($this, 'reviews_grid_shortcode') );

		//Bulk actions
		add_filter( 'bulk_actions-edit-shop_order', array( $this, 'add_bulk_options'), 20, 1);
		add_filter( 'handle_bulk_actions-edit-shop_order', array( $this, 'handle_bulk_actions'), 10, 3 );
		add_filter( 'bulk_actions-woocommerce_page_wc-orders', array( $this, 'add_bulk_options'), 20, 1 );
		add_filter( 'handle_bulk_actions-woocommerce_page_wc-orders', array( $this, 'handle_bulk_actions'), 10, 3 );
		add_action( 'admin_notices', array( $this, 'bulk_actions_results') );

	}

	//Frontend CSS & JS if we are on the thank you page
	public function frontend_assets() {
		global $post;

		if ( is_product() || ( ! empty( $post->post_content ) && strstr( $post->post_content, '[vp_review' ) ) ) {
			$css_deps = array();
			$js_deps = array('jquery');

			if ( current_theme_supports( 'wc-product-gallery-lightbox' ) ) {
				$css_deps = array('photoswipe-default-skin');
				$js_deps = array('jquery', 'photoswipe', 'photoswipe-ui-default');		
				add_action( 'wp_footer', 'woocommerce_photoswipe' );
			}

			wp_enqueue_style( 'vp_woo_review_reminder_frontend_css', plugins_url( '/assets/css/frontend.css',__FILE__ ), $css_deps, VP_Woo_Review_Reminder::$version );
			wp_enqueue_script( 'vp_woo_review_reminder_frontend_js', plugins_url( '/assets/js/frontend.min.js',__FILE__ ), $js_deps, VP_Woo_Review_Reminder::$version );
	
			$script_data = array(
				'ajaxurl' => admin_url( 'admin-ajax.php' ),
				'supports_photoswipe' => current_theme_supports( 'wc-product-gallery-lightbox' )
			);
			wp_localize_script( 'vp_woo_review_reminder_frontend_js', 'vp_woo_review_reminder_params', $script_data );
		}

	}

	public function add_settings($settings, $current_section) {
		$setting_field = array(
			'id' => 'vp_woo_review_reminder_redirect',
			'title'    => __( 'Thank you page', 'vp-woo-review-reminder' ),
			'desc'	   => __('Customer will be redirected to this page after the review has been submitted. Use the [vp_review_image] shortcode to show an additional image upload interface on this page, so the customer can upload an image after they left a review.', 'vp-woo-review-reminder'),
			'type'     => 'single_select_page_with_search',
			'default'  => '',
			'class'    => 'wc-page-search',
			'css'      => 'min-width:300px;',
			'args'     => array(
				'exclude' =>
					array(
						wc_get_page_id( 'cart' ),
						wc_get_page_id( 'myaccount' ),
						wc_get_page_id( 'checkout' ),
					),
			),
			'autoload' => false,
			'desc_tip' => true
		);

		$index = array_search('woocommerce_review_rating_required', array_column($settings, 'id'));
		if ($index !== false) {
			array_splice($settings, $index + 1, 0, array($setting_field));
		}

		return $settings;		
	}

	public function register_email( $emails ) {
		require_once 'class-email.php';
		$emails['VP_Woo_Review_Reminder_Email'] = new VP_Woo_Review_Reminder_Email();
		return $emails;
	}

  	public function init() {

		//Load translations
		load_plugin_textdomain( 'vp-woo-review-reminder', false, basename( dirname( __FILE__ ) ) . '/languages/' );

	}

	public function send_email_manually($actions) {
		$actions['send_review_reminder'] = __( 'Ask for review', 'vp-woo-review-reminder' );
		return $actions;
	}


	public function send_reminder_manually($order) {
		$order_items = $order->get_items();
		foreach ( $order_items as $item_id => $item ) {
			$product = $item->get_product();
			if($product) {
				WC()->mailer()->emails['VP_Woo_Review_Reminder_Email']->trigger( $order->get_id(), $order, $product );
			}
		}
	}

	public function process_email_review() {
		if ( isset( $_GET['vp_review_order'] ) ) {

			// Get the submitted data
			$rating_indicator = isset( $_GET['vp_review_rating'] ) ? intval( $_GET['vp_review_rating'] ) : 5;
			$order_key = isset( $_GET['vp_review_order'] ) ? sanitize_text_field( $_GET['vp_review_order'] ) : '';
			$review_message = isset( $_GET['vp_review_message'] ) ? wp_kses_post( $_GET['vp_review_message'] ) : '';
			$product_id = get_queried_object_id();
			$order_id = wc_get_order_id_by_order_key($order_key);

			//If order or product not found, just bail
			if(!$order_id || !$product_id) return;

			//Get order and product
			$order = wc_get_order($order_id);
			$product = wc_get_product($product_id);

			//If order or product not found, just bail
			if(!$order || !$product) return;

			//Just to verify, make sure product is in the order
			if(!$this->is_product_in_order($product_id, $order)) return;

			//Check if user already had a review
			if($this->is_user_reviewed_product($order, $product_id)) {
				wc_add_notice( __('You’ve already submitted a review for this product', 'vp-woo-review-reminder'), 'notice' );
        		return;
			}

			//Create review
			$token = wp_generate_password(12, false);
			$review = array(
				'comment_post_ID'      => $product_id,
				'comment_author'       => $order->get_billing_first_name(),
				'comment_author_email' => $order->get_billing_email(),
				'comment_content'      => $review_message,
				'comment_type'         => 'review',
				'comment_approved'     => 1,
				'comment_meta'		   => array(
					'rating' => $rating_indicator,
					'verified' => true,
					'_vp_woo_review_token' => $token
				)
			);

			//Set customer id if it was a register customer
			if($order->get_customer_id()) {
				$review['user_id'] = $order->get_customer_id();
			}

			//Save review
			$review_id = wp_insert_comment($review);

			//And redirect user to the success page if set, if not, just to the product page
			$redirect = get_option('vp_woo_review_reminder_redirect');
			if($redirect && get_post($redirect)) {
				$url = add_query_arg( array(
					'vp_review_token' => $token
				), get_permalink($redirect) );
				wp_redirect( $url );
				exit;
			} else {
				wc_add_notice( __('Thank you for your feedback!', 'vp-woo-review-reminder'), 'success' );
				wp_redirect( $product->get_permalink() );
				exit;
			}

		}
	}

	public function process_product_page_review() {
		if ( isset( $_GET['vp_review_email_link'] ) && is_product()) {
			$order_key = isset( $_GET['vp_review_email_link'] ) ? sanitize_text_field( $_GET['vp_review_email_link'] ) : '';
			$order_id = wc_get_order_id_by_order_key($order_key);
			$product_id = get_queried_object_id();

			//If order or product not found, just bail
			if(!$order_id) return;

			//Get order and product
			$order = wc_get_order($order_id);
			$product = wc_get_product($product_id);

			//If order or product not found, just bail
			if(!$order || !$product) return;
			
			//Just to verify, make sure product is in the order
			if(!$this->is_product_in_order($product_id, $order)) return;

			//Check if user already had a review
			if($this->is_user_reviewed_product($order, $product_id)) {
				wc_add_notice( __('You’ve already submitted a review for this product', 'vp-woo-review-reminder'), 'notice' );
				return;
			}

			//Get e-mail template as a website
			$email = WC()->mailer()->emails['VP_Woo_Review_Reminder_Email'];
			$email->website = true;
			$email->trigger( $order->get_id(), $order, $product );
			$email_template = $email->get_content_html();
			$message = apply_filters( 'woocommerce_mail_content', $email->style_inline( $email_template ) );
			echo $message;
			exit;
		}
	}

	public function is_product_in_order($product_id, $order) {
		//Get a list of product id's in the order
		$products_in_order = array();
		foreach($order->get_items() as $order_item) {
			if($order_item->get_product_id()) {
				$products_in_order[] = $order_item->get_product_id();
			}
		}

		return (in_array($product_id, $products_in_order));
	}

	public function is_user_reviewed_product($order, $product_id) {
		$args = array(
			'post_type' => 'product',
			'author_email' => $order->get_billing_email(),
			'post_id' => $product_id,
			'status' => 'approve',
		);
	
		$existing_reviews = get_comments($args);
		if (!empty($existing_reviews)) {
			return true;
		}

		return false;
	}

	public function schedule_email($order_id) {
		$order = wc_get_order($order_id);
		$order_items = $order->get_items();
		$email = WC()->mailer()->emails['VP_Woo_Review_Reminder_Email'];
		foreach ( $order_items as $item_id => $item ) {
			$product = $item->get_product();
			if($product && $email->is_enabled()) {

				//Get sending delay(days)
				$delay = $email->get_option('delay', 5);

				//Create scheduled action
				WC()->queue()->schedule_single(
					time() + DAY_IN_SECONDS*$delay,
					'vp_woo_review_reminder_email',
					array(
						'order_id' => $order_id,
						'product_id' => $product->get_id()
					),
					'vp-woo-review-reminder'
				);

			}
		}
	}

	public function send_reminder_email($order_id, $product_id) {

		//Get order and product
		$order = wc_get_order($order_id);
		$product = wc_get_product($product_id);
		
		//If order or product not found, just bail
		if(!$order || !$product) return;

		//Check if already sent a review, in this case we can stop
		if($this->is_user_reviewed_product($order, $product_id)) {
			return;
		}

		//Check if email is still enabled
		$email = WC()->mailer()->emails['VP_Woo_Review_Reminder_Email'];
		
		if(!$email->is_enabled()) {
			return;
		}

		//Send email
		$email->trigger( $order->get_id(), $order, $product );

	}

	public function image_uploader_shortcode() {
		ob_start();

		$review_token = isset( $_GET['vp_review_token'] ) ? sanitize_text_field( $_GET['vp_review_token'] ) : false;
		if(!$review_token) return '';

		//Try to get review and order
		$review = $this->get_review_by_token( $review_token ); 
		
		//Check if they exists
		if(!$review) {
			return '';
		}

		?>
		<form class="vp-woo-review-reminder-image-uploader">
			<div class="vp-woo-review-reminder-image-uploader-form">
				<label for="vp-woo-review-image">
					<span class="vp-woo-review-reminder-image-uploader-icon">📷</span>
					<strong class="vp-woo-review-reminder-image-uploader-text"><?php esc_html_e('Choose a photo or drag it here', 'vp-woo-review-reminder'); ?></strong>
				</label>
				<input type="file" id="vp-woo-review-image" accept="image/*">
			</div>
			<div class="vp-woo-review-reminder-image-uploader-results">
				<div class="vp-woo-review-reminder-image-uploader-results-image">
					
				</div>
				<div class="vp-woo-review-reminder-image-uploader-results-text">
					<p><?php esc_html_e('Thank you for your review! Once approved, your image will appear on the product page.', 'vp-woo-review-reminder'); ?></p>
					<p><a href="#" class="vp-woo-review-reminder-image-uploader-reset"><?php esc_html_e('Select a different image.', 'vp-woo-review-reminder'); ?></a>					
				</div>
			</div>
			<input type="hidden" name="review_token" value="<?php echo esc_attr($review_token); ?>">
			<input type="hidden" name="action" value="vp_woo_review_reminder_upload_image">
			<input type="hidden" name="security" value="<?php echo esc_attr(wp_create_nonce( 'vp_woo_review_reminder_image_upload' )); ?>">
		</form>
		<?php
		return ob_get_clean();	
	}

	public function file_upload_callback() {
		check_ajax_referer('vp_woo_review_reminder_image_upload', 'security');
		$arr_img_ext = array('image/png', 'image/jpeg', 'image/jpg');

		//Check if an image was submitted
		if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
			wp_send_json_error(array(
				'message' => __('Please select an image to upload.', 'vp-woo-review-reminder'),
				'code' => 'missing_image'
			));
		}

		//Get comment data(post is the product we are leaving a review for)
		$review_token = isset( $_POST['review_token'] ) ? sanitize_text_field( $_POST['review_token'] ) : false;

		//If parameters not set
		if(!$review_token) {
			wp_send_json_error(array(
				'message' => __('Missing parameters.', 'vp-woo-review-reminder'),
				'code' => 'missing_parameters'
			));
		}

		//Try to get review and order
		$review = $this->get_review_by_token( $review_token ); 
		
		//Check if they exists
		if(!$review) {
			wp_send_json_error(array(
				'message' => __('Review not found.', 'vp-woo-review-reminder'),
				'code' => 'review_not_found'
			));
		}

		//Parse submitted image
		if (in_array($_FILES['image']['type'], $arr_img_ext)) {

			//Create a custom file name
			$original_file_name = $_FILES["image"]["name"];
			$file_extension = pathinfo($original_file_name, PATHINFO_EXTENSION);
			$custom_file_name = 'review-'.$review->comment_ID.'-'.$review->comment_post_ID.'.'.$file_extension;

			//Upload file
			$upload = wp_upload_bits( $custom_file_name, null, file_get_contents( $_FILES["image"]["tmp_name"] ) );
			if ( ! $upload['error'] ) {

				//Set it up as an attahcment
				$filename = $upload['file'];
				$wp_filetype = wp_check_filetype( $filename, null );
				$attachment = array(
					'post_mime_type' => $wp_filetype['type'],
					'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
					'post_content' => '',
					'post_status' => 'inherit'
				);
	 
				//And Save it to the media library too, so its easier to manage and we have nice thumbnails generated
				$attachment_id = wp_insert_attachment( $attachment, $filename );
				if ( ! is_wp_error( $attachment_id ) ) {
					require_once(ABSPATH . 'wp-admin/includes/image.php');
					$attachment_data = wp_generate_attachment_metadata( $attachment_id, $filename );
					wp_update_attachment_metadata( $attachment_id, $attachment_data );
				}

				//And pair the attachment id with our review
				update_comment_meta($review->comment_ID, '_vp_woo_review_image', $attachment_id);

				//In this case, set the review to pending approval just in case
				wp_set_comment_status($review->comment_ID, 'hold');

				//And return the uploaded image
				$uploaded_image = wp_get_attachment_image_src($attachment_id, 'large');
				wp_send_json_success(array(
					'image' => $uploaded_image[0]
				));

			} else {
				wp_send_json_error(array(
					'message' => __('Unable to upload image.', 'vp-woo-review-reminder'),
					'code' => 'upload_error',
					'error' => $upload['error']
				));
			}
		} else {

			//Wrong format
			wp_send_json_error(array(
				'message' => __('Wrong file format. Please try to upload a different image.', 'vp-woo-review-reminder'),
				'code' => 'wrong_format',
			));

		}
	}

	public function add_review_token($comment_id) {
		if ( isset( $_POST['comment_post_ID'] ) && 'product' === get_post_type( absint( $_POST['comment_post_ID'] ) ) ) {
			$token = wp_generate_password(12, false);
			add_comment_meta( $comment_id, '_vp_woo_review_token', $token, true );
		}
	}

	public function redirect_after_normal_review($location, $comment) {
		$redirect = get_option('vp_woo_review_reminder_redirect');
		if ($redirect && 'product' === get_post_type($comment->comment_post_ID)) {
			$token = get_comment_meta($comment->comment_ID, '_vp_woo_review_token', true);
			if($token) {
				$location = add_query_arg( array(
					'vp_review_token' => $token
				), get_permalink($redirect) );
			}
		}

		return $location;
	}

	public function get_review_by_token($token) {
		$args = array(
			'meta_key'       => '_vp_woo_review_token',
			'meta_value'     => $token,
			'post_type'      => 'product',
			'post_status'    => 'any',
			'number'         => 1,
		);
		$comments = get_comments($args);
		if (!empty($comments)) {
			return $comments[0];
		} else {
			return false;
		}
	}

	public function show_image_in_reviews_admin($output, $review) {
		$image_id = $this->get_review_image_id($review);
		if($image_id) {
			$uploaded_image = wp_get_attachment_image_src($image_id, 'thumbnail');
			$link = '#';
			if(current_user_can( 'edit_comment', $review->comment_ID )) {
				$link = get_edit_post_link($image_id);
			}
			$output .= '<a href="'.esc_url($link).'" target="_blank"><img style="border-radius:4px;margin-top:10px;" width="64" height="64" src="'.esc_url($uploaded_image[0]).'"></a>';
		}
		return $output;
	}

	public function get_review_image_id($review) {
		$image_id = get_comment_meta( $review->comment_ID, '_vp_woo_review_image', true );
		if($image_id && wp_get_attachment_metadata($image_id)) {
			return $image_id;
		} else {	
			return false;
		}
	}

	public function show_image_in_product_page($review) {
		$image_id = $this->get_review_image_id($review);
		if($image_id) {
			$full = wp_get_attachment_image_src($image_id, 'full');
			echo '<a class="vp-woo-review-image" href="'.esc_url($full[0]).'" data-width="'.$full[1].'" data-height="'.$full[2].'">'.wp_get_attachment_image( $image_id ).'</a>';
		}
	}

	public function show_image_in_blocks($response) {
		if(!is_admin()) {
			print_r($response);
			die();
		}
		return $response;
	}

	public function reviews_grid_shortcode($atts) {
		$atts = shortcode_atts(array(
			'limit' => 10,
			'product_id' => '',
			'only_images' => false,
		), $atts);
		
		$single_product = false;
		$args = array(
			'number' => $atts['limit'],
			'status' => 'approve',
			'post_type' => 'product'
		);

		//If we only need reviews with images
		if($atts['only_images']) {
			$args['meta_key'] = '_vp_woo_review_image';
			$args['meta_compare'] = 'EXISTS';
		}

		//For specific products
		if($atts['product_id']) {
			$product_ids = explode(',', $atts['product_id']);
			$args['post__in'] = $product_ids;
			$single_product = true;
		}

		//Get results
		$reviews = get_comments($args);

		ob_start();
		wc_get_template('reviews-grid.php', array(
			'reviews' => $reviews,
			'single_product' => $single_product
		), false, VP_Woo_Review_Reminder::$plugin_path . '/templates/');
		return ob_get_clean();
	}


	public function add_bulk_options( $actions ) {
		$actions['vp_woo_review_reminder_send'] = __('Send Review Reminders', 'vp-woo-review-reminder');
		return $actions;
	}

	public function handle_bulk_actions( $redirect_to, $action, $post_ids ) {
		if( $action == 'vp_woo_review_reminder_send' ) {
			$processed = array();

    		// Loop through each selected order and call the send_reminder_manually() function
			foreach ( $post_ids as $order_id ) {
				$order = wc_get_order($order_id);
				$this->send_reminder_manually($order);
				$processed[] = $order_id;
			}
			
			$redirect_to = add_query_arg( array('vp_woo_review_reminder_send' => count($processed)), $redirect_to );
			return $redirect_to;

		} else {
			return $redirect_to;
		}

	}

	public function bulk_actions_results() {
		if(isset($_REQUEST['vp_woo_review_reminder_send'])) {
			$review_count = intval( $_REQUEST['vp_woo_review_reminder_send'] );
			?>
			<div class="notice notice-info vp-woo-pont-notice vp-woo-pont-bulk-actions vp-woo-pont-print">
				<p>
					<span><?php echo sprintf( esc_html__( 'Review reminders sent out for %1$s order(s) successfully.', 'vp-woo-review-reminder' ), $review_count); ?></span>
				</p>
			</div>
			<?php
		}
	}

}

//WC Detection
if ( ! function_exists( 'is_woocommerce_active' ) ) {
	function is_woocommerce_active() {
		$active_plugins = (array) get_option( 'active_plugins', array() );

		if ( is_multisite() ) {
			$active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins', array() ) );
		}

		return in_array( 'woocommerce/woocommerce.php', $active_plugins ) || array_key_exists( 'woocommerce/woocommerce.php', $active_plugins ) ;
	}
}


//WooCommerce inactive notice.
function vp_woo_review_reminder_notice() {
	if ( current_user_can( 'activate_plugins' ) ) {
		echo '<div id="message" class="error"><p>';
		printf( __( '%1$sThe VP Review Reminder E-mails for WooCommerce extension is inactive%2$s. You need to install and enable %3$sWooCommerce%4$s first. %5$sPlease install and turn on WooCommerce &raquo;%6$s', 'vp-woo-user-guide' ), '<strong>', '</strong>', '<a href="http://wordpress.org/extend/plugins/woocommerce/">', '</a>', '<a href="' . esc_url( admin_url( 'plugins.php' ) ) . '">', '</a>' );
		echo '</p></div>';
	}
}

//Initialize
if ( is_woocommerce_active() ) {
	function VP_Woo_Review_Reminder() {
		return VP_Woo_Review_Reminder::instance();
	}

	//For backward compatibility
	$vp_woo_review_reminder = VP_Woo_Review_Reminder();
} else {
	add_action( 'admin_notices', 'vp_woo_review_reminder_notice' );
}