File "Lifecycle.php"

Full Path: /home/vantageo/public_html/wp-admin/.wp-cli/wp-content/plugins/facebook-for-woocommerce/includes/Framework/Lifecycle.php
File size: 13.72 KB
MIME-type: text/x-php
Charset: utf-8

<?php
// phpcs:ignoreFile
/**
 * Facebook for WooCommerce.
 */

namespace WooCommerce\Facebook\Framework;

defined( 'ABSPATH' ) or exit;

/**
 * Plugin lifecycle handler.
 *
 * Registers and displays milestone notice prompts and eventually the plugin
 * install, upgrade, activation, and deactivation routines.
 */
class Lifecycle {
	/** @var array the version numbers that have an upgrade routine */
	protected $upgrade_versions = [];

	/** @var string minimum milestone version */
	private $milestone_version;

	/** @var Plugin plugin instance */
	private $plugin;

	/**
	 * Constructs the class.
	 *
	 * @since 5.1.0
	 *
	 * @param Plugin $plugin plugin instance
	 */
	public function __construct( Plugin $plugin ) {
		$this->plugin = $plugin;
		$this->add_hooks();
	}


	/**
	 * Adds the action & filter hooks.
	 *
	 * @since 5.1.0
	 */
	protected function add_hooks() {
		// handle activation
		add_action( 'admin_init', array( $this, 'handle_activation' ) );
		// handle deactivation
		add_action( 'deactivate_' . $this->get_plugin()->get_plugin_file(), array( $this, 'handle_deactivation' ) );
		if ( is_admin() && ! wp_doing_ajax() ) {
			// initialize the plugin lifecycle
			add_action( 'wp_loaded', array( $this, 'init' ) );
			// add the admin notices
			add_action( 'init', array( $this, 'add_admin_notices' ) );
		}
		// catch any milestones triggered by action
		add_action( 'wc_' . $this->get_plugin()->get_id() . '_milestone_reached', array( $this, 'trigger_milestone' ), 10, 3 );
	}


	/**
	 * Initializes the plugin lifecycle.
	 *
	 * @since 5.2.0
	 */
	public function init() {
		// potentially handle a new activation
		$this->handle_activation();
		$installed_version = $this->get_installed_version();
		$plugin_version    = $this->get_plugin()->get_version();
		// installed version lower than plugin version?
		if ( version_compare( $installed_version, $plugin_version, '<' ) ) {
			if ( ! $installed_version ) {
				// store the upgrade event regardless if there was a routine for it
				$this->store_event( 'install' );
				/**
				 * Fires after the plugin has been installed.
				 *
				 * @since 5.1.0
				 */
				do_action( 'wc_' . $this->get_plugin()->get_id() . '_installed' );
			} else {
				$this->upgrade( $installed_version );
				// store the upgrade event regardless if there was a routine for it
				$this->add_upgrade_event( $installed_version );
				// if the plugin never had any previous milestones, consider them all reached so their notices aren't displayed
				if ( ! $this->get_milestone_version() ) {
					$this->set_milestone_version( $plugin_version );
				}
				/**
				 * Fires after the plugin has been updated.
				 *
				 * @since 5.1.0
				 *
				 * @param string $installed_version previously installed version
				 */
				do_action( 'wc_' . $this->get_plugin()->get_id() . '_updated', $installed_version );
			}
			// new version number
			$this->set_installed_version( $plugin_version );
		}
	}


	/**
	 * Triggers plugin activation.
	 *
	 * We don't use register_activation_hook() as that can't be called inside
	 * the 'plugins_loaded' action. Instead, we rely on setting to track the
	 * plugin's activation status.
	 *
	 * @internal
	 *
	 * @link https://developer.wordpress.org/reference/functions/register_activation_hook/#comment-2100
	 *
	 * @since 5.2.0
	 */
	public function handle_activation() {
		if ( ! get_option( 'wc_' . $this->get_plugin()->get_id() . '_is_active', false ) ) {
			/**
			 * Fires when the plugin is activated.
			 *
			 * @since 5.2.0
			 */
			do_action( 'wc_' . $this->get_plugin()->get_id() . '_activated' );
			update_option( 'wc_' . $this->get_plugin()->get_id() . '_is_active', 'yes' );
		}
	}


	/**
	 * Triggers plugin deactivation.
	 *
	 * @internal
	 *
	 * @since 5.2.0
	 */
	public function handle_deactivation() {
		/**
		 * Fires when the plugin is deactivated.
		 *
		 * @since 5.2.0
		 */
		do_action( 'wc_' . $this->get_plugin()->get_id() . '_deactivated' );
		delete_option( 'wc_' . $this->get_plugin()->get_id() . '_is_active' );
	}


	/**
	 * Helper method to install default settings for a plugin.
	 *
	 * @since 5.2.0
	 *
	 * @param array $settings settings in format required by WC_Admin_Settings
	 */
	public function install_default_settings( array $settings ) {
		foreach ( $settings as $setting ) {
			if ( isset( $setting['id'], $setting['default'] ) ) {
				update_option( $setting['id'], $setting['default'] );
			}
		}
	}


