File: /var/www/html/ielts-store/wp-content/plugins/woocommerce-zapier/legacy/Feed/Feed.php
<?php
namespace OM4\Zapier\Feed;
use Exception;
use OM4\Zapier\Feed\FeedFactory;
use OM4\Zapier\Logger;
use OM4\Zapier\Plugin;
use OM4\Zapier\Trigger\Base;
use OM4\Zapier\Trigger\TriggerFactory;
use WP_Post;
defined( 'ABSPATH' ) || exit;
/**
 * Represents a single Zapier Feed.
 * One or more Zapier Feeds are configured via the user and stored in the WordPress installation.
 * They define which Zapier webhook URL should be contacted once the specified Zapier Trigger occurs.
 *
 * @deprecated 2.0.0
 */
class Feed {
	/**
	 * The Post ID of this Zapier Feed.
	 *
	 * @var int
	 */
	private $id;
	/**
	 * WP_Post instance.
	 *
	 * @var WP_Post
	 */
	private $post;
	/**
	 * The title/name of this Zapier Feed.
	 *
	 * @var string
	 */
	private $title;
	/**
	 * The Zapier Trigger that this Zapier Feed applies to.
	 *
	 * @var Base
	 */
	private $trigger;
	/**
	 * The Webhook URL.
	 *
	 * @var string
	 */
	private $webhook_url;
	/**
	 * Whether or not this Zapier Feed is active
	 *
	 * @var bool
	 */
	private $is_active = false;
	/**
	 * Regular Expression used to validate a Webhook URL.
	 *
	 * Valid webhook examples:
	 * - https://zapier.com/hooks/catch/n/abcdef/ (For Zaps created before April 2014)
	 * - https://zapier.com/hooks/catch/fvc2n/ (For Zaps created between April 2014 and March 2016)
	 * - https://zapier.com/hooks/catch/12345/abcdef/ (For Zaps created from March 2016 onwards)
	 */
	const WEBHOOK_URL_REGEXP = '#^https://(hooks\.)?zapier\.com\/hooks\/catch(\/n)?\/([a-z0-9]+)\/([a-z0-9]+\/)?\z#';
	/**
	 * Example Zapier Webhook URL. Displayed in the Dashboard.
	 */
	const WEBHOOK_URL_EXAMPLE = 'https://hooks.zapier.com/hooks/catch/12345/abcdef/';
	/**
	 * Loads an existing Zapier Feed if its ID is specified
	 *
	 * @param null|int|object $id Post ID or post object.
	 */
	public function __construct( $id = null ) {
		if ( ! empty( $id ) ) {
			$this->load( $id );
		}
	}
	/**
	 * Load the feed from the WordPress database
	 *
	 * @param int|object $id Post ID or post object.
	 *
	 * @return void
	 */
	public function load( $id ) {
		$post = get_post( $id );
		if ( is_null( $post ) || 'wc_zapier_feed' !== $post->post_type ) {
			return;
		}
		$this->post = $post;
		$this->populate_from_post_object();
	}
	/**
	 * Populate the class properties based on the WordPress WP_Post object.
	 *
	 * @return void
	 */
	private function populate_from_post_object() {
		try {
			$this->id = $this->post->ID;
			$this->set_title( $this->post->post_title );
			$this->set_webhook_url( $this->post->post_excerpt, false );
			$this->set_active( isset( $this->post->post_status ) && 'publish' === $this->post->post_status );
			// Do this last in case the trigger is invalid.
			if ( ! empty( $this->post->post_content ) ) {
				// Attempt to sanitize post_content if other plugin modified it.
				// See Issue #204.
				preg_match( '/^wc\.[a-z_]+/', $this->post->post_content, $matches );
				if ( $this->post->post_content !== $matches[0] ) {
					$msg = sprintf(
						'Altered trigger key: "%s" in Feed "%s" (%s)',
						$this->post->post_content,
						$this->post->post_title,
						$this->post->ID
					);
					( new Logger() )->notice( $msg );
					$this->post->post_content = $matches[0];
				}
				$this->set_trigger( TriggerFactory::get_trigger_with_key( $this->post->post_content ) );
			}
		} catch ( Exception $ex ) {
			$msg = sprintf(
				'No trigger for key: "%s" found in Feed "%s" (%s)',
				$this->post->post_content,
				$this->post->post_title,
				$this->post->ID
			);
			( new Logger() )->debug( $msg );
		}
	}
	/**
	 * Obtain an array representing this feed's properties.
	 * Used when inserting/updating the Feed details into the WordPress database.
	 *
	 * @return array
	 */
	private function get_array_from_properties() {
		$data = array(
			'post_title'   => $this->title(),
			'post_content' => empty( $this->trigger ) ? '' : $this->trigger->get_trigger_key(),
			'post_excerpt' => $this->webhook_url(),
			'post_status'  => $this->is_active() ? 'publish' : 'draft',
			'post_type'    => 'wc_zapier_feed',
		);
		if ( $this->id ) {
			$data['ID'] = $this->id;
		}
		return $data;
	}
	/**
	 * The ID of this Zapier Feed.
	 *
	 * @return int
	 */
	public function id() {
		return $this->id;
	}
	/**
	 * The Title/Name of this Zapier Feed.
	 *
	 * @return string
	 */
	public function title() {
		return $this->title;
	}
	/**
	 * The Trigger for this Zapier Feed.
	 *
	 * @return Base
	 */
	public function trigger() {
		return $this->trigger;
	}
	/**
	 * The webhook URL of this Zapier Feed.
	 *
	 * @return string
	 */
	public function webhook_url() {
		return $this->webhook_url;
	}
	/**
	 * Whether or not this Zapier Feed is active.
	 *
	 * @return bool
	 */
	public function is_active() {
		return $this->is_active;
	}
	/**
	 * Set the Title/Name of this Zapier Feed.
	 *
	 * @param string $title Name to set.
	 *
	 * @return bool
	 */
	public function set_title( $title ) {
		$this->title = trim( (string) $title );
		return true;
	}
	/**
	 * Set the Trigger for this Zapier Feed.
	 *
	 * @param Base $trigger Name to set.
	 *
	 * @return bool
	 */
	public function set_trigger( Base $trigger ) {
		$this->trigger = $trigger;
		return true;
	}
	/**
	 * Set the Trigger for this Zapier Feed using a trigger key (rather than a Trigger object)
	 *
	 * @param string $trigger_key The trigger key.
	 *
	 * @return boolean
	 * @throws Exception If trigger not found.
	 */
	public function set_trigger_with_key( $trigger_key ) {
		if ( TriggerFactory::trigger_exists( $trigger_key ) ) {
			$this->trigger = TriggerFactory::get_trigger_with_key( $trigger_key );
			return true;
		}
		$this->trigger = null;
		return false;
	}
	/**
	 * Set the webhook URL for this Zapier Feed.
	 *
	 * Validation occurs to make sure only a valid Webhook URL can be specified.
	 *
	 * @param string  $webhook_url The URL of the webhook.
	 * @param boolean $validate Whether or not to validate the URL. Defaults to true.
	 *
	 * @return boolean
	 */
	public function set_webhook_url( $webhook_url, $validate = true ) {
		$webhook_url = trim( (string) $webhook_url );
		if ( $validate ) {
			// Ensure the specified webhook URL matches our expected format.
			if ( self::is_valid_webhook_url( $webhook_url ) ) {
				$this->webhook_url = $webhook_url;
				return true;
			} else {
				$this->webhook_url = '';
			}
		} else {
			// No need to validate/check the webhook URL.
			$this->webhook_url = $webhook_url;
			return true;
		}
		return false;
	}
	/**
	 * Set this Zapier Feed as active or inactive.
	 *
	 * @param boolean $active Whether this feed is active or not.
	 *
	 * @return void
	 */
	public function set_active( $active = true ) {
		$this->is_active = (bool) $active;
	}
	/**
	 * Ensure that this feed is valid.
	 *
	 * If it isn't valid, ensure it cannot be published.
	 *
	 * @return boolean|array True if valid, array of validation errors/warnings on failure
	 */
	public function validate() {
		$validation = array(
			'errors'   => array(),
			'warnings' => array(),
		);
		// If the Feed's title is empty, automatically set the Feed's title to match the name of the chosen trigger.
		if ( empty( $this->title ) && ! is_null( $this->trigger ) ) {
			$this->title = $this->trigger()->get_trigger_title();
		}
		if ( empty( $this->title ) ) {
			$validation['errors'][] = __( '<strong>Title:</strong> A title is required.', 'woocommerce-zapier' );
		}
		// Ensure unique title.
		if ( FeedFactory::get_number_of_feeds_with_title( $this->title, $this ) ) {
			$validation['errors'][] = __( '<strong>Title:</strong> Another Zapier Feed with this title already exists. Please choose a unique Title.', 'woocommerce-zapier' );
		}
		if ( ! $this->is_valid_trigger() ) {
			$validation['errors'][] = __( 'Invalid Trigger.', 'woocommerce-zapier' );
		}
		if ( empty( $this->webhook_url ) ) {
			// Translators: %s: URL of the example WebbHook.
			$validation['errors'][] = sprintf( __( '<strong>Webhook URL:</strong> Invalid Webhook URL. Zapier Webhook URLs should be in the following format: <code>%s</code>', 'woocommerce-zapier' ), self::WEBHOOK_URL_EXAMPLE );
		}
		if ( $this->webhook_url && ! is_null( $this->trigger ) ) {
			// Ensure unique trigger/webhook_url combination.
			if ( FeedFactory::get_number_of_feeds_with_webhook_url_and_trigger( $this->webhook_url, $this->trigger, $this ) ) {
				$validation['errors'][] = __( 'Another Zapier Feed with this Trigger and Webhook URL already exists.', 'woocommerce-zapier' );
			}
		}
		if ( empty( $validation['errors'] ) && empty( $validation['warnings'] ) ) {
			// The Feed is valid (configured correctly)
			// Send sample data to Zapier so that Zapier know what the data structure is like.
			$result = $this->trigger->send_sample_data_payload( $this );
			if ( true !== $result ) {
				// Translators: %1$s: URL of the Zapier WebbHook. %2$s: Incoming error message. %3$s: URL of the WooCommerce Zapier.
				$validation['errors'][] = sprintf( __( 'There was an error communicating with your Zapier Webhook (%1$s).<br />Error Message: %2$s<br />Please try again, and see <a href="%3$s">here for troubleshooting steps</a>.', 'woocommerce-zapier' ), '<code>' . esc_url( $this->webhook_url() ) . '</code>', '<code>' . esc_html( $result ) . '</code>', esc_url( Plugin::DOCUMENTATION_URL . '#troubleshooting' ) );
			}
		}
		if ( ! empty( $validation['errors'] ) ) {
			// Ensure the feed is in draft status.
			$this->set_active( false );
		} else {
			// Feed is error free.
			return true;
		}
		return $validation;
	}
	/**
	 * Test whether or not the specified Webhook URL is valid.
	 *
	 * @param string $webhook_url The webhook URL to check.
	 *
	 * @return boolean
	 */
	public static function is_valid_webhook_url( $webhook_url ) {
		if ( preg_match( self::WEBHOOK_URL_REGEXP, $webhook_url ) ) {
			return true;
		}
		return false;
	}
	/**
	 * Whether or not this feed has a valid trigger assigned to it.
	 * For example, the feed could contain an invalid trigger if WC
	 * Subscriptions has been deactivated since creating the Feed.
	 *
	 * @return bool
	 */
	public function is_valid_trigger() {
		return ! is_null( $this->trigger );
	}
	/**
	 * The URL that of the Edit Feed screen.
	 *
	 * @return string
	 */
	public function edit_url() {
		// Unfortunately we can't use get_edit_post_link() because it doesn't
		// work during cron because no user is logged in.
		return admin_url( "post.php?post={$this->id}&action=edit" );
	}
	/**
	 * Save this Zapier feed to the database.
	 *
	 * @return bool
	 */
	public function save() {
		$result = null;
		if ( is_a( $this->post, 'WP_Post' ) ) {
			// The post could be an auto-draft (for a newly created Zapier Feed), or
			// The post could be an existing Zapier Feed.
			$result = wp_update_post( $this->get_array_from_properties(), true );
		} else {
			// No post yet. Unlikely, but possible.
			$result = wp_insert_post( $this->get_array_from_properties(), true );
		}
		if ( is_wp_error( $result ) || ! $result ) {
			( new Logger() )->error( $result->get_error_message() );
			return false;
		} else {
			// Success
			// Re-load the new feed data in case it has somehow changed.
			$this->load( $result );
			return true;
		}
	}
}