File "SWP_Notice.php"

Full Path: /home/bfxleof/www/wp-content/plugins/social-warfare/lib/utilities/SWP_Notice.php
File size: 11.42 KB
MIME-type: text/x-php
Charset: utf-8

<?php

/**
 * SWP_Notice
 *
 * A class to control the creation and display of admin notices throughout the
 * WordPress dashboard and on the Social Warfare settings page. This class also
 * creates the framework and functionality for both permanently and temporarily
 * dismissing these notices. It also allows for creating start dates, end dates,
 * and various types of calls-to-actions used to dismiss these notices.
 *
 * @package   SocialWarfare\Utilities
 * @copyright Copyright (c) 2018, Warfare Plugins, LLC
 * @license   GPL-3.0+
 * @since     3.0.9 | 07 JUN 2018 | Created
 * @access    public
 *
 */
class SWP_Notice {
	public static $notice_keys = array();

	/**
	 * The Magic __construct method
	 *
	 * This method will initialize our notice object and then add the necessary hooks to
	 * allow it to be displayed and to be dismissed via admin-ajax.php.
	 *
	 * @since 3.0.9 | 07 JUN 2018 | Created
	 * @param string $key     A unique key for this notice.
	 * @param string $message The message for this notice
	 *
	 */
	public function __construct( $key = "", $message = "", $ctas = array() ) {
		$this->set_key( $key );
		$this->init();
		$this->set_message( $message );
		$this->actions = $ctas;
		$this->no_cta = false;

		// Add hooks to display our admin notices in the dashbaord and on our settings page.
		add_action( 'admin_notices', array( $this, 'print_HTML' ) );
		add_action( 'swp_admin_notices', array( $this, 'get_HTML' ) );

		// Add a hook for permanently dismissing a notice via admin-ajax.php
		add_action( 'wp_ajax_dismiss', array( $this, 'dismiss' ) );
		add_action( 'wp_ajax_nopriv_dismiss', array( $this, 'dismiss' ) );

	}


	/**
	 * Initialize the basics of this property.
	 *
	 * This method checks for the dismissed_notices options array in the database.
	 * If it doesn't exist, it creates it as an empty array. It then stores that
	 * array in a local property to control the display or non-display of this
	 * notice. It then finds the attributes for this specific notice and stores it
	 * in the local $data property.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  null
	 * @return null
	 *
	 */
	public function init() {
		$notices = get_option( 'social_warfare_dismissed_notices', false );

		if ( false === $notices ) {
			update_option( 'social_warfare_dismissed_notices', array() );
			$notices = array();
		}

		$this->notices = $notices;

		if ( isset( $notices[$this->key] ) ) :
			$this->data = $notices[$this->key];
		endif;
	}


	/**
	 * A method to determine if this notice should be displayed.
	 *
	 * This method lets the class now if this notice should be displayed or not. It checks
	 * thing like the start date, the end date, the dimissal status if it was temporarily
	 * dismissed versus permanently dismissed and so on.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  null
	 * @return bool Default true.
	 *
	 */
	public function should_display_notice() {
		$now = new DateTime();
		$now = $now->format('Y-m-d H:i:s');

		// If the start date has not been reached.
		if ( isset( $this->start_date ) && $now < $this->start_date ) {
			return false;
		}

		// If the end date has been reached.
		if( isset( $this->end_date ) && $now > $this->end_date ) {
			return false;
		}

		//* No dismissal has happened yet.
		if ( empty( $this->data['timestamp']) ) :
			return true;
		endif;

		//* They have dismissed a permadismiss.
		if ( isset( $this->data['timestamp'] ) && $this->data['timeframe'] == 0) {
			return false;
		}

		//* They have dismissed with a temp CTA.
		if ( isset( $this->data['timeframe'] ) && $this->data['timeframe'] > 0 ) {

			$expiry = $this->data['timestamp'];

			return $now > $expiry;
		}

		return true;
	}


	/**
	 * Processes notice dismissals via ajax.
	 *
	 * This is the method that is added to the Wordpress admin-ajax hooks.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  null
	 * @return null The response from update_option is echoed.
	 *
	 */
	public function dismiss() {

		SWP_Utility::auth();

		$key = $_POST['key'];
		$timeframe = $_POST['timeframe'];
		$now = new DateTime();

		if ( 0 < $timeframe ) {
			$timestamp = $now->modify("+$timeframe days")->format('Y-m-d H:i:s');
		} else {
			$timestamp = $now->format('Y-m-d H:i:s');
		}

		$this->notices[$key]['timestamp'] = $timestamp;
		$this->notices[$key]['timeframe'] = $timeframe;

		echo json_encode( update_option( 'social_warfare_dismissed_notices', $this->notices ) );
		wp_die();
	}


	/**
	 * A method to allow you to set the message text for this notice.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  string $message A string of text for the notices message.
	 * @return object $this    Allows for method chaining.
	 *
	 */
	public function set_message( $message ) {
		if ( !is_string( $message ) ) :
			throw("Please provide a string for your database key.");
		endif;

		$this->message = $message;

		return $this;
	}


	/**
	 * A method to allow you to set the unique key for this notice.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access protected
	 * @param  string $key   A string representing this notices unique key.
	 * @return object $this  Allows for method chaining.
	 *
	 */
	protected function set_key( $key ) {
		if ( !is_string ( $key ) ) :
			throw("Please provide a string for your database key.");
		endif;

		$this->key = $key;

		return $this;
	}