	/**
	 * Performs any upgrade tasks based on the provided installed version.
	 *
	 * @since 5.2.0
	 *
	 * @param string $installed_version installed version
	 */
	protected function upgrade( $installed_version ) {
		foreach ( $this->upgrade_versions as $upgrade_version ) {
			$upgrade_method = 'upgrade_to_' . str_replace( array( '.', '-' ), '_', $upgrade_version );
			if ( version_compare( $installed_version, $upgrade_version, '<' ) && is_callable( array( $this, $upgrade_method ) ) ) {
				$this->get_plugin()->log( "Starting upgrade to v{$upgrade_version}" );
				$this->$upgrade_method( $installed_version );
				$this->get_plugin()->log( "Upgrade to v{$upgrade_version} complete" );
			}
		}
	}


	/**
	 * Adds any lifecycle admin notices.
	 *
	 * @since 5.1.0
	 */
	public function add_admin_notices() {
		// display any milestone notices
		foreach ( $this->get_milestone_messages() as $id => $message ) {
			// bail if this notice was already dismissed
			if ( ! $this->get_plugin()->get_admin_notice_handler()->should_display_notice( $id ) ) {
				continue;
			}
			/**
			 * Filters a milestone notice message.
			 *
			 * @since 5.1.0
			 *
			 * @param string $message message text to be used for the milestone notice
			 * @param string $id milestone ID
			 */
			$message = apply_filters(
				'wc_' . $this->get_plugin()->get_id() . '_milestone_message',
				$this->generate_milestone_notice_message( $message ), $id
			);
			if ( $message ) {
				$this->get_plugin()
					->get_admin_notice_handler()
					->add_admin_notice( $message, $id, array( 'always_show_on_settings' => false, ) );
				// only display one notice at a time
				break;
			}
		}
	}


	/** Milestone Methods *****************************************************/


	/**
	 * Triggers a milestone.
	 *
	 * This will only be triggered if the install's "milestone version" is lower
	 * than $since. Plugins can specify $since as the version at which a
	 * milestone's feature was added. This prevents existing installs from
	 * triggering notices for milestones that have long passed, like a payment
	 * gateway's first successful payment. Omitting $since will assume the
	 * milestone has always existed and should only trigger for fresh installs.
	 *
	 * @since 5.1.0
	 *
	 * @param string $id milestone ID
	 * @param string $message message to display to the user
	 * @param string $since the version since this milestone has existed in the plugin
	 * @return bool
	 */
	public function trigger_milestone( $id, $message, $since = '1.0.0' ) {
		// if the plugin was had milestones before this milestone was added, don't trigger it
		if ( version_compare( $this->get_milestone_version(), $since, '>' ) ) {
			return false;
		}
		return $this->register_milestone_message( $id, $message );
	}


	/**
	 * Generates a milestone notice message.
	 *
	 * @since 5.1.0
	 *
	 * @param string $custom_message custom text that notes what milestone was completed.
	 * @return string
	 */
	protected function generate_milestone_notice_message( $custom_message ) {
		$message = '';
		if ( $this->get_plugin()->get_reviews_url() ) {
			// to be prepended at random to each milestone notice
			$exclamations = array(
				__( 'Awesome', 'facebook-for-woocommerce' ),
				__( 'Fantastic', 'facebook-for-woocommerce' ),
				__( 'Cowabunga', 'facebook-for-woocommerce' ),
				__( 'Congratulations', 'facebook-for-woocommerce' ),
				__( 'Hot dog', 'facebook-for-woocommerce' ),
			);
			$message = $exclamations[ array_rand( $exclamations ) ] . ', ' . esc_html( $custom_message ) . ' ';
			$message .= sprintf(
				/* translators: Placeholders: %1$s - plugin name, %2$s - <a> tag, %3$s - </a> tag, %4$s - <a> tag, %5$s - </a> tag */
				__( 'Are you having a great experience with %1$s so far? Please consider %2$sleaving a review%3$s! If things aren\'t going quite as expected, we\'re happy to help -- please %4$sreach out to our support team%5$s.', 'facebook-for-woocommerce' ),
				'<strong>' . esc_html( $this->get_plugin()->get_plugin_name() ) . '</strong>',
				'<a href="' . esc_url( $this->get_plugin()->get_reviews_url() ) . '">', '</a>',
				'<a href="' . esc_url( $this->get_plugin()->get_support_url() ) . '">', '</a>'
			);
		}
		return $message;
	}


	/**
	 * Registers a milestone message to be displayed in the admin.
	 *
	 * @since 5.1.0
	 * @see Lifecycle::generate_milestone_notice_message()
	 *
	 * @param string $id milestone ID
	 * @param string $message message to display to the user
	 * @return bool whether the message was successfully registered
	 */
	public function register_milestone_message( $id, $message ) {
		$milestone_messages = $this->get_milestone_messages();
		$dismissed_notices  = array_keys( $this->get_plugin()->get_admin_notice_handler()->get_dismissed_notices() );
		// get the total number of dismissed milestone messages
		$dismissed_milestone_messages = array_intersect( array_keys( $milestone_messages ), $dismissed_notices );
		// if the user has dismissed more than three milestone messages already, don't add any more
		if ( count( $dismissed_milestone_messages ) > 3 ) {
			return false;
		}
		$milestone_messages[ $id ] = $message;
		return update_option( 'wc_' . $this->get_plugin()->get_id() . '_milestone_messages', $milestone_messages );
	}


