773 lines
19 KiB
PHP
773 lines
19 KiB
PHP
<?php
|
|
/**
|
|
* Simply Schedule Appointments Notices.
|
|
*
|
|
* @since 0.1.0
|
|
* @package Simply_Schedule_Appointments
|
|
*/
|
|
|
|
/**
|
|
* Simply Schedule Appointments Notices.
|
|
*
|
|
* @since 0.1.0
|
|
*/
|
|
class SSA_Notices {
|
|
/**
|
|
* Parent plugin class.
|
|
*
|
|
* @since 0.1.0
|
|
*
|
|
* @var Simply_Schedule_Appointments
|
|
*/
|
|
protected $plugin = null;
|
|
|
|
protected $top_notice_transient_key = 'ssa/notices/one_notice_to_display';
|
|
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @since 0.1.0
|
|
*
|
|
* @param Simply_Schedule_Appointments $plugin Main plugin object.
|
|
*/
|
|
public function __construct( $plugin ) {
|
|
$this->plugin = $plugin;
|
|
$this->hooks();
|
|
}
|
|
|
|
/**
|
|
* Initiate our hooks.
|
|
*
|
|
* @since 0.1.0
|
|
*/
|
|
public function hooks() {
|
|
|
|
}
|
|
|
|
/**
|
|
* Call & Return cached notice if set, otherwise call for it and cache it
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_the_one_notice_to_display() {
|
|
|
|
$cached_notice = get_transient( $this->top_notice_transient_key );
|
|
|
|
if( empty( $cached_notice ) ) {
|
|
|
|
$cached_notice = $this->get_appropriate_notice();
|
|
|
|
set_transient( $this->top_notice_transient_key , $cached_notice, HOUR_IN_SECONDS );
|
|
|
|
}
|
|
|
|
return $cached_notice === 'none' ? '' : $cached_notice;
|
|
|
|
}
|
|
|
|
/**
|
|
* Invoke the chain of filters to run
|
|
* Return the notice's id to display for the current site | 'none'
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_appropriate_notice(){
|
|
|
|
$valid_notices = $this->get_appropriate_notices_for_this_site();
|
|
|
|
$filtered_by_pinned_notices = $this->filter_by_pinned_notices( $valid_notices );
|
|
|
|
$notice_to_display = $this->filter_by_priority( $filtered_by_pinned_notices );
|
|
|
|
return $notice_to_display ? $notice_to_display['id'] : 'none';
|
|
}
|
|
|
|
/**
|
|
* Get the max priority from a list of notices then return the first that matches
|
|
* If two notices have their priority set to 1 (most important)
|
|
* We would return the first one found and discard all other notices
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_priority( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$min_priority = min(array_column($input, 'priority'));
|
|
|
|
foreach( $input as $notice ) {
|
|
if ( $min_priority === $notice['priority'] ) {
|
|
$output = $notice;
|
|
break;
|
|
}
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Get all notices, then filter out all inapproriate for the current site
|
|
* Returns an array of all valid notices to display
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_appropriate_notices_for_this_site() {
|
|
|
|
$all_notices_list = $this->get_all_notices();
|
|
|
|
$filtered_by_active_state = $this->filter_by_active_status( $all_notices_list );
|
|
|
|
$filtered_by_dissmissed_notices = $this->filter_by_dismissed_notices( $filtered_by_active_state );
|
|
|
|
$filtered_by_edition = $this->filter_by_edition( $filtered_by_dissmissed_notices );
|
|
|
|
$filtered_by_active_plugin = $this->filter_by_active_plugin_any( $filtered_by_edition );
|
|
|
|
$filtered_by_installed_features = $this->filter_by_installed_feature_any( $filtered_by_active_plugin );
|
|
|
|
$filtered_by_enabled_features = $this->filter_by_enabled_feature_any( $filtered_by_installed_features );
|
|
|
|
$filtered_by_activated_features = $this->filter_by_activated_feature_any( $filtered_by_enabled_features );
|
|
|
|
$filtered_by_not_installed_features = $this->filter_by_not_installed_feature_any( $filtered_by_activated_features );
|
|
|
|
$filtered_by_not_enabled_features = $this->filter_by_not_enabled_feature_any( $filtered_by_not_installed_features );
|
|
|
|
$filtered_by_not_activated_features = $this->filter_by_not_activated_feature_any( $filtered_by_not_enabled_features );
|
|
|
|
$filtered_by_current_user_can = $this->filter_by_current_user_can( $filtered_by_not_activated_features );
|
|
|
|
$filtered_by_min_activated_days = $this->filter_by_min_activated_days( $filtered_by_current_user_can );
|
|
|
|
$filtered_by_activation_date_after = $this->filter_by_activation_date_after( $filtered_by_min_activated_days );
|
|
|
|
$filtered_by_min_appt_count = $this->filter_by_min_appt_count( $filtered_by_activation_date_after );
|
|
|
|
return $filtered_by_min_appt_count;
|
|
}
|
|
|
|
/**
|
|
* Get ALL_NOTICES_LIST
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_all_notices() {
|
|
return SSA_Notices_Data::get_notices_list();
|
|
}
|
|
|
|
/**
|
|
* Each notice has and active property set to true by default
|
|
* In case set to false, will allow us to eliminate this notice early
|
|
* Without the need to remove it from the list entirely
|
|
*
|
|
* @return array
|
|
*/
|
|
public function filter_by_active_status( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
return $notice['active'] === true;
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Filter out notices that got dissmissed by the user
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_dismissed_notices( $input = array() ) {
|
|
|
|
$dismissed_notices = $this->get_dismissed_notices();
|
|
|
|
if ( empty( $dismissed_notices ) || empty( $input ) ){
|
|
return $input;
|
|
}
|
|
|
|
$output = array_filter( $input, function( $notice ) use ( $dismissed_notices ) {
|
|
|
|
return !in_array( $notice['id'], $dismissed_notices);
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Get dismissed notices stored in the database if any
|
|
* An empty option dissmissed notices is stored: a:0:{}
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_dismissed_notices() {
|
|
$dismissed_notices = get_option( 'ssa_dismissed_notices', array() );
|
|
|
|
return $dismissed_notices;
|
|
}
|
|
|
|
/**
|
|
* Get pinned notices stored in the database if any
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_pinned_notices() {
|
|
$pinned_notices = get_option( 'ssa_pinned_notices', array() );
|
|
|
|
return $pinned_notices;
|
|
}
|
|
|
|
/**
|
|
* Check if the user's edition matches with the required edition for the notices
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_edition( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$edition_detected = $this->plugin->get_current_edition();
|
|
|
|
$output = array_filter( $input, function( $notice ) use ( $edition_detected ) {
|
|
|
|
$required_editions = $notice['requires']['current_edition_any'];
|
|
|
|
if ( empty( $required_editions ) ) {
|
|
// No specific edition required for this notice -> keep it
|
|
return true;
|
|
|
|
} else {
|
|
// If the notice requires specific edition(s); check if the user's edition matches
|
|
return in_array( $edition_detected, $required_editions );
|
|
}
|
|
});
|
|
return $output;
|
|
}
|
|
|
|
|
|
/**
|
|
* Filter by ['active_plugin_any'] field
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_active_plugin_any( $input = array() ){
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
$plugins = $notice['requires']['active_plugin_any'];
|
|
|
|
if ( empty( $plugins ) ) {
|
|
return true;
|
|
}
|
|
|
|
static $all_active_plugins;
|
|
|
|
foreach( $plugins as $plugin ) {
|
|
|
|
if( empty( $all_active_plugins ) ) {
|
|
$all_active_plugins = $this->get_active_plugins();
|
|
}
|
|
if ( in_array( $plugin, $all_active_plugins ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Get all active plugins
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_active_plugins(){
|
|
|
|
$active_plugins = get_option( 'active_plugins' );
|
|
$output = array();
|
|
|
|
foreach ($active_plugins as $active_plugin ) {
|
|
if ( strpos( $active_plugin, '/' ) ) {
|
|
$active_plugin = substr( $active_plugin, 0, strpos( $active_plugin, '/' ) );
|
|
}
|
|
$output[] = $active_plugin;
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Check if any notice requires a specific installed feature
|
|
* By checking the ['installed_feature_any'] field
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_installed_feature_any( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
// For every notice in the array check the field below
|
|
$features = $notice['requires']['installed_feature_any'];
|
|
|
|
if ( empty( $features ) ) {
|
|
// No feature required to be installed for this notice -> Nothing to check -> keep it
|
|
return true;
|
|
|
|
} else {
|
|
// Else a feature is required to be installed, so we need to check
|
|
foreach( $features as $feature) {
|
|
if ( $this->check_if_feature_installed( $feature ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Check if any notice requires a NOT installed feature
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_not_installed_feature_any( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
// For every notice check if it requires a NOT installed feature
|
|
$features = $notice['requires']['not_installed_feature_any'];
|
|
|
|
if ( empty( $features ) ) {
|
|
// No feature required to be NOT installed for this notice -> Nothing to check -> keep it
|
|
return true;
|
|
|
|
} else {
|
|
// Else a feature is required to be NOT installed, so we need to check
|
|
foreach( $features as $feature) {
|
|
if ( ! $this->check_if_feature_installed( $feature ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Custom function to call out the is_installed built in method
|
|
* Return true if installed, false otherwise
|
|
*
|
|
* @param string $feature
|
|
* @return boolean
|
|
*/
|
|
public function check_if_feature_installed( $feature = '' ) {
|
|
|
|
if ( empty( $feature ) ){ return false; }
|
|
|
|
return $this->plugin->settings_installed->is_installed( $feature );
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Check if any notice requires an enabled feature
|
|
* If no enabled feature is required then let it pass; keep the notice
|
|
* Otherwise check for the feature:
|
|
* If it is enabled; keep the notice
|
|
* If it is not then filter the notice out
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_enabled_feature_any( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
// For every notice in the array check the field below
|
|
$features = $notice['requires']['enabled_feature_any'];
|
|
|
|
if ( empty( $features ) ) {
|
|
// No feature required to be enabled for this notice -> Nothing to check -> keep it
|
|
return true;
|
|
|
|
} else {
|
|
// Else a feature is required to be enabled, so we need to check
|
|
foreach( $features as $feature) {
|
|
if ( $this->check_if_feature_enabled( $feature ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Check if any notice requires an NOT enabled feature
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_not_enabled_feature_any( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
// For every notice check for required feature to be NOT enabled
|
|
$features = $notice['requires']['not_enabled_feature_any'];
|
|
|
|
if ( empty( $features ) ) {
|
|
// No feature required to be NOT enabled for this notice -> Nothing to check -> keep it
|
|
return true;
|
|
|
|
} else {
|
|
// Else a feature is required to be NOT enabled, so we need to check
|
|
foreach( $features as $feature) {
|
|
if ( ! $this->check_if_feature_enabled( $feature ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Custom function to call out the is_enabled built in method
|
|
* Return true if enabled, false otherwise
|
|
*
|
|
* @param string $feature
|
|
* @return boolean
|
|
*/
|
|
public function check_if_feature_enabled( $feature = '' ) {
|
|
|
|
if ( empty( $feature ) ){ return false; }
|
|
|
|
return $this->plugin->settings_installed->is_enabled( $feature );
|
|
}
|
|
|
|
/**
|
|
* Check if any notice requires an activated feature
|
|
* If any has been found call out the check_if_feature_activated
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_activated_feature_any( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
$features = $notice['requires']['activated_feature_any'];
|
|
|
|
if ( empty( $features ) ) {
|
|
// No feature required to be activated for this notice -> keep it
|
|
return true;
|
|
|
|
} else {
|
|
foreach( $features as $feature) {
|
|
if ( $this->check_if_feature_activated( $feature ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if any notice requires a NOT activated feature
|
|
* If any has been found call out the check_if_feature_activated
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_not_activated_feature_any( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
$features = $notice['requires']['not_activated_feature_any'];
|
|
|
|
if ( empty( $features ) ) {
|
|
// No feature required to be not activated for this notice -> keep it
|
|
return true;
|
|
|
|
} else {
|
|
// the `!` is needed since it requires the feature to be NOT activated
|
|
foreach( $features as $feature) {
|
|
if ( ! $this->check_if_feature_activated( $feature ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Custom function to call out the is_activated built in method
|
|
*
|
|
* @param string $feature
|
|
* @return boolean
|
|
*/
|
|
public function check_if_feature_activated( $feature = '' ) {
|
|
|
|
if ( empty( $feature ) ){ return false; }
|
|
|
|
return $this->plugin->settings_installed->is_activated( $feature );
|
|
}
|
|
|
|
public function filter_by_pinned_notices( $input = array() ) {
|
|
|
|
$pinned_notices = $this->get_pinned_notices();
|
|
|
|
if ( empty( $pinned_notices ) || empty( $input ) ){
|
|
return $input;
|
|
}
|
|
|
|
// Assign a priority of 22 for every pinned notices
|
|
$output = array_map( function( $notice ) use ( $pinned_notices ) {
|
|
// Check for pinned notices
|
|
if ( in_array( $notice['id'], $pinned_notices ) ){
|
|
$notice['priority'] = '22';
|
|
|
|
}
|
|
return $notice;
|
|
|
|
}, $input );
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Filter by ['requires']['current_user_can'] field
|
|
* Example: ['requires']['current_user_can'] => array( 'ssa_manage_site_settings' ),
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_current_user_can( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
$permissions = $notice['requires']['current_user_can'];
|
|
|
|
if ( empty( $permissions ) ) {
|
|
return true;
|
|
|
|
} else {
|
|
// Loop over the permissions since it's an array
|
|
foreach( $permissions as $permission ) {
|
|
// If any evaluated to false break & return false to filter the notice out
|
|
if ( ! current_user_can( $permission ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Check and filter notices by min_activated_days
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_min_activated_days( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
$required_activated_days = $notice['requires']['min_activated_days'];
|
|
|
|
if ( empty( $required_activated_days ) ) {
|
|
return true;
|
|
|
|
} else {
|
|
static $ssa_activated_days;
|
|
|
|
if( empty( $ssa_activated_days ) && $ssa_activated_days !== 0 ) {
|
|
$ssa_activated_days = $this->ssa_activated_days();
|
|
}
|
|
|
|
return (int) $required_activated_days <= (int) $ssa_activated_days;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Check and filter notices by activation_date_after
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_activation_date_after( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) return [];
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
$required_activation_date_after = $notice['requires']['activation_date_after'];
|
|
|
|
if ( empty( $required_activation_date_after ) ) {
|
|
return true;
|
|
|
|
} else {
|
|
static $ssa_activation_date;
|
|
|
|
if( empty( $ssa_activation_date ) ) {
|
|
$ssa_activation_date = $this->get_ssa_activation_date();
|
|
}
|
|
|
|
$activation_date = $ssa_activation_date; // DateTimeImmutable
|
|
$min_date_required = ssa_datetime( $required_activation_date_after );
|
|
|
|
return $activation_date > $min_date_required;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* In class-upgrade.php -> record_version() stores the date of each migration running
|
|
* Hence the first migration date indicates the activation date of the plugin
|
|
*
|
|
* @return int
|
|
*/
|
|
public function ssa_activated_days() {
|
|
|
|
$ssa_versions = get_option( 'ssa_versions', json_encode( array() ) );
|
|
$ssa_versions = json_decode( $ssa_versions, true );
|
|
|
|
if( empty( $ssa_versions ) ) {
|
|
return 0;
|
|
}
|
|
|
|
$activation_date = array_keys($ssa_versions)[0];
|
|
$activation_date = ssa_datetime( $activation_date );
|
|
$now = ssa_datetime();
|
|
$diff = $now->diff( $activation_date );
|
|
|
|
return $diff->days;
|
|
}
|
|
|
|
/**
|
|
* In class-upgrade.php -> record_version() stores the date of each migration running
|
|
* Hence the first migration date indicates the activation date of the plugin
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_ssa_activation_date() {
|
|
|
|
$ssa_versions = get_option( 'ssa_versions', json_encode( array() ) );
|
|
$ssa_versions = json_decode( $ssa_versions, true );
|
|
|
|
if( empty( $ssa_versions ) || ! is_array( $ssa_versions ) ) {
|
|
return ssa_datetime(); // Let's assume it's today in case is empty
|
|
}
|
|
|
|
if ( empty( array_keys( $ssa_versions ) ) || empty( array_keys( $ssa_versions )[0] ) ) {
|
|
return ssa_datetime();
|
|
}
|
|
|
|
return ssa_datetime( array_keys($ssa_versions)[0] );
|
|
}
|
|
|
|
/**
|
|
* Check and filter notices that require minimum booked appointment count
|
|
*
|
|
* @param array $input
|
|
* @return array
|
|
*/
|
|
public function filter_by_min_appt_count( $input = array() ) {
|
|
|
|
if ( empty( $input ) ) { return []; }
|
|
|
|
$output = array_filter( $input, function( $notice ) {
|
|
|
|
$required_appt_count = $notice['requires']['min_appt_count'];
|
|
|
|
if ( empty( $required_appt_count ) ) {
|
|
return true;
|
|
|
|
} else {
|
|
|
|
static $appointments_count;
|
|
if( empty( $appointments_count ) && $appointments_count !== 0 ) {
|
|
$appointments_count = $this->get_completed_appointments_count();
|
|
}
|
|
|
|
return (int) $required_appt_count <= (int) $appointments_count;
|
|
}
|
|
});
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Query COUNT of all booked appointments that have their end_date before today
|
|
*
|
|
* @return integer
|
|
*/
|
|
public function get_completed_appointments_count(){
|
|
|
|
$appointments_count = $this->plugin->appointment_model->count( array(
|
|
'status' => array( 'booked' ),
|
|
'end_date_max' => gmdate( 'Y-m-d H:i:s' ),
|
|
));
|
|
|
|
return $appointments_count;
|
|
}
|
|
|
|
/**
|
|
* Delete cached transient
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function delete_top_notice_cached_transient(){
|
|
$transient = $this->top_notice_transient_key;
|
|
return delete_transient( $transient );
|
|
}
|
|
|
|
}
|