	/**
	 * Set a start date.
	 *
	 * This will allow us to schedule messages to be displayed at a specific date in the
	 * future. For example, before the StumbleUpon service goes away, we may want to post
	 * a notice letting folks know that it WILL BE going away. The day that they actually
	 * go away could be the start date for a notice that says that they HAVE gone away.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  string $start_date A str date formatted to 'Y-m-d H:i:s'
	 * @return $this Allows for method chaining
	 * @TODO   Add a type check, if possible, for a properly formatted date string.
	 *
	 */
	public function set_start_date( $start_date ) {
		if ( $this->is_date( $start_date ) ) :
			$this->start_date = $start_date;
		endif;

		return $this;
	}


	/**
	 * Set an end date.
	 *
	 * This will allow us to schedule messages to stop being displayed at a specific date
	 * in the future. For example, before the StumbleUpon service goes away, we may want
	 * to post a notice letting folks know that it WILL BE going away. The day that they
	 * actually go away could be the end date for that notice and the start date for a
	 * notice that says that they HAVE gone away. Additionally, we may only want to notify
	 * people about StumbleUpon having gone away for 60 days after it happens. After that,
	 * we can just assume that they've probably heard from somewhere else and not worry
	 * about showing a notice message.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  string $end_date A str date formatted to 'Y-m-d H:i:s'
	 * @return $this Allows for method chaining
	 * @TODO   Add a type check, if possible, for a properly formatted date string.
	 *
	 */
	public function set_end_date( $end_date ) {
		if ( $this->is_date( $end_date ) ) :
			$this->end_date = $end_date;
		endif;

		return $this;
	}


	/**
	* Creates the interactive CTA for the notice.
	*
	* @since  3.0.9 | 07 JUN 2018 | Created
	* @access public
	* @param  string $action Optional. The message to be displayed. Default "Thanks, I understand."
	* @param  string $href Optional. The outbound href.
	* @param  string $class Optional. The CSS classname to assign to the CTA.
	* @param  string $timeframe
	* @return $this Allows for method chaining.
	*
	*/
	public function add_default_cta()  {
		$cta = array();
		$cta['action']    = "Thanks, I understand.";
		$cta['href']      = '';
		$cta['target']    = '_self';
		$cta['class']     = '';
		$cta['timeframe'] =  0;

		$this->actions[] = $cta;

		return $this;
	}


	/**
	 * Render out the HTML.
	 *
	 * Ideally, everything before this method will create a beautiful data-oriented
	 * object. The only HTML that should be compiled should be inside this method.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  null
	 * @return string The compiled HTML of the dashboard notice.
	 *
	 */
	public function render_HTML() {
		if ( empty( $this->actions ) && false === $this->no_cta) :
			$this->add_default_cta();
		endif;

		$html = '<div class="swp-dismiss-notice notice notice-info " data-key="' . $this->key . '">';
			$html .= '<p>' . $this->message . ' - Warfare Plugins Team</p>';
			$html .= '<div class="swp-actions">';

				foreach( $this->actions as $cta) {
					$class = isset( $cta['class'] ) ? $cta['class'] : '';
					$href = isset( $cta['href'] ) ? $cta['href'] : '';
					$target = isset( $cta['target'] ) ? $cta['target'] : '';
					$timeframe = isset( $cta['timeframe'] ) ?  $cta['timeframe'] : 0;
					$html .= '<a class="swp-notice-cta ' . $class . '" href="' . $href . '" target="' . $target . '" data-timeframe="' . $timeframe .'">';
						$html .= $cta['action'];
					$html .= "</a>";
				}

			$html .= '</div>';
		$html .= '</div>';

		$this->html = $html;

		return $this;
	}


	/**
	 * Gets (returns) the HTML for this notice.
	 *
	 * We have two separate methods for this. One for returning the HTML, and
	 * one for echoing the html. This one returns it.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  string $notices The string of notices to be modified.
	 * @return string          The modified string of notices' html.
	 *
	 */
	public function get_HTML( $notices = '' ) {

		if ( !$this->should_display_notice() ) :
			return $notices;
		endif;

		return $this->html;
	}


	/**
	 * Echos the HTML for this notice.
	 *
	 * We have two separate methods for this. One for returning the HTML, and
	 * one for echoing the html. This one echos it.
	 *
	 * @since  3.0.9 | 07 JUN 2018 | Created
	 * @access public
	 * @param  string $notices The string of notices to be modified.
	 * @return string          The modified string of notices' html.
	 *
	 */
	public function print_HTML() {
		if ( !$this->should_display_notice() ) :
			return;
		endif;

		if ( empty( $this->html ) ) :
			$this->render_HTML();
		endif;

		echo $this->html;

		return $this;
	}

	/**
	 * Checks whether a string is formatted as our default Date format.
	 *
	 * @since  3.0.9 | 08 JUN 2018 | Created
	 * @param string $string The datetime string in question.
	 * @return bool True iff the string is of the format 'Y-m-d h:i:s'.
	 *
	 */
	private function is_date( $string ) {
		return DateTime::createFromFormat( 'Y-m-d h:i:s', $string ) !== false;
	}


	/**
	 * Prevents a CTA from being displayed on the notice.
	 *
	 * In cases where we require the user to take action, we need them
	 * to follow the directions in the message before removing the notice.
	 *
	 * @since  3.1.0 | 05 JUL 2018 | Created the method.
	 * @return SWP_Notice $this, for method chaining.
	 *
	 */
	 public function remove_cta() {
		 //* Force the ctas to an empty array so render can still loop over it.
		 $this->actions = array();

		 $this->no_cta = true;

		 return $this;
	 }
}