	/** Event history methods *****************************************************************************************/


	/**
	 * Adds an upgrade lifecycle event.
	 *
	 * @since 5.4.0
	 *
	 * @param string $from_version version upgrading from
	 * @param array $data extra data to add
	 * @return false|int
	 */
	public function add_upgrade_event( $from_version, array $data = [] ) {
		$data = array_merge( array(
			'from_version' => $from_version,
		), $data );
		return $this->store_event( 'upgrade', $data );
	}


	/**
	 * Adds a migration lifecycle event.
	 *
	 * @since 5.4.0
	 *
	 * @param string $from_plugin plugin migrating from
	 * @param string $from_version version migrating from
	 * @param array $data extra data to add
	 * @return false|int
	 */
	public function add_migrate_event( $from_plugin, $from_version = '', array $data = [] ) {
		$data = array_merge( array(
			'from_plugin'  => $from_plugin,
			'from_version' => $from_version,
		), $data );
		return $this->store_event( 'migrate', $data );
	}


	/**
	 * Stores a lifecycle event.
	 *
	 * This can be used to log installs, upgrades, etc...
	 *
	 * Uses a direct database query to avoid cache issues.
	 *
	 * @since 5.4.0
	 *
	 * @param string $name lifecycle event name
	 * @param array $data any extra data to store
	 * @return false|int
	 */
	public function store_event( $name, array $data = [] ) {
		global $wpdb;
		$history = $this->get_event_history();
		$event = array(
			'name'    => wc_clean( $name ),
			'time'    => (int) current_time( 'timestamp' ),
			'version' => wc_clean( $this->get_plugin()->get_version() ),
		);
		if ( ! empty( $data ) ) {
			$event['data'] = wc_clean( $data );
		}
		array_unshift( $history, $event );
		// limit to the last 30 events
		$history = array_slice( $history, 0, 29 );
		return $wpdb->replace(
			$wpdb->options,
			array(
				'option_name'  => $this->get_event_history_option_name(),
				'option_value' => json_encode( $history ),
				'autoload'     => 'no',
			),
			array(
				'%s',
				'%s',
			)
		);
	}


	/**
	 * Gets the lifecycle event history.
	 *
	 * The last 30 events are stored, with the latest first.
	 *
	 * @since 5.4.0
	 *
	 * @return array
	 */
	public function get_event_history() {
		global $wpdb;
		$history = [];
		$results = $wpdb->get_var( $wpdb->prepare( "
			SELECT option_value
			FROM {$wpdb->options}
			WHERE option_name = %s
		", $this->get_event_history_option_name() ) );
		if ( $results ) {
			$history = json_decode( $results, true );
		}
		return is_array( $history ) ? $history : [];
	}


	/**
	 * Gets the event history option name.
	 *
	 * @since 5.4.0
	 *
	 * @return string
	 */
	protected function get_event_history_option_name() {
		return 'wc_' . $this->get_plugin()->get_id() . '_lifecycle_events';
	}


	/** Utility Methods *******************************************************/


	/**
	 * Gets the registered milestone messages.
	 *
	 * @since 5.1.0
	 *
	 * @return array
	 */
	protected function get_milestone_messages() {
		return get_option( 'wc_' . $this->get_plugin()->get_id() . '_milestone_messages', [] );
	}


	/**
	 * Sets the milestone version.
	 *
	 * @since 5.1.0
	 *
	 * @param string $version plugin version
	 * @return bool
	 */
	public function set_milestone_version( $version ) {
		$this->milestone_version = $version;
		return update_option( 'wc_' . $this->get_plugin()->get_id() . '_milestone_version', $version );
	}


	/**
	 * Gets the milestone version.
	 *
	 * @since 5.1.0
	 *
	 * @return string
	 */
	public function get_milestone_version() {
		if ( ! $this->milestone_version ) {
			$this->milestone_version = get_option( 'wc_' . $this->get_plugin()->get_id() . '_milestone_version', '' );
		}
		return $this->milestone_version;
	}


	/**
	 * Gets the currently installed plugin version.
	 *
	 * @since 5.2.0
	 *
	 * @return string
	 */
	protected function get_installed_version() {
		return get_option( $this->get_plugin()->get_plugin_version_name() );
	}


	/**
	 * Sets the installed plugin version.
	 *
	 * @since 5.2.0
	 *
	 * @param string $version version to set
	 */
	protected function set_installed_version( $version ) {
		update_option( $this->get_plugin()->get_plugin_version_name(), $version );
	}


	/**
	 * Gets the plugin instance.
	 *
	 * @return Plugin
	 */
	protected function get_plugin() {
		return $this->plugin;
	}
}