Initial commit: Atomaste website
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
/**
|
||||
* Astra Notices
|
||||
*
|
||||
* An easy to use PHP Library to add dismissible admin notices in the WordPress admin.
|
||||
*
|
||||
* @package Astra Notices
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'Astra_Notices' ) ) :
|
||||
|
||||
/**
|
||||
* Astra_Notices
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Astra_Notices {
|
||||
|
||||
/**
|
||||
* Notices
|
||||
*
|
||||
* @access private
|
||||
* @var array Notices.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static $version = '1.1.11';
|
||||
|
||||
/**
|
||||
* Notices
|
||||
*
|
||||
* @access private
|
||||
* @var array Notices.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static $notices = array();
|
||||
|
||||
/**
|
||||
* Instance
|
||||
*
|
||||
* @access private
|
||||
* @var object Class object.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* Initiator
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return object initialized object of class.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'admin_notices', array( $this, 'show_notices' ), 30 );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
|
||||
add_action( 'wp_ajax_astra-notice-dismiss', array( $this, 'dismiss_notice' ) );
|
||||
add_filter( 'wp_kses_allowed_html', array( $this, 'add_data_attributes' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters and Returns a list of allowed tags and attributes for a given context.
|
||||
*
|
||||
* @param array $allowedposttags array of allowed tags.
|
||||
* @param string $context Context type (explicit).
|
||||
* @since 1.0.0
|
||||
* @return array
|
||||
*/
|
||||
public function add_data_attributes( $allowedposttags, $context ) {
|
||||
$allowedposttags['a']['data-repeat-notice-after'] = true;
|
||||
|
||||
return $allowedposttags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Notice.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $args Notice arguments.
|
||||
* @return void
|
||||
*/
|
||||
public static function add_notice( $args = array() ) {
|
||||
self::$notices[] = $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss Notice.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function dismiss_notice() {
|
||||
$notice_id = ( isset( $_POST['notice_id'] ) ) ? sanitize_key( $_POST['notice_id'] ) : '';
|
||||
$repeat_notice_after = ( isset( $_POST['repeat_notice_after'] ) ) ? absint( $_POST['repeat_notice_after'] ) : '';
|
||||
$nonce = ( isset( $_POST['nonce'] ) ) ? sanitize_key( $_POST['nonce'] ) : '';
|
||||
$notice = $this->get_notice_by_id( $notice_id );
|
||||
$capability = isset( $notice['capability'] ) ? $notice['capability'] : 'manage_options';
|
||||
|
||||
if ( ! apply_filters( 'astra_notices_user_cap_check', current_user_can( $capability ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( false === wp_verify_nonce( $nonce, 'astra-notices' ) ) {
|
||||
wp_send_json_error( esc_html_e( 'WordPress Nonce not validated.', 'astra' ) );
|
||||
}
|
||||
|
||||
// Valid inputs?
|
||||
if ( ! empty( $notice_id ) ) {
|
||||
|
||||
if ( ! empty( $repeat_notice_after ) ) {
|
||||
set_transient( $notice_id, true, $repeat_notice_after );
|
||||
} else {
|
||||
update_user_meta( get_current_user_id(), $notice_id, 'notice-dismissed' );
|
||||
}
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue Scripts.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
wp_register_style( 'astra-notices', self::get_url() . 'notices.css', array(), self::$version );
|
||||
wp_register_script( 'astra-notices', self::get_url() . 'notices.js', array( 'jquery' ), self::$version, true );
|
||||
wp_localize_script(
|
||||
'astra-notices',
|
||||
'astraNotices',
|
||||
array(
|
||||
'_notice_nonce' => wp_create_nonce( 'astra-notices' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the notices based on the given priority of the notice.
|
||||
* This function is called from usort()
|
||||
*
|
||||
* @since 1.5.2
|
||||
* @param array $notice_1 First notice.
|
||||
* @param array $notice_2 Second Notice.
|
||||
* @return array
|
||||
*/
|
||||
public function sort_notices( $notice_1, $notice_2 ) {
|
||||
if ( ! isset( $notice_1['priority'] ) ) {
|
||||
$notice_1['priority'] = 10;
|
||||
}
|
||||
if ( ! isset( $notice_2['priority'] ) ) {
|
||||
$notice_2['priority'] = 10;
|
||||
}
|
||||
|
||||
return $notice_1['priority'] - $notice_2['priority'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered notices.
|
||||
* Since v1.1.8 it is recommended to register the notices on
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function get_notices() {
|
||||
usort( self::$notices, array( $this, 'sort_notices' ) );
|
||||
|
||||
return self::$notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notice by notice_id
|
||||
*
|
||||
* @param string $notice_id Notice id.
|
||||
*
|
||||
* @return array notice based on the notice id.
|
||||
*/
|
||||
private function get_notice_by_id( $notice_id ) {
|
||||
if ( empty( $notice_id ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$notices = $this->get_notices();
|
||||
$notice = wp_list_filter(
|
||||
$notices,
|
||||
array(
|
||||
'id' => $notice_id,
|
||||
)
|
||||
);
|
||||
|
||||
return ! empty( $notice ) ? $notice[0] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the notices in the WordPress admin.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function show_notices() {
|
||||
$defaults = array(
|
||||
'id' => '', // Optional, Notice ID. If empty it set `astra-notices-id-<$array-index>`.
|
||||
'type' => 'info', // Optional, Notice type. Default `info`. Expected [info, warning, notice, error].
|
||||
'message' => '', // Optional, Message.
|
||||
'show_if' => true, // Optional, Show notice on custom condition. E.g. 'show_if' => if( is_admin() ) ? true, false, .
|
||||
'repeat-notice-after' => '', // Optional, Dismiss-able notice time. It'll auto show after given time.
|
||||
'display-notice-after' => false, // Optional, Dismiss-able notice time. It'll auto show after given time.
|
||||
'class' => '', // Optional, Additional notice wrapper class.
|
||||
'priority' => 10, // Priority of the notice.
|
||||
'display-with-other-notices' => true, // Should the notice be displayed if other notices are being displayed from Astra_Notices.
|
||||
'is_dismissible' => true,
|
||||
'capability' => 'manage_options', // User capability - This capability is required for the current user to see this notice.
|
||||
);
|
||||
|
||||
// Count for the notices that are rendered.
|
||||
$notices_displayed = 0;
|
||||
$notices = $this->get_notices();
|
||||
|
||||
foreach ( $notices as $key => $notice ) {
|
||||
$notice = wp_parse_args( $notice, $defaults );
|
||||
|
||||
// Show notices only for users with `manage_options` cap.
|
||||
if ( ! current_user_can( $notice['capability'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$notice['id'] = self::get_notice_id( $notice, $key );
|
||||
$notice['classes'] = self::get_wrap_classes( $notice );
|
||||
|
||||
// Notices visible after transient expire.
|
||||
if ( isset( $notice['show_if'] ) && true === $notice['show_if'] ) {
|
||||
|
||||
// don't display the notice if it is not supposed to be displayed with other notices.
|
||||
if ( 0 !== $notices_displayed && false === $notice['display-with-other-notices'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( self::is_expired( $notice ) ) {
|
||||
|
||||
self::markup( $notice );
|
||||
++$notices_displayed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a notice.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $notice Notice markup.
|
||||
* @return void
|
||||
*/
|
||||
public static function markup( $notice = array() ) {
|
||||
wp_enqueue_script( 'astra-notices' );
|
||||
wp_enqueue_style( 'astra-notices' );
|
||||
|
||||
do_action( 'astra_notice_before_markup' );
|
||||
|
||||
do_action( "astra_notice_before_markup_{$notice['id']}" );
|
||||
|
||||
?>
|
||||
<div id="<?php echo esc_attr( $notice['id'] ); ?>" class="<?php echo 'astra-notice-wrapper ' . esc_attr( $notice['classes'] ); ?>" data-repeat-notice-after="<?php echo esc_attr( $notice['repeat-notice-after'] ); ?>">
|
||||
<div class="astra-notice-container">
|
||||
<?php do_action( "astra_notice_inside_markup_{$notice['id']}" ); ?>
|
||||
<?php echo wp_kses_post( $notice['message'] ); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
do_action( "astra_notice_after_markup_{$notice['id']}" );
|
||||
|
||||
do_action( 'astra_notice_after_markup' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get wrapper classes for a notice.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $notice Notice arguments.
|
||||
* @return array Notice wrapper classes.
|
||||
*/
|
||||
private static function get_wrap_classes( $notice ) {
|
||||
$classes = array( 'astra-notice', 'notice' );
|
||||
|
||||
if ( $notice['is_dismissible'] ) {
|
||||
$classes[] = 'is-dismissible';
|
||||
}
|
||||
|
||||
$classes[] = $notice['class'];
|
||||
if ( isset( $notice['type'] ) && '' !== $notice['type'] ) {
|
||||
$classes[] = 'notice-' . $notice['type'];
|
||||
}
|
||||
|
||||
return esc_attr( implode( ' ', $classes ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML ID for a given notice.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $notice Notice arguments.
|
||||
* @param int $key Notice array index.
|
||||
* @return string HTML if for the notice.
|
||||
*/
|
||||
private static function get_notice_id( $notice, $key ) {
|
||||
if ( isset( $notice['id'] ) && ! empty( $notice['id'] ) ) {
|
||||
return $notice['id'];
|
||||
}
|
||||
|
||||
return 'astra-notices-id-' . $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the notice is expires.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $notice Notice arguments.
|
||||
* @return boolean
|
||||
*/
|
||||
private static function is_expired( $notice ) {
|
||||
$transient_status = get_transient( $notice['id'] );
|
||||
|
||||
if ( false === $transient_status ) {
|
||||
|
||||
if ( isset( $notice['display-notice-after'] ) && false !== $notice['display-notice-after'] ) {
|
||||
|
||||
if ( 'delayed-notice' !== get_user_meta( get_current_user_id(), $notice['id'], true ) &&
|
||||
'notice-dismissed' !== get_user_meta( get_current_user_id(), $notice['id'], true ) ) {
|
||||
set_transient( $notice['id'], 'delayed-notice', $notice['display-notice-after'] );
|
||||
update_user_meta( get_current_user_id(), $notice['id'], 'delayed-notice' );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the user meta status if current notice is dismissed or delay completed.
|
||||
$meta_status = get_user_meta( get_current_user_id(), $notice['id'], true );
|
||||
|
||||
if ( empty( $meta_status ) || 'delayed-notice' === $meta_status ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base URL for the astra-notices.
|
||||
*
|
||||
* @return mixed URL.
|
||||
*/
|
||||
public static function get_url() {
|
||||
$path = wp_normalize_path( dirname( __FILE__ ) );
|
||||
$theme_dir = wp_normalize_path( get_template_directory() );
|
||||
|
||||
if ( strpos( $path, $theme_dir ) !== false ) {
|
||||
return trailingslashit( get_template_directory_uri() . str_replace( $theme_dir, '', $path ) );
|
||||
} else {
|
||||
return plugin_dir_url( __FILE__ );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicking this off by calling 'get_instance()' method
|
||||
*/
|
||||
Astra_Notices::get_instance();
|
||||
|
||||
endif;
|
||||
@@ -0,0 +1,39 @@
|
||||
.astra-review-notice-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.astra-review-notice-container .dashicons {
|
||||
font-size: 1.4em;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.astra-review-notice-container a {
|
||||
padding-left: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.astra-review-notice-container .dashicons:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.astra-notice-container .notice-image img {
|
||||
max-width: 90px;
|
||||
}
|
||||
|
||||
.astra-notice-container .notice-content .notice-heading {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.astra-notice-container .notice-content {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.astra-notice-container {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Customizer controls toggles
|
||||
*
|
||||
* @package Astra
|
||||
*/
|
||||
|
||||
( function( $ ) {
|
||||
|
||||
/**
|
||||
* Helper class for the main Customizer interface.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @class ASTCustomizer
|
||||
*/
|
||||
AstraNotices = {
|
||||
|
||||
/**
|
||||
* Initializes our custom logic for the Customizer.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @method init
|
||||
*/
|
||||
init: function()
|
||||
{
|
||||
this._bind();
|
||||
},
|
||||
|
||||
/**
|
||||
* Binds events for the Astra Portfolio.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @access private
|
||||
* @method _bind
|
||||
*/
|
||||
_bind: function()
|
||||
{
|
||||
$( document ).on('click', '.astra-notice-close', AstraNotices._dismissNoticeNew );
|
||||
$( document ).on('click', '.astra-notice .notice-dismiss', AstraNotices._dismissNotice );
|
||||
},
|
||||
|
||||
_dismissNotice: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
var repeat_notice_after = $( this ).parents('.astra-notice').data( 'repeat-notice-after' ) || '';
|
||||
var notice_id = $( this ).parents('.astra-notice').attr( 'id' ) || '';
|
||||
|
||||
AstraNotices._ajax( notice_id, repeat_notice_after );
|
||||
},
|
||||
|
||||
_dismissNoticeNew: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
var repeat_notice_after = $( this ).attr( 'data-repeat-notice-after' ) || '';
|
||||
var notice_id = $( this ).parents('.astra-notice').attr( 'id' ) || '';
|
||||
|
||||
var $el = $( this ).parents('.astra-notice');
|
||||
$el.fadeTo( 100, 0, function() {
|
||||
$el.slideUp( 100, function() {
|
||||
$el.remove();
|
||||
});
|
||||
});
|
||||
|
||||
AstraNotices._ajax( notice_id, repeat_notice_after );
|
||||
|
||||
var link = $( this ).attr( 'href' ) || '';
|
||||
var target = $( this ).attr( 'target' ) || '';
|
||||
if( '' !== link && '_blank' === target ) {
|
||||
window.open(link , '_blank');
|
||||
}
|
||||
},
|
||||
|
||||
_ajax: function( notice_id, repeat_notice_after ) {
|
||||
|
||||
if( '' === notice_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action : 'astra-notice-dismiss',
|
||||
nonce : astraNotices._notice_nonce,
|
||||
notice_id : notice_id,
|
||||
repeat_notice_after : parseInt( repeat_notice_after ),
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
$( function() {
|
||||
AstraNotices.init();
|
||||
} );
|
||||
} )( jQuery );
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* WP Async Request
|
||||
*
|
||||
* @package WP-Background-Processing
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'Astra_WP_Async_Request' ) ) {
|
||||
|
||||
/**
|
||||
* Abstract Astra_WP_Async_Request class.
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
abstract class Astra_WP_Async_Request {
|
||||
|
||||
/**
|
||||
* Prefix
|
||||
*
|
||||
* (default value: 'wp')
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = 'wp';
|
||||
|
||||
/**
|
||||
* Action
|
||||
*
|
||||
* (default value: 'async_request')
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $action = 'async_request';
|
||||
|
||||
/**
|
||||
* Identifier
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* Data
|
||||
*
|
||||
* (default value: array())
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* Initiate new async request
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->identifier = $this->prefix . '_' . $this->action;
|
||||
|
||||
add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
|
||||
add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set data used during the request
|
||||
*
|
||||
* @param array $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function data( $data ) {
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the async request
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function dispatch() {
|
||||
$url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
|
||||
$args = $this->get_post_args();
|
||||
|
||||
return wp_remote_post( esc_url_raw( $url ), $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_query_args() {
|
||||
if ( property_exists( $this, 'query_args' ) ) {
|
||||
return $this->query_args;
|
||||
}
|
||||
|
||||
return array(
|
||||
'action' => $this->identifier,
|
||||
'nonce' => wp_create_nonce( $this->identifier ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query URL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_query_url() {
|
||||
if ( property_exists( $this, 'query_url' ) ) {
|
||||
return $this->query_url;
|
||||
}
|
||||
|
||||
return admin_url( 'admin-ajax.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get post args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_post_args() {
|
||||
if ( property_exists( $this, 'post_args' ) ) {
|
||||
return $this->post_args;
|
||||
}
|
||||
|
||||
return array(
|
||||
'timeout' => 0.01,
|
||||
'blocking' => false,
|
||||
'body' => $this->data,
|
||||
'cookies' => $_COOKIE,
|
||||
'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe handle
|
||||
*
|
||||
* Check for correct nonce and pass to handler.
|
||||
*/
|
||||
public function maybe_handle() {
|
||||
// Don't lock up other requests while processing
|
||||
session_write_close();
|
||||
|
||||
check_ajax_referer( $this->identifier, 'nonce' );
|
||||
|
||||
$this->handle();
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle
|
||||
*
|
||||
* Override this method to perform any actions required
|
||||
* during the async request.
|
||||
*/
|
||||
abstract protected function handle();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
<?php
|
||||
/**
|
||||
* WP Background Process
|
||||
*
|
||||
* @package WP-Background-Processing
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'Astra_WP_Background_Process' ) ) {
|
||||
|
||||
/**
|
||||
* Abstract Astra_WP_Background_Process class.
|
||||
*
|
||||
* @abstract
|
||||
* @extends Astra_WP_Async_Request
|
||||
*/
|
||||
abstract class Astra_WP_Background_Process extends Astra_WP_Async_Request {
|
||||
|
||||
/**
|
||||
* Action
|
||||
*
|
||||
* (default value: 'background_process')
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $action = 'background_process';
|
||||
|
||||
/**
|
||||
* Start time of current process.
|
||||
*
|
||||
* (default value: 0)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $start_time = 0;
|
||||
|
||||
/**
|
||||
* Cron_hook_identifier
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $cron_hook_identifier;
|
||||
|
||||
/**
|
||||
* Cron_interval_identifier
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $cron_interval_identifier;
|
||||
|
||||
/**
|
||||
* Initiate new background process
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->cron_hook_identifier = $this->identifier . '_cron';
|
||||
$this->cron_interval_identifier = $this->identifier . '_cron_interval';
|
||||
|
||||
add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
|
||||
add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dispatch() {
|
||||
// Schedule the cron healthcheck.
|
||||
$this->schedule_event();
|
||||
|
||||
// Perform remote post.
|
||||
return parent::dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Push to queue
|
||||
*
|
||||
* @param mixed $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function push_to_queue( $data ) {
|
||||
$this->data[] = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save queue
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function save() {
|
||||
$key = $this->generate_key();
|
||||
|
||||
if ( ! empty( $this->data ) ) {
|
||||
update_site_option( $key, $this->data );
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update queue
|
||||
*
|
||||
* @param string $key Key.
|
||||
* @param array $data Data.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function update( $key, $data ) {
|
||||
if ( ! empty( $data ) ) {
|
||||
update_site_option( $key, $data );
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete queue
|
||||
*
|
||||
* @param string $key Key.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function delete( $key ) {
|
||||
delete_site_option( $key );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate key
|
||||
*
|
||||
* Generates a unique key based on microtime. Queue items are
|
||||
* given a unique key so that they can be merged upon save.
|
||||
*
|
||||
* @param int $length Length.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_key( $length = 64 ) {
|
||||
// file deepcode ignore InsecureHash: This is the external library.
|
||||
$unique = md5( microtime() . rand() );
|
||||
$prepend = $this->identifier . '_batch_';
|
||||
|
||||
return substr( $prepend . $unique, 0, $length );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe process queue
|
||||
*
|
||||
* Checks whether data exists within the queue and that
|
||||
* the process is not already running.
|
||||
*/
|
||||
public function maybe_handle() {
|
||||
// Don't lock up other requests while processing
|
||||
session_write_close();
|
||||
|
||||
if ( $this->is_process_running() ) {
|
||||
// Background process already running.
|
||||
wp_die();
|
||||
}
|
||||
|
||||
if ( $this->is_queue_empty() ) {
|
||||
// No data to process.
|
||||
wp_die();
|
||||
}
|
||||
|
||||
check_ajax_referer( $this->identifier, 'nonce' );
|
||||
|
||||
$this->handle();
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is queue empty
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_queue_empty() {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->ast_db_table = $wpdb->options;
|
||||
$wpdb->ast_db_column = 'option_name';
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$wpdb->ast_db_table = $wpdb->sitemeta;
|
||||
$wpdb->ast_db_column = 'meta_key';
|
||||
}
|
||||
|
||||
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
|
||||
|
||||
$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->ast_db_table} WHERE {$wpdb->ast_db_column} LIKE %s ", $key ) );
|
||||
|
||||
return ( $count > 0 ) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is process running
|
||||
*
|
||||
* Check whether the current process is already running
|
||||
* in a background process.
|
||||
*/
|
||||
protected function is_process_running() {
|
||||
if ( get_site_transient( $this->identifier . '_process_lock' ) ) {
|
||||
// Process already running.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock process
|
||||
*
|
||||
* Lock the process so that multiple instances can't run simultaneously.
|
||||
* Override if applicable, but the duration should be greater than that
|
||||
* defined in the time_exceeded() method.
|
||||
*/
|
||||
protected function lock_process() {
|
||||
$this->start_time = time(); // Set start time of current process.
|
||||
|
||||
$lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
|
||||
$lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
|
||||
|
||||
set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock process
|
||||
*
|
||||
* Unlock the process so that other instances can spawn.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function unlock_process() {
|
||||
delete_site_transient( $this->identifier . '_process_lock' );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get batch
|
||||
*
|
||||
* @return stdClass Return the first batch from the queue
|
||||
*/
|
||||
protected function get_batch() {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->ast_db_table = $wpdb->options;
|
||||
$wpdb->ast_db_column = 'option_name';
|
||||
$wpdb->ast_db_key_column = 'option_id';
|
||||
$value_column = 'option_value';
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$wpdb->ast_db_table = $wpdb->sitemeta;
|
||||
$wpdb->ast_db_column = 'meta_key';
|
||||
$wpdb->ast_db_key_column = 'meta_id';
|
||||
$value_column = 'meta_value';
|
||||
}
|
||||
|
||||
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
|
||||
|
||||
$query = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->ast_db_table} WHERE {$wpdb->ast_db_column} LIKE %s ORDER BY {$wpdb->ast_db_key_column} ASC LIMIT 1", $key ) );
|
||||
|
||||
$batch = new stdClass();
|
||||
$batch->key = $query->{$wpdb->ast_db_column};
|
||||
$batch->data = maybe_unserialize( $query->$value_column );
|
||||
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle
|
||||
*
|
||||
* Pass each queue item to the task handler, while remaining
|
||||
* within server memory and time limit constraints.
|
||||
*/
|
||||
protected function handle() {
|
||||
$this->lock_process();
|
||||
|
||||
do {
|
||||
$batch = $this->get_batch();
|
||||
|
||||
foreach ( $batch->data as $key => $value ) {
|
||||
$task = $this->task( $value );
|
||||
|
||||
if ( false !== $task ) {
|
||||
$batch->data[ $key ] = $task;
|
||||
} else {
|
||||
unset( $batch->data[ $key ] );
|
||||
}
|
||||
|
||||
if ( $this->time_exceeded() || $this->memory_exceeded() ) {
|
||||
// Batch limits reached.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Update or delete current batch.
|
||||
if ( ! empty( $batch->data ) ) {
|
||||
$this->update( $batch->key, $batch->data );
|
||||
} else {
|
||||
$this->delete( $batch->key );
|
||||
}
|
||||
} while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
|
||||
|
||||
$this->unlock_process();
|
||||
|
||||
// Start next batch or complete process.
|
||||
if ( ! $this->is_queue_empty() ) {
|
||||
$this->dispatch();
|
||||
} else {
|
||||
$this->complete();
|
||||
}
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory exceeded
|
||||
*
|
||||
* Ensures the batch process never exceeds 90%
|
||||
* of the maximum WordPress memory.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function memory_exceeded() {
|
||||
$memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
|
||||
$current_memory = memory_get_usage( true );
|
||||
$return = false;
|
||||
|
||||
if ( $current_memory >= $memory_limit ) {
|
||||
$return = true;
|
||||
}
|
||||
|
||||
return apply_filters( $this->identifier . '_memory_exceeded', $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory limit
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_memory_limit() {
|
||||
if ( function_exists( 'ini_get' ) ) {
|
||||
$memory_limit = ini_get( 'memory_limit' );
|
||||
} else {
|
||||
// Sensible default.
|
||||
$memory_limit = '128M';
|
||||
}
|
||||
|
||||
if ( ! $memory_limit || -1 === intval( $memory_limit ) ) {
|
||||
// Unlimited, set to 32GB.
|
||||
$memory_limit = '32000M';
|
||||
}
|
||||
|
||||
return intval( $memory_limit ) * 1024 * 1024;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time exceeded.
|
||||
*
|
||||
* Ensures the batch never exceeds a sensible time limit.
|
||||
* A timeout limit of 30s is common on shared hosting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function time_exceeded() {
|
||||
$finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds
|
||||
$return = false;
|
||||
|
||||
if ( time() >= $finish ) {
|
||||
$return = true;
|
||||
}
|
||||
|
||||
return apply_filters( $this->identifier . '_time_exceeded', $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete.
|
||||
*
|
||||
* Override if applicable, but ensure that the below actions are
|
||||
* performed, or, call parent::complete().
|
||||
*/
|
||||
protected function complete() {
|
||||
// Unschedule the cron healthcheck.
|
||||
$this->clear_scheduled_event();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule cron health check
|
||||
*
|
||||
* @param mixed $schedules Schedules.
|
||||
* @return mixed
|
||||
*/
|
||||
public function schedule_cron_healthcheck( $schedules ) {
|
||||
$interval = apply_filters( $this->identifier . '_cron_interval', 5 );
|
||||
|
||||
if ( property_exists( $this, 'cron_interval' ) ) {
|
||||
$interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval );
|
||||
}
|
||||
|
||||
// Adds every 5 minutes to the existing schedules.
|
||||
$schedules[ $this->identifier . '_cron_interval' ] = array(
|
||||
'interval' => MINUTE_IN_SECONDS * $interval,
|
||||
'display' => sprintf( /* translators: %d: Minutes interval */ __( 'Every %d Minutes', 'astra' ), $interval ),
|
||||
);
|
||||
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cron healthcheck
|
||||
*
|
||||
* Restart the background process if not already running
|
||||
* and data exists in the queue.
|
||||
*/
|
||||
public function handle_cron_healthcheck() {
|
||||
if ( $this->is_process_running() ) {
|
||||
// Background process already running.
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( $this->is_queue_empty() ) {
|
||||
// No data to process.
|
||||
$this->clear_scheduled_event();
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->handle();
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule event
|
||||
*/
|
||||
protected function schedule_event() {
|
||||
if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
|
||||
wp_schedule_event( time(), $this->cron_interval_identifier, $this->cron_hook_identifier );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear scheduled event
|
||||
*/
|
||||
protected function clear_scheduled_event() {
|
||||
$timestamp = wp_next_scheduled( $this->cron_hook_identifier );
|
||||
|
||||
if ( $timestamp ) {
|
||||
wp_unschedule_event( $timestamp, $this->cron_hook_identifier );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel Process
|
||||
*
|
||||
* Stop processing queue items, clear cronjob and delete batch.
|
||||
*
|
||||
*/
|
||||
public function cancel_process() {
|
||||
if ( ! $this->is_queue_empty() ) {
|
||||
$batch = $this->get_batch();
|
||||
|
||||
$this->delete( $batch->key );
|
||||
|
||||
wp_clear_scheduled_hook( $this->cron_hook_identifier );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Task
|
||||
*
|
||||
* Override this method to perform any actions required on each
|
||||
* queue item. Return the modified item for further processing
|
||||
* in the next pass through. Or, return false to remove the
|
||||
* item from the queue.
|
||||
*
|
||||
* @param mixed $item Queue item to iterate over.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function task( $item );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package NPS Survey
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'Astra_Nps_Notice' ) ) {
|
||||
|
||||
/**
|
||||
* Admin
|
||||
*/
|
||||
class Astra_Nps_Notice {
|
||||
/**
|
||||
* Instance
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var (Object) Astra_Nps_Notice
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function __construct() {
|
||||
|
||||
// Allow users to disable NPS survey via a filter.
|
||||
if ( apply_filters( 'astra_nps_survey_disable', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Added filter to allow overriding the URL externally.
|
||||
add_filter( 'nps_survey_build_url', static function( $url ) {
|
||||
return get_template_directory_uri() . '/inc/lib/nps-survey/dist/';
|
||||
} );
|
||||
|
||||
// Bail early if soft while labeling is enabled.
|
||||
if (
|
||||
defined( 'ASTRA_EXT_VER' ) &&
|
||||
is_callable( 'Astra_Ext_White_Label_Markup::get_whitelabel_string' ) &&
|
||||
'astra' !== strtolower( Astra_Ext_White_Label_Markup::get_whitelabel_string( 'astra', 'name', 'astra' ) )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Return if white labelled is enabled.
|
||||
if ( astra_is_white_labelled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'admin_footer', array( $this, 'render_astra_nps_survey' ), 999 );
|
||||
|
||||
add_filter( 'nps_survey_allowed_screens', static function( $screens ) {
|
||||
// Restrict other NPS popups on Astra specific pages.
|
||||
if ( ! self::is_nps_showing() ) {
|
||||
return $screens;
|
||||
}
|
||||
|
||||
// Add new screen IDs to the array.
|
||||
$screens[] = 'toplevel_page_astra';
|
||||
$screens[] = 'astra_page_theme-builder-free';
|
||||
$screens[] = 'astra_page_theme-builder';
|
||||
|
||||
return $screens;
|
||||
});
|
||||
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'register_assets' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Instance
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return object Class object.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if NPS is showing.
|
||||
*
|
||||
* @since 4.8.7
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_nps_showing() {
|
||||
$astra_nps_options = get_option( Nps_Survey::get_nps_id( 'astra' ), array() );
|
||||
$display_after = isset( $astra_nps_options['display_after'] ) && is_int( $astra_nps_options['display_after'] ) ? $astra_nps_options['display_after'] : 0;
|
||||
|
||||
return Nps_Survey::is_show_nps_survey_form( 'astra', $display_after );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register admin scripts for NPS visibility condition.
|
||||
*
|
||||
* @param String $hook Screen name where the hook is fired.
|
||||
* @since 4.8.7
|
||||
* @return void
|
||||
*/
|
||||
public static function register_assets( ): void {
|
||||
if ( self::is_nps_showing() ) {
|
||||
// Intentionally hiding the other NPS popups when visible along with the Astra NPS.
|
||||
$css_file = is_rtl() ? 'nps-visibility-rtl.css' : 'nps-visibility.css';
|
||||
wp_enqueue_style( 'astra-nps-visibility', ASTRA_THEME_URI . 'inc/assets/css/' . $css_file, array(), ASTRA_THEME_VERSION );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render NPS Survey
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_astra_nps_survey(): void {
|
||||
Nps_Survey::show_nps_notice(
|
||||
'nps-survey-astra',
|
||||
array(
|
||||
'show_if' => defined( 'ASTRA_THEME_VERSION' ),
|
||||
'dismiss_timespan' => 2 * WEEK_IN_SECONDS,
|
||||
'display_after' => get_option('astra_nps_show') ? 0 : 2 * WEEK_IN_SECONDS,
|
||||
'plugin_slug' => 'astra',
|
||||
'message' => array(
|
||||
// Step 1 i.e rating input.
|
||||
'logo' => esc_url( ASTRA_THEME_URI . 'inc/assets/images/astra-logo.svg'),
|
||||
'plugin_name' => __( 'Astra', 'astra' ),
|
||||
'nps_rating_message' => __( 'How likely are you to recommend #pluginname to your friends or colleagues?', 'astra' ),
|
||||
|
||||
// Step 2A i.e. positive.
|
||||
'feedback_title' => __( 'Thanks a lot for your feedback! 😍', 'astra' ),
|
||||
'feedback_content' => __( 'Could you please do us a favor and give us a 5-star rating on WordPress? It would help others choose Astra with confidence. Thank you!', 'astra' ),
|
||||
'plugin_rating_link' => esc_url( 'https://wordpress.org/support/theme/astra/reviews/#new-post' ),
|
||||
'plugin_rating_button_string' => __( 'Rate the Theme', 'astra' ),
|
||||
|
||||
// Step 2B i.e. negative.
|
||||
'plugin_rating_title' => __( 'Thank you for your feedback', 'astra' ),
|
||||
'plugin_rating_content' => __( 'We value your input. How can we improve your experience?', 'astra' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicking this off by calling 'get_instance()' method
|
||||
*/
|
||||
Astra_Nps_Notice::get_instance();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package NPS Survey
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'Astra_Nps_Survey' ) ) :
|
||||
|
||||
/**
|
||||
* Admin
|
||||
*/
|
||||
class Astra_Nps_Survey {
|
||||
/**
|
||||
* Instance
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var (Object) Astra_Nps_Survey
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Get Instance
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return object Class object.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function __construct() {
|
||||
|
||||
// Allow users to disable NPS survey via a filter.
|
||||
if ( apply_filters( 'astra_nps_survey_disable', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->version_check();
|
||||
add_action( 'init', array( $this, 'load' ), 999 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Version Check
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function version_check() {
|
||||
|
||||
$file = realpath( dirname( __FILE__ ) . '/nps-survey/version.json' );
|
||||
|
||||
// Is file exist?
|
||||
if ( is_file( $file ) ) {
|
||||
// @codingStandardsIgnoreStart
|
||||
$file_data = json_decode( file_get_contents( $file ), true );
|
||||
// @codingStandardsIgnoreEnd
|
||||
global $nps_survey_version, $nps_survey_init;
|
||||
$path = realpath( dirname( __FILE__ ) . '/nps-survey/nps-survey.php' );
|
||||
$version = isset( $file_data['nps-survey'] ) ? $file_data['nps-survey'] : 0;
|
||||
|
||||
if ( null === $nps_survey_version ) {
|
||||
$nps_survey_version = '1.0.0';
|
||||
}
|
||||
|
||||
// Compare versions.
|
||||
if ( version_compare( $version, $nps_survey_version, '>=' ) ) {
|
||||
$nps_survey_version = $version;
|
||||
$nps_survey_init = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load latest plugin
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load() {
|
||||
|
||||
global $nps_survey_version, $nps_survey_init;
|
||||
if ( is_file( realpath( $nps_survey_init ) ) ) {
|
||||
include_once realpath( $nps_survey_init );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicking this off by calling 'get_instance()' method
|
||||
*/
|
||||
Astra_Nps_Survey::get_instance();
|
||||
|
||||
endif;
|
||||
@@ -0,0 +1,402 @@
|
||||
<?php
|
||||
/**
|
||||
* Download Docs locally.
|
||||
*
|
||||
* @package Astra
|
||||
* @since 4.6.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Process Docs from locally.
|
||||
*/
|
||||
class Astra_Docs_Loader {
|
||||
|
||||
/**
|
||||
* The remote URL.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $remote_url;
|
||||
|
||||
/**
|
||||
* Base path.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $base_path;
|
||||
|
||||
/**
|
||||
* Base URL.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $base_url;
|
||||
|
||||
/**
|
||||
* Subfolder name.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $subfolder_name;
|
||||
|
||||
/**
|
||||
* The docs folder.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $docs_folder;
|
||||
|
||||
/**
|
||||
* The local stylesheet's path.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $local_stylesheet_path;
|
||||
|
||||
/**
|
||||
* The local stylesheet's URL.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $local_docs_json_url;
|
||||
|
||||
/**
|
||||
* The remote CSS.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $remote_styles;
|
||||
|
||||
/**
|
||||
* The final docs data.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $docs_data;
|
||||
|
||||
/**
|
||||
* Cleanup routine frequency.
|
||||
*/
|
||||
const CLEANUP_FREQUENCY = 'weekly';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Get a new instance of the object for a new URL.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @param string $url The remote URL.
|
||||
* @param string $subfolder_name The subfolder name.
|
||||
*/
|
||||
public function __construct( $url = '', $subfolder_name = 'bsf-docs' ) {
|
||||
$this->remote_url = $url;
|
||||
$this->subfolder_name = $subfolder_name;
|
||||
|
||||
// Add a cleanup routine.
|
||||
$this->schedule_cleanup();
|
||||
add_action( 'astra_delete_docs_folder', array( $this, 'astra_delete_docs_folder' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local URL which contains the styles.
|
||||
*
|
||||
* Fallback to the remote URL if we were unable to write the file locally.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_url() {
|
||||
|
||||
// Check if the local stylesheet exists.
|
||||
if ( $this->local_file_exists() ) {
|
||||
|
||||
// Attempt to update the stylesheet. Return the local URL on success.
|
||||
if ( $this->write_json() ) {
|
||||
return $this->get_local_docs_json_url();
|
||||
}
|
||||
}
|
||||
|
||||
$astra_docs_url = file_exists( $this->get_local_docs_file_path() ) ? $this->get_local_docs_json_url() : $this->remote_url;
|
||||
|
||||
return $astra_docs_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local stylesheet URL.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_local_docs_json_url() {
|
||||
if ( ! $this->local_docs_json_url ) {
|
||||
$this->local_docs_json_url = str_replace(
|
||||
$this->get_base_path(),
|
||||
$this->get_base_url(),
|
||||
$this->get_local_docs_file_path()
|
||||
);
|
||||
}
|
||||
return $this->local_docs_json_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote data locally.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_remote_data() {
|
||||
|
||||
// If we already have the local file, return its contents.
|
||||
$local_docs_contents = $this->get_local_docs_contents();
|
||||
if ( $local_docs_contents ) {
|
||||
return $local_docs_contents;
|
||||
}
|
||||
|
||||
// Get the remote URL contents.
|
||||
$this->remote_styles = $this->get_remote_url_contents();
|
||||
$this->docs_data = $this->remote_styles;
|
||||
|
||||
$this->write_json();
|
||||
|
||||
return $this->docs_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local stylesheet contents.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string|false Returns the remote URL contents.
|
||||
*/
|
||||
public function get_local_docs_contents() {
|
||||
$local_path = $this->get_local_docs_file_path();
|
||||
|
||||
// Check if the local file exists.
|
||||
if ( $this->local_file_exists() ) {
|
||||
|
||||
// Attempt to update the file. Return false on fail.
|
||||
if ( ! $this->write_json() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ob_start();
|
||||
include $local_path;
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote file contents.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string Returns the remote URL contents.
|
||||
*/
|
||||
public function get_remote_url_contents() {
|
||||
|
||||
/**
|
||||
* The user-agent we want to use.
|
||||
*
|
||||
* The default user-agent is the only one compatible with woff (not woff2)
|
||||
* which also supports unicode ranges.
|
||||
*/
|
||||
$user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8';
|
||||
|
||||
// Get the response.
|
||||
$response = wp_remote_get( $this->remote_url, array( 'user-agent' => $user_agent ) );
|
||||
|
||||
// Early exit if there was an error.
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the CSS from our response.
|
||||
$contents = wp_remote_retrieve_body( $response );
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the CSS to the filesystem.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string|false Returns the absolute path of the file on success, or false on fail.
|
||||
*/
|
||||
protected function write_json() {
|
||||
$file_path = $this->get_local_docs_file_path();
|
||||
$filesystem = $this->get_filesystem();
|
||||
|
||||
if ( ! defined( 'FS_CHMOD_DIR' ) ) {
|
||||
define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) );
|
||||
}
|
||||
|
||||
// If the folder doesn't exist, create it.
|
||||
if ( ! file_exists( $this->get_docs_folder() ) ) {
|
||||
$this->get_filesystem()->mkdir( $this->get_docs_folder(), FS_CHMOD_DIR );
|
||||
}
|
||||
|
||||
// If the file doesn't exist, create it. Return false if it can not be created.
|
||||
if ( ! $filesystem->exists( $file_path ) && ! $filesystem->touch( $file_path ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we got this far, we need to write the file.
|
||||
// Get the CSS.
|
||||
if ( ! $this->docs_data ) {
|
||||
$this->get_remote_data();
|
||||
}
|
||||
|
||||
// Put the contents in the file. Return false if that fails.
|
||||
if ( ! $filesystem->put_contents( $file_path, $this->docs_data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stylesheet path.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_local_docs_file_path() {
|
||||
if ( ! $this->local_stylesheet_path ) {
|
||||
$this->local_stylesheet_path = $this->get_docs_folder() . '/' . $this->get_local_docs_filename() . '.json';
|
||||
}
|
||||
return $this->local_stylesheet_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local stylesheet filename.
|
||||
*
|
||||
* This is a hash, generated from the site-URL, the wp-content path and the URL.
|
||||
* This way we can avoid issues with sites changing their URL, or the wp-content path etc.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_local_docs_filename() {
|
||||
return apply_filters( 'astra_local_docs_file_name', 'docs' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the local stylesheet exists.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return bool
|
||||
*/
|
||||
public function local_file_exists() {
|
||||
return ( ! file_exists( $this->get_local_docs_file_path() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base path.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_base_path() {
|
||||
if ( ! $this->base_path ) {
|
||||
$this->base_path = apply_filters( 'astra_local_docs_base_path', $this->get_filesystem()->wp_content_dir() . 'uploads' );
|
||||
}
|
||||
return $this->base_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URL.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_base_url() {
|
||||
if ( ! $this->base_url ) {
|
||||
$this->base_url = apply_filters( 'astra_local_docs_base_url', content_url() . '/uploads' );
|
||||
}
|
||||
return $this->base_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder for docs.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_docs_folder() {
|
||||
if ( ! $this->docs_folder ) {
|
||||
$this->docs_folder = $this->get_base_path();
|
||||
$this->docs_folder .= '/' . $this->subfolder_name;
|
||||
}
|
||||
|
||||
return $this->docs_folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a cleanup.
|
||||
*
|
||||
* Deletes the docs file on a regular basis.
|
||||
* This way docs file will get updated regularly,
|
||||
* and we avoid edge cases where unused files remain in the server.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return void
|
||||
*/
|
||||
public function schedule_cleanup() {
|
||||
if ( ! wp_next_scheduled( 'astra_delete_docs_folder' ) && ! wp_installing() ) {
|
||||
wp_schedule_event( time(), self::CLEANUP_FREQUENCY, 'astra_delete_docs_folder' ); // phpcs:ignore WPThemeReview.PluginTerritory.ForbiddenFunctions.cron_functionality_wp_schedule_event
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the documentation folder.
|
||||
*
|
||||
* This runs as part of a cleanup routine.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return bool
|
||||
*/
|
||||
public function astra_delete_docs_folder() {
|
||||
// Delete previously created supportive options.
|
||||
return $this->get_filesystem()->delete( $this->get_docs_folder(), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filesystem.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return \WP_Filesystem_Base
|
||||
*/
|
||||
protected function get_filesystem() {
|
||||
|
||||
// We are using WP_Filesystem for managing local doc files which is necessary for the proper functionality of the theme -- This is an extension version of TRT webfont library.
|
||||
global $wp_filesystem;
|
||||
|
||||
// If the filesystem has not been instantiated yet, do it here.
|
||||
if ( ! $wp_filesystem ) {
|
||||
if ( ! function_exists( 'WP_Filesystem' ) ) {
|
||||
require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' ); // PHPCS:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound
|
||||
}
|
||||
WP_Filesystem();
|
||||
}
|
||||
return $wp_filesystem;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create instance of Astra_Docs_Loader class.
|
||||
*
|
||||
* @param string $docs_rest_url Knowledge Base URL to set data.
|
||||
* @param string $subfolder_name Subfolder name.
|
||||
*
|
||||
* @return object
|
||||
* @since 4.6.0
|
||||
*/
|
||||
function astra_docs_loader_instance( $docs_rest_url = '', $subfolder_name = 'bsf-docs' ) {
|
||||
return new Astra_Docs_Loader( $docs_rest_url, $subfolder_name );
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
Version 1.0.4 - 13-12-2024
|
||||
- Improvement: Optimized file loading to prevent duplicate loads, enhancing performance.
|
||||
|
||||
Version 1.0.3 - 10-12-2024
|
||||
- Fix: Fixed library update issue.
|
||||
|
||||
Version 1.0.2 - 09-12-2024
|
||||
- Improvement: NPS popup will now be permanently dismissed when closed for the second time.
|
||||
- Improvement: Added an option to customize the rate button text for plugins/themes.
|
||||
- Fix: Resolved CSS conflicts with other plugins.
|
||||
|
||||
Version 1.0.1 - 20-11-2024
|
||||
- New: Added filter to 'nps_survey_allowed_screens' to allow custom screens.
|
||||
- New: Added filter to 'nps_survey_build_url' update build url for themes.
|
||||
|
||||
Version 1.0.0 - 23-09-2024
|
||||
- New: Initial release.
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
/**
|
||||
* NPS Survey Script
|
||||
* File to handle behaviour and content of NPS popup
|
||||
*
|
||||
* @package {{package}}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Nps_Survey
|
||||
*/
|
||||
class Nps_Survey {
|
||||
|
||||
/**
|
||||
* Instance
|
||||
*
|
||||
* @access private
|
||||
* @var object Class Instance.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Initiator
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return object initialized object of class.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'editor_load_scripts' ) );
|
||||
add_action( 'rest_api_init', array( $this, 'register_route' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render NPS Survey.
|
||||
*
|
||||
* @param string $id ID of the root element, should start with nps-survey- .
|
||||
* @param array<mixed> $vars Variables to be passed to the NPS.
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public static function show_nps_notice( string $id, array $vars = [] ) {
|
||||
|
||||
if ( ! isset( $vars['plugin_slug'] ) || ! is_string( $vars['plugin_slug'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$plugin_slug = $vars['plugin_slug'];
|
||||
$display_after = is_int( $vars['display_after'] ) ? $vars['display_after'] : 0;
|
||||
|
||||
if ( ! self::is_show_nps_survey_form( $plugin_slug, $display_after ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?><div data-id="<?php echo esc_attr( $id ); ?>" class="nps-survey-root" data-vars="<?php echo esc_attr( strval( wp_json_encode( $vars ) ) ); ?>"></div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and return the Google fonts url.
|
||||
*
|
||||
* @since 1.0.2
|
||||
* @return string
|
||||
*/
|
||||
public static function google_fonts_url() {
|
||||
|
||||
$fonts_url = '';
|
||||
$font_families = array(
|
||||
'Figtree:400,500,600,700',
|
||||
);
|
||||
|
||||
$query_args = array(
|
||||
'family' => rawurlencode( implode( '|', $font_families ) ),
|
||||
'subset' => rawurlencode( 'latin,latin-ext' ),
|
||||
);
|
||||
|
||||
$fonts_url = add_query_arg( $query_args, '//fonts.googleapis.com/css' );
|
||||
|
||||
return $fonts_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load script.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public static function editor_load_scripts() {
|
||||
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
$screen_id = $screen ? $screen->id : '';
|
||||
// Added a filter to allow adding additional screens from outside.
|
||||
$allowed_screens = apply_filters(
|
||||
'nps_survey_allowed_screens',
|
||||
[
|
||||
'dashboard',
|
||||
'themes',
|
||||
'options-general',
|
||||
'plugins',
|
||||
]
|
||||
);
|
||||
|
||||
if ( ! in_array( $screen_id, $allowed_screens, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$handle = 'nps-survey-script';
|
||||
$build_path = NPS_SURVEY_DIR . 'dist/';
|
||||
$default_build_url = NPS_SURVEY_URL . 'dist/';
|
||||
|
||||
// Use a filter to allow $build_url to be modified externally.
|
||||
$build_url = apply_filters( 'nps_survey_build_url', $default_build_url );
|
||||
$script_asset_path = $build_path . 'main.asset.php';
|
||||
|
||||
$script_info = file_exists( $script_asset_path )
|
||||
? include $script_asset_path
|
||||
: array(
|
||||
'dependencies' => array(),
|
||||
'version' => NPS_SURVEY_VER,
|
||||
);
|
||||
|
||||
$script_dep = array_merge( $script_info['dependencies'], array( 'jquery' ) );
|
||||
|
||||
wp_enqueue_script(
|
||||
$handle,
|
||||
$build_url . 'main.js',
|
||||
$script_dep,
|
||||
$script_info['version'],
|
||||
true
|
||||
);
|
||||
|
||||
$data = apply_filters(
|
||||
'nps_survey_vars',
|
||||
[
|
||||
'ajaxurl' => esc_url( admin_url( 'admin-ajax.php' ) ),
|
||||
'_ajax_nonce' => wp_create_nonce( 'nps-survey' ),
|
||||
]
|
||||
);
|
||||
|
||||
// Add localize JS.
|
||||
wp_localize_script(
|
||||
'nps-survey-script',
|
||||
'npsSurvey',
|
||||
$data
|
||||
);
|
||||
|
||||
wp_enqueue_style( 'nps-survey-style', $build_url . '/style-main.css', array(), NPS_SURVEY_VER );
|
||||
wp_style_add_data( 'nps-survey-style', 'rtl', 'replace' );
|
||||
wp_enqueue_style( 'nps-survey-google-fonts', self::google_fonts_url(), array(), 'all' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all the required files in the importer.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return void
|
||||
*/
|
||||
public static function register_route() {
|
||||
|
||||
register_rest_route(
|
||||
self::get_api_namespace(),
|
||||
'/rating/',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::CREATABLE,
|
||||
'callback' => array( __CLASS__, 'submit_rating' ),
|
||||
'permission_callback' => array( __CLASS__, 'get_item_permissions_check' ),
|
||||
'args' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
self::get_api_namespace(),
|
||||
'/dismiss-nps-survey/',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::CREATABLE,
|
||||
'callback' => array( __CLASS__, 'dismiss_nps_survey_panel' ),
|
||||
'permission_callback' => array( __CLASS__, 'get_item_permissions_check' ),
|
||||
'args' => array(),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API URL.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_api_domain() {
|
||||
return trailingslashit( defined( 'NPS_SURVEY_REMOTE_URL' ) ? NPS_SURVEY_REMOTE_URL : apply_filters( 'nps_survey_api_domain', 'https://websitedemos.net/' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get api namespace
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return string
|
||||
*/
|
||||
public static function get_api_namespace() {
|
||||
return 'nps-survey/v1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API headers
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function get_api_headers() {
|
||||
return array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given request has permission to read notes.
|
||||
*
|
||||
* @param object $request WP_REST_Request Full details about the request.
|
||||
* @return object|boolean
|
||||
*/
|
||||
public static function get_item_permissions_check( $request ) {
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return new \WP_Error(
|
||||
'gt_rest_cannot_access',
|
||||
__( 'Sorry, you are not allowed to do that.', 'astra' ),
|
||||
array( 'status' => rest_authorization_required_code() )
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit Ratings.
|
||||
*
|
||||
* @param \WP_REST_Request $request Request object.
|
||||
* @return void
|
||||
*/
|
||||
public static function submit_rating( $request ) {
|
||||
|
||||
$nonce = $request->get_header( 'X-WP-Nonce' );
|
||||
|
||||
// Verify the nonce.
|
||||
if ( ! wp_verify_nonce( sanitize_text_field( (string) $nonce ), 'wp_rest' ) ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'data' => __( 'Nonce verification failed.', 'astra' ),
|
||||
'status' => false,
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$api_endpoint = self::get_api_domain() . 'wp-json/starter-templates/v1/nps-survey/';
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
$post_data = array(
|
||||
'rating' => ! empty( $request['rating'] ) ? sanitize_text_field( strval( $request['rating'] ) ) : '',
|
||||
'comment' => ! empty( $request['comment'] ) ? sanitize_text_field( strval( $request['comment'] ) ) : '',
|
||||
'email' => $current_user->user_email,
|
||||
'first_name' => $current_user->first_name ?? $current_user->display_name,
|
||||
'last_name' => $current_user->last_name ?? '',
|
||||
'source' => ! empty( $request['plugin_slug'] ) ? sanitize_text_field( strval( $request['plugin_slug'] ) ) : '',
|
||||
'plugin_slug' => ! empty( $request['plugin_slug'] ) ? sanitize_text_field( strval( $request['plugin_slug'] ) ) : '',
|
||||
);
|
||||
|
||||
$request_args = array(
|
||||
'body' => wp_json_encode( $post_data ),
|
||||
'headers' => self::get_api_headers(),
|
||||
'timeout' => 60,
|
||||
);
|
||||
|
||||
$response = wp_safe_remote_post( $api_endpoint, $request_args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
// There was an error in the request.
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'data' => 'Failed ' . $response->get_error_message(),
|
||||
'status' => false,
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( 200 === $response_code ) {
|
||||
|
||||
$nps_form_status = array(
|
||||
'dismiss_count' => 0,
|
||||
'dismiss_permanently' => true,
|
||||
'dismiss_step' => '',
|
||||
);
|
||||
|
||||
update_option( self::get_nps_id( strval( $request['plugin_slug'] ) ), $nps_form_status );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'status' => true,
|
||||
)
|
||||
);
|
||||
|
||||
} else {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'status' => false,
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss NPS Survey.
|
||||
*
|
||||
* @param \WP_REST_Request $request Request object.
|
||||
* @return void
|
||||
*/
|
||||
public static function dismiss_nps_survey_panel( $request ) {
|
||||
|
||||
$nonce = $request->get_header( 'X-WP-Nonce' );
|
||||
|
||||
// Verify the nonce.
|
||||
if ( ! wp_verify_nonce( sanitize_text_field( (string) $nonce ), 'wp_rest' ) ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'data' => __( 'Nonce verification failed.', 'astra' ),
|
||||
'status' => false,
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$nps_form_status = self::get_nps_survey_dismiss_status( strval( $request['plugin_slug'] ) );
|
||||
|
||||
// Add dismiss timespan.
|
||||
$nps_form_status['dismiss_timespan'] = $request['dismiss_timespan'];
|
||||
|
||||
// Add dismiss date.
|
||||
$nps_form_status['dismiss_time'] = time();
|
||||
|
||||
// Update dismiss count.
|
||||
$nps_form_status['dismiss_count'] = $nps_form_status['dismiss_count'] + 1;
|
||||
$nps_form_status['dismiss_step'] = $request['current_step'];
|
||||
|
||||
// Dismiss Permanantly.
|
||||
if ( $nps_form_status['dismiss_count'] >= 2 ) {
|
||||
$nps_form_status['dismiss_permanently'] = true;
|
||||
}
|
||||
|
||||
update_option( self::get_nps_id( strval( $request['plugin_slug'] ) ), $nps_form_status );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'status' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dismiss status of NPS Survey.
|
||||
*
|
||||
* @param string $plugin_slug slug of unique NPS Survey.
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function get_nps_survey_dismiss_status( string $plugin_slug ) {
|
||||
|
||||
$default_status = get_option(
|
||||
self::get_nps_id( $plugin_slug ),
|
||||
array(
|
||||
'dismiss_count' => 0,
|
||||
'dismiss_permanently' => false,
|
||||
'dismiss_step' => '',
|
||||
'dismiss_time' => '',
|
||||
'dismiss_timespan' => null,
|
||||
'first_render_time' => null,
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! is_array( $default_status ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$status = array(
|
||||
'dismiss_count' => ! empty( $default_status['dismiss_count'] ) ? $default_status['dismiss_count'] : 0,
|
||||
'dismiss_permanently' => ! empty( $default_status['dismiss_permanently'] ) ? $default_status['dismiss_permanently'] : false,
|
||||
'dismiss_step' => ! empty( $default_status['dismiss_step'] ) ? $default_status['dismiss_step'] : '',
|
||||
'dismiss_time' => ! empty( $default_status['dismiss_time'] ) ? $default_status['dismiss_time'] : '',
|
||||
'dismiss_timespan' => ! empty( $default_status['dismiss_timespan'] ) ? $default_status['dismiss_timespan'] : null,
|
||||
'first_render_time' => ! empty( $default_status['first_render_time'] ) ? $default_status['first_render_time'] : null,
|
||||
);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show status of NPS Survey.
|
||||
*
|
||||
* @param string $plugin_slug slug of unique NPS Survey.
|
||||
* @param int $display_after number of days after which NPS Survey should be displayed.
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_show_nps_survey_form( string $plugin_slug, int $display_after ) {
|
||||
|
||||
$current_time = time();
|
||||
$status = self::get_nps_survey_dismiss_status( $plugin_slug );
|
||||
|
||||
if ( $status['dismiss_permanently'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$first_render_time = $status['first_render_time'];
|
||||
|
||||
if ( 0 !== $display_after ) {
|
||||
if ( null === $first_render_time ) {
|
||||
$status['first_render_time'] = $current_time;
|
||||
update_option( self::get_nps_id( $plugin_slug ), $status );
|
||||
$status = self::get_nps_survey_dismiss_status( $plugin_slug );
|
||||
return false;
|
||||
}
|
||||
if ( $display_after + $first_render_time > $current_time ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the stored date time stamp from wp_options.
|
||||
$stored_date_timestamp = $status['dismiss_time'];
|
||||
$dismiss_timespan = $status['dismiss_timespan'];
|
||||
|
||||
if ( $stored_date_timestamp ) {
|
||||
|
||||
$current_time = time();
|
||||
|
||||
// time difference of current time and the time user dismissed the nps.
|
||||
$time_difference = $current_time - $stored_date_timestamp;
|
||||
|
||||
// Check if two weeks have passed.
|
||||
if ( $time_difference <= $dismiss_timespan ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get NPS Dismiss Option Name.
|
||||
*
|
||||
* @param string $plugin_slug Plugin name.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_nps_id( $plugin_slug ) {
|
||||
return 'nps-survey-' . $plugin_slug;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicking this off by calling 'get_instance()' method
|
||||
*/
|
||||
Nps_Survey::get_instance();
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "brainstormforce/nps-survey",
|
||||
"type": "wordpress-plugin",
|
||||
"description": "NPS Survey Plugin",
|
||||
"require-dev": {
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.1",
|
||||
"phpcompatibility/php-compatibility": "^9.3",
|
||||
"wp-coding-standards/wpcs": "^2.2",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"szepeviktor/phpstan-wordpress": "^1.1",
|
||||
"php-stubs/wordpress-stubs": "^6.1",
|
||||
"php-stubs/generator": "^0.8.2",
|
||||
"automattic/vipwpcs": "^2.3"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "vendor/bin/phpcbf",
|
||||
"lint": "vendor/bin/phpcs",
|
||||
"test": "vendor/bin/phpunit",
|
||||
"phpstan": "vendor/bin/phpstan --memory-limit=2048M analyse",
|
||||
"gen-stubs": "vendor/bin/generate-stubs artifact/phpstan/nps-survey/ --out=tests/php/stubs/nps-survey-stubs.php && rm -rf artifact/phpstan",
|
||||
"update-stubs": "rm -f tests/php/stubs/nps-survey-stubs.php && bash bin/build-folder-phpstan.sh && composer gen-stubs"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-element', 'wp-i18n'), 'version' => '1d2887c1739029e6a045');
|
||||
1
Atomaste Reference/public_html/wp-content/themes/astra/inc/lib/nps-survey/dist/main.js
vendored
Normal file
1
Atomaste Reference/public_html/wp-content/themes/astra/inc/lib/nps-survey/dist/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
119
Atomaste Reference/public_html/wp-content/themes/astra/inc/lib/nps-survey/dist/style-main-rtl.css
vendored
Normal file
119
Atomaste Reference/public_html/wp-content/themes/astra/inc/lib/nps-survey/dist/style-main-rtl.css
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
.nps-survey-root .invisible {visibility: hidden
|
||||
}.nps-survey-root .fixed {position: fixed
|
||||
}.nps-survey-root .absolute {position: absolute
|
||||
}.nps-survey-root .relative {position: relative
|
||||
}.nps-survey-root .inset-0 {inset: 0px
|
||||
}.nps-survey-root .bottom-2 {bottom: 0.5rem
|
||||
}.nps-survey-root .right-2 {left: 0.5rem
|
||||
}.nps-survey-root .right-3 {left: 0.75rem
|
||||
}.nps-survey-root .top-3 {top: 0.75rem
|
||||
}.nps-survey-root .isolate {isolation: isolate
|
||||
}.nps-survey-root .z-10 {z-index: 10
|
||||
}.nps-survey-root .mx-0 {margin-right: 0px;margin-left: 0px
|
||||
}.nps-survey-root .my-0 {margin-top: 0px;margin-bottom: 0px
|
||||
}.nps-survey-root .mb-0 {margin-bottom: 0px
|
||||
}.nps-survey-root .mt-1 {margin-top: 0.25rem
|
||||
}.nps-survey-root .mt-2 {margin-top: 0.5rem
|
||||
}.nps-survey-root .mt-3 {margin-top: 0.75rem
|
||||
}.nps-survey-root .mt-5 {margin-top: 1.25rem
|
||||
}.nps-survey-root .block {display: block
|
||||
}.nps-survey-root .flex {display: flex
|
||||
}.nps-survey-root .inline-flex {display: inline-flex
|
||||
}.nps-survey-root .size-5 {width: 1.25rem;height: 1.25rem
|
||||
}.nps-survey-root .size-6 {width: 1.5rem;height: 1.5rem
|
||||
}.nps-survey-root .h-11 {height: 2.75rem
|
||||
}.nps-survey-root .h-5 {height: 1.25rem
|
||||
}.nps-survey-root .h-\[2\.625rem\] {height: 2.625rem
|
||||
}.nps-survey-root .w-4 {width: 1rem
|
||||
}.nps-survey-root .w-5 {width: 1.25rem
|
||||
}.nps-survey-root .w-full {width: 100%
|
||||
}.nps-survey-root .max-w-\[30rem\] {max-width: 30rem
|
||||
}.nps-survey-root .flex-1 {flex: 1 1 0%
|
||||
}@keyframes spin {to {transform: rotate(-360deg)
|
||||
}
|
||||
}.nps-survey-root .animate-spin {animation: spin 1s linear infinite
|
||||
}.nps-survey-root .cursor-not-allowed {cursor: not-allowed
|
||||
}.nps-survey-root .cursor-pointer {cursor: pointer
|
||||
}.nps-survey-root .cursor-progress {cursor: progress
|
||||
}.nps-survey-root .items-center {align-items: center
|
||||
}.nps-survey-root .justify-start {justify-content: flex-start
|
||||
}.nps-survey-root .justify-center {justify-content: center
|
||||
}.nps-survey-root .justify-between {justify-content: space-between
|
||||
}.nps-survey-root .gap-2 {gap: 0.5rem
|
||||
}.nps-survey-root .rounded {border-radius: 0.25rem
|
||||
}.nps-survey-root .rounded-md {border-radius: 0.375rem
|
||||
}.nps-survey-root .border {border-width: 1px
|
||||
}.nps-survey-root .border-0 {border-width: 0px
|
||||
}.nps-survey-root .border-solid {border-style: solid
|
||||
}.nps-survey-root .border-none {border-style: none
|
||||
}.nps-survey-root .border-border-tertiary {--tw-border-opacity: 1;border-color: rgb(216 223 233 / var(--tw-border-opacity))
|
||||
}.nps-survey-root .border-button-disabled {--tw-border-opacity: 1;border-color: rgb(229 231 235 / var(--tw-border-opacity))
|
||||
}.nps-survey-root .border-nps-button-background {--tw-border-opacity: 1;border-color: rgb(34 113 177 / var(--tw-border-opacity))
|
||||
}.nps-survey-root .border-transparent {border-color: transparent
|
||||
}.nps-survey-root .border-white {--tw-border-opacity: 1;border-color: rgb(255 255 255 / var(--tw-border-opacity))
|
||||
}.nps-survey-root .border-zip-body-text {--tw-border-opacity: 1;border-color: rgb(var(--zip-body-text) / var(--tw-border-opacity))
|
||||
}.nps-survey-root .bg-nps-button-background {--tw-bg-opacity: 1;background-color: rgb(34 113 177 / var(--tw-bg-opacity))
|
||||
}.nps-survey-root .bg-transparent {background-color: transparent
|
||||
}.nps-survey-root .bg-white {--tw-bg-opacity: 1;background-color: rgb(255 255 255 / var(--tw-bg-opacity))
|
||||
}.nps-survey-root .p-4 {padding: 1rem
|
||||
}.nps-survey-root .px-4 {padding-right: 1rem;padding-left: 1rem
|
||||
}.nps-survey-root .px-5 {padding-right: 1.25rem;padding-left: 1.25rem
|
||||
}.nps-survey-root .px-6 {padding-right: 1.5rem;padding-left: 1.5rem
|
||||
}.nps-survey-root .py-1\.5 {padding-top: 0.375rem;padding-bottom: 0.375rem
|
||||
}.nps-survey-root .py-2 {padding-top: 0.5rem;padding-bottom: 0.5rem
|
||||
}.nps-survey-root .py-3 {padding-top: 0.75rem;padding-bottom: 0.75rem
|
||||
}.nps-survey-root .pl-0 {padding-right: 0px
|
||||
}.nps-survey-root .pl-3 {padding-right: 0.75rem
|
||||
}.nps-survey-root .pl-4 {padding-right: 1rem
|
||||
}.nps-survey-root .pl-5 {padding-right: 1.25rem
|
||||
}.nps-survey-root .pl-6 {padding-right: 1.5rem
|
||||
}.nps-survey-root .pr-3 {padding-left: 0.75rem
|
||||
}.nps-survey-root .pr-4 {padding-left: 1rem
|
||||
}.nps-survey-root .pr-5 {padding-left: 1.25rem
|
||||
}.nps-survey-root .pr-6 {padding-left: 1.5rem
|
||||
}.nps-survey-root .text-base {font-size: 1rem;line-height: 1.5rem
|
||||
}.nps-survey-root .text-lg {font-size: 1.125rem;line-height: 1.75rem
|
||||
}.nps-survey-root .text-sm {font-size: 0.875rem;line-height: 1.25rem
|
||||
}.nps-survey-root .text-xs {font-size: 0.75rem;line-height: 1rem
|
||||
}.nps-survey-root .font-bold {font-weight: 700
|
||||
}.nps-survey-root .font-medium {font-weight: 500
|
||||
}.nps-survey-root .font-normal {font-weight: 400
|
||||
}.nps-survey-root .font-semibold {font-weight: 600
|
||||
}.nps-survey-root .leading-5 {line-height: 1.25rem
|
||||
}.nps-survey-root .leading-6 {line-height: 1.5rem
|
||||
}.nps-survey-root .leading-7 {line-height: 1.75rem
|
||||
}.nps-survey-root .text-border-secondary {--tw-text-opacity: 1;color: rgb(107 114 128 / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-nps-button-background {--tw-text-opacity: 1;color: rgb(34 113 177 / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-secondary-text {--tw-text-opacity: 1;color: rgb(156 163 175 / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-white {--tw-text-opacity: 1;color: rgb(255 255 255 / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-zip-app-heading {--tw-text-opacity: 1;color: rgb(var(--zip-app-heading) / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-zip-app-inactive-icon {--tw-text-opacity: 1;color: rgb(var(--zip-app-inactive-icon) / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-zip-body-text {--tw-text-opacity: 1;color: rgb(var(--zip-body-text) / var(--tw-text-opacity))
|
||||
}.nps-survey-root .underline {text-decoration-line: underline
|
||||
}.nps-survey-root .no-underline {text-decoration-line: none
|
||||
}.nps-survey-root .opacity-25 {opacity: 0.25
|
||||
}.nps-survey-root .opacity-50 {opacity: 0.5
|
||||
}.nps-survey-root .opacity-70 {opacity: 0.7
|
||||
}.nps-survey-root .opacity-75 {opacity: 0.75
|
||||
}.nps-survey-root .shadow-lg {--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)
|
||||
}.nps-survey-root .shadow-sm {--tw-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.05);--tw-shadow-colored: 0px 1px 2px 0px var(--tw-shadow-color);box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)
|
||||
}.nps-survey-root .transition {transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);transition-duration: 150ms
|
||||
}.nps-survey-root .transition-colors {transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);transition-duration: 150ms
|
||||
}.nps-survey-root .duration-150 {transition-duration: 150ms
|
||||
}.nps-survey-root .ease-in-out {transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1)
|
||||
}.nps-survey-root {font-size: 1rem;line-height: 1.5rem
|
||||
}.nps-survey-root * {box-sizing: border-box;font-family: Figtree, sans-serif
|
||||
}.nps-survey-root .hover\:cursor-pointer:hover {cursor: pointer
|
||||
}.nps-survey-root .hover\:bg-gray-50:hover {--tw-bg-opacity: 1;background-color: rgb(249 250 251 / var(--tw-bg-opacity))
|
||||
}.nps-survey-root .focus\:z-10:focus {z-index: 10
|
||||
}.nps-survey-root .focus\:ring-1:focus {--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000)
|
||||
}.nps-survey-root .focus\:ring-nps-button-background:focus {--tw-ring-opacity: 1;--tw-ring-color: rgb(34 113 177 / var(--tw-ring-opacity))
|
||||
}.nps-survey-root .focus-visible\:outline:focus-visible {outline-style: solid
|
||||
}.nps-survey-root .focus-visible\:outline-2:focus-visible {outline-width: 2px
|
||||
}.nps-survey-root .focus-visible\:outline-offset-2:focus-visible {outline-offset: 2px
|
||||
}@media (min-width: 640px) {.nps-survey-root .sm\:rounded-lg {border-radius: 0.5rem
|
||||
}.nps-survey-root .sm\:p-5 {padding: 1.25rem
|
||||
}.nps-survey-root .sm\:text-sm {font-size: 0.875rem;line-height: 1.25rem
|
||||
}.nps-survey-root .sm\:leading-6 {line-height: 1.5rem
|
||||
}
|
||||
}
|
||||
119
Atomaste Reference/public_html/wp-content/themes/astra/inc/lib/nps-survey/dist/style-main.css
vendored
Normal file
119
Atomaste Reference/public_html/wp-content/themes/astra/inc/lib/nps-survey/dist/style-main.css
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
.nps-survey-root .invisible {visibility: hidden
|
||||
}.nps-survey-root .fixed {position: fixed
|
||||
}.nps-survey-root .absolute {position: absolute
|
||||
}.nps-survey-root .relative {position: relative
|
||||
}.nps-survey-root .inset-0 {inset: 0px
|
||||
}.nps-survey-root .bottom-2 {bottom: 0.5rem
|
||||
}.nps-survey-root .right-2 {right: 0.5rem
|
||||
}.nps-survey-root .right-3 {right: 0.75rem
|
||||
}.nps-survey-root .top-3 {top: 0.75rem
|
||||
}.nps-survey-root .isolate {isolation: isolate
|
||||
}.nps-survey-root .z-10 {z-index: 10
|
||||
}.nps-survey-root .mx-0 {margin-left: 0px;margin-right: 0px
|
||||
}.nps-survey-root .my-0 {margin-top: 0px;margin-bottom: 0px
|
||||
}.nps-survey-root .mb-0 {margin-bottom: 0px
|
||||
}.nps-survey-root .mt-1 {margin-top: 0.25rem
|
||||
}.nps-survey-root .mt-2 {margin-top: 0.5rem
|
||||
}.nps-survey-root .mt-3 {margin-top: 0.75rem
|
||||
}.nps-survey-root .mt-5 {margin-top: 1.25rem
|
||||
}.nps-survey-root .block {display: block
|
||||
}.nps-survey-root .flex {display: flex
|
||||
}.nps-survey-root .inline-flex {display: inline-flex
|
||||
}.nps-survey-root .size-5 {width: 1.25rem;height: 1.25rem
|
||||
}.nps-survey-root .size-6 {width: 1.5rem;height: 1.5rem
|
||||
}.nps-survey-root .h-11 {height: 2.75rem
|
||||
}.nps-survey-root .h-5 {height: 1.25rem
|
||||
}.nps-survey-root .h-\[2\.625rem\] {height: 2.625rem
|
||||
}.nps-survey-root .w-4 {width: 1rem
|
||||
}.nps-survey-root .w-5 {width: 1.25rem
|
||||
}.nps-survey-root .w-full {width: 100%
|
||||
}.nps-survey-root .max-w-\[30rem\] {max-width: 30rem
|
||||
}.nps-survey-root .flex-1 {flex: 1 1 0%
|
||||
}@keyframes spin {to {transform: rotate(360deg)
|
||||
}
|
||||
}.nps-survey-root .animate-spin {animation: spin 1s linear infinite
|
||||
}.nps-survey-root .cursor-not-allowed {cursor: not-allowed
|
||||
}.nps-survey-root .cursor-pointer {cursor: pointer
|
||||
}.nps-survey-root .cursor-progress {cursor: progress
|
||||
}.nps-survey-root .items-center {align-items: center
|
||||
}.nps-survey-root .justify-start {justify-content: flex-start
|
||||
}.nps-survey-root .justify-center {justify-content: center
|
||||
}.nps-survey-root .justify-between {justify-content: space-between
|
||||
}.nps-survey-root .gap-2 {gap: 0.5rem
|
||||
}.nps-survey-root .rounded {border-radius: 0.25rem
|
||||
}.nps-survey-root .rounded-md {border-radius: 0.375rem
|
||||
}.nps-survey-root .border {border-width: 1px
|
||||
}.nps-survey-root .border-0 {border-width: 0px
|
||||
}.nps-survey-root .border-solid {border-style: solid
|
||||
}.nps-survey-root .border-none {border-style: none
|
||||
}.nps-survey-root .border-border-tertiary {--tw-border-opacity: 1;border-color: rgb(216 223 233 / var(--tw-border-opacity))
|
||||
}.nps-survey-root .border-button-disabled {--tw-border-opacity: 1;border-color: rgb(229 231 235 / var(--tw-border-opacity))
|
||||
}.nps-survey-root .border-nps-button-background {--tw-border-opacity: 1;border-color: rgb(34 113 177 / var(--tw-border-opacity))
|
||||
}.nps-survey-root .border-transparent {border-color: transparent
|
||||
}.nps-survey-root .border-white {--tw-border-opacity: 1;border-color: rgb(255 255 255 / var(--tw-border-opacity))
|
||||
}.nps-survey-root .border-zip-body-text {--tw-border-opacity: 1;border-color: rgb(var(--zip-body-text) / var(--tw-border-opacity))
|
||||
}.nps-survey-root .bg-nps-button-background {--tw-bg-opacity: 1;background-color: rgb(34 113 177 / var(--tw-bg-opacity))
|
||||
}.nps-survey-root .bg-transparent {background-color: transparent
|
||||
}.nps-survey-root .bg-white {--tw-bg-opacity: 1;background-color: rgb(255 255 255 / var(--tw-bg-opacity))
|
||||
}.nps-survey-root .p-4 {padding: 1rem
|
||||
}.nps-survey-root .px-4 {padding-left: 1rem;padding-right: 1rem
|
||||
}.nps-survey-root .px-5 {padding-left: 1.25rem;padding-right: 1.25rem
|
||||
}.nps-survey-root .px-6 {padding-left: 1.5rem;padding-right: 1.5rem
|
||||
}.nps-survey-root .py-1\.5 {padding-top: 0.375rem;padding-bottom: 0.375rem
|
||||
}.nps-survey-root .py-2 {padding-top: 0.5rem;padding-bottom: 0.5rem
|
||||
}.nps-survey-root .py-3 {padding-top: 0.75rem;padding-bottom: 0.75rem
|
||||
}.nps-survey-root .pl-0 {padding-left: 0px
|
||||
}.nps-survey-root .pl-3 {padding-left: 0.75rem
|
||||
}.nps-survey-root .pl-4 {padding-left: 1rem
|
||||
}.nps-survey-root .pl-5 {padding-left: 1.25rem
|
||||
}.nps-survey-root .pl-6 {padding-left: 1.5rem
|
||||
}.nps-survey-root .pr-3 {padding-right: 0.75rem
|
||||
}.nps-survey-root .pr-4 {padding-right: 1rem
|
||||
}.nps-survey-root .pr-5 {padding-right: 1.25rem
|
||||
}.nps-survey-root .pr-6 {padding-right: 1.5rem
|
||||
}.nps-survey-root .text-base {font-size: 1rem;line-height: 1.5rem
|
||||
}.nps-survey-root .text-lg {font-size: 1.125rem;line-height: 1.75rem
|
||||
}.nps-survey-root .text-sm {font-size: 0.875rem;line-height: 1.25rem
|
||||
}.nps-survey-root .text-xs {font-size: 0.75rem;line-height: 1rem
|
||||
}.nps-survey-root .font-bold {font-weight: 700
|
||||
}.nps-survey-root .font-medium {font-weight: 500
|
||||
}.nps-survey-root .font-normal {font-weight: 400
|
||||
}.nps-survey-root .font-semibold {font-weight: 600
|
||||
}.nps-survey-root .leading-5 {line-height: 1.25rem
|
||||
}.nps-survey-root .leading-6 {line-height: 1.5rem
|
||||
}.nps-survey-root .leading-7 {line-height: 1.75rem
|
||||
}.nps-survey-root .text-border-secondary {--tw-text-opacity: 1;color: rgb(107 114 128 / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-nps-button-background {--tw-text-opacity: 1;color: rgb(34 113 177 / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-secondary-text {--tw-text-opacity: 1;color: rgb(156 163 175 / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-white {--tw-text-opacity: 1;color: rgb(255 255 255 / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-zip-app-heading {--tw-text-opacity: 1;color: rgb(var(--zip-app-heading) / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-zip-app-inactive-icon {--tw-text-opacity: 1;color: rgb(var(--zip-app-inactive-icon) / var(--tw-text-opacity))
|
||||
}.nps-survey-root .text-zip-body-text {--tw-text-opacity: 1;color: rgb(var(--zip-body-text) / var(--tw-text-opacity))
|
||||
}.nps-survey-root .underline {text-decoration-line: underline
|
||||
}.nps-survey-root .no-underline {text-decoration-line: none
|
||||
}.nps-survey-root .opacity-25 {opacity: 0.25
|
||||
}.nps-survey-root .opacity-50 {opacity: 0.5
|
||||
}.nps-survey-root .opacity-70 {opacity: 0.7
|
||||
}.nps-survey-root .opacity-75 {opacity: 0.75
|
||||
}.nps-survey-root .shadow-lg {--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)
|
||||
}.nps-survey-root .shadow-sm {--tw-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.05);--tw-shadow-colored: 0px 1px 2px 0px var(--tw-shadow-color);box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)
|
||||
}.nps-survey-root .transition {transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);transition-duration: 150ms
|
||||
}.nps-survey-root .transition-colors {transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);transition-duration: 150ms
|
||||
}.nps-survey-root .duration-150 {transition-duration: 150ms
|
||||
}.nps-survey-root .ease-in-out {transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1)
|
||||
}.nps-survey-root {font-size: 1rem;line-height: 1.5rem
|
||||
}.nps-survey-root * {box-sizing: border-box;font-family: Figtree, sans-serif
|
||||
}.nps-survey-root .hover\:cursor-pointer:hover {cursor: pointer
|
||||
}.nps-survey-root .hover\:bg-gray-50:hover {--tw-bg-opacity: 1;background-color: rgb(249 250 251 / var(--tw-bg-opacity))
|
||||
}.nps-survey-root .focus\:z-10:focus {z-index: 10
|
||||
}.nps-survey-root .focus\:ring-1:focus {--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000)
|
||||
}.nps-survey-root .focus\:ring-nps-button-background:focus {--tw-ring-opacity: 1;--tw-ring-color: rgb(34 113 177 / var(--tw-ring-opacity))
|
||||
}.nps-survey-root .focus-visible\:outline:focus-visible {outline-style: solid
|
||||
}.nps-survey-root .focus-visible\:outline-2:focus-visible {outline-width: 2px
|
||||
}.nps-survey-root .focus-visible\:outline-offset-2:focus-visible {outline-offset: 2px
|
||||
}@media (min-width: 640px) {.nps-survey-root .sm\:rounded-lg {border-radius: 0.5rem
|
||||
}.nps-survey-root .sm\:p-5 {padding: 1.25rem
|
||||
}.nps-survey-root .sm\:text-sm {font-size: 0.875rem;line-height: 1.25rem
|
||||
}.nps-survey-root .sm\:leading-6 {line-height: 1.5rem
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Loader.
|
||||
*
|
||||
* @package {{package}}
|
||||
* @since {{since}}
|
||||
*/
|
||||
|
||||
namespace NPS_Survey;
|
||||
|
||||
/**
|
||||
* Plugin_Loader
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class NPS_Survey_Plugin_Loader {
|
||||
|
||||
/**
|
||||
* Instance
|
||||
*
|
||||
* @access private
|
||||
* @var object Class Instance.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* Initiator
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return object initialized object of class.
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
spl_autoload_register( [ $this, 'autoload' ] );
|
||||
add_action( 'wp_loaded', [ $this, 'load_files' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Autoload classes.
|
||||
*
|
||||
* @param string $class class name.
|
||||
* @return void
|
||||
*/
|
||||
public function autoload( $class ) {
|
||||
if ( 0 !== strpos( $class, __NAMESPACE__ ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$class_to_load = $class;
|
||||
|
||||
$filename = strtolower(
|
||||
strval(
|
||||
preg_replace(
|
||||
[ '/^' . __NAMESPACE__ . '\\\/', '/([a-z])([A-Z])/', '/_/', '/\\\/' ],
|
||||
[ '', '$1-$2', '-', DIRECTORY_SEPARATOR ],
|
||||
$class_to_load
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$file = NPS_SURVEY_DIR . $filename . '.php';
|
||||
|
||||
// if the file redable, include it.
|
||||
if ( is_readable( $file ) ) {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Files
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load_files() {
|
||||
require_once NPS_SURVEY_DIR . 'classes/nps-survey-script.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicking this off by calling 'get_instance()' method
|
||||
*/
|
||||
NPS_Survey_Plugin_Loader::get_instance();
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: NPS Survey
|
||||
* Description: It is a nps survey library.
|
||||
* Author: Brainstorm Force
|
||||
* Version: 1.0.4
|
||||
* License: GPL v2
|
||||
* Text Domain: nps-survey
|
||||
*
|
||||
* @package {{package}}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set constants
|
||||
* Check of plugin constant is already defined
|
||||
*/
|
||||
if ( defined( 'NPS_SURVEY_FILE' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
define( 'NPS_SURVEY_FILE', __FILE__ );
|
||||
define( 'NPS_SURVEY_BASE', plugin_basename( NPS_SURVEY_FILE ) );
|
||||
define( 'NPS_SURVEY_DIR', plugin_dir_path( NPS_SURVEY_FILE ) );
|
||||
define( 'NPS_SURVEY_URL', plugins_url( '/', NPS_SURVEY_FILE ) );
|
||||
define( 'NPS_SURVEY_VER', '1.0.4' );
|
||||
require_once 'nps-survey-plugin-loader.php';
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"nps-survey": "1.0.4"
|
||||
}
|
||||
@@ -0,0 +1,719 @@
|
||||
<?php
|
||||
/**
|
||||
* Download webfonts locally.
|
||||
*
|
||||
* @package WPTT/webfont-loader
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
*
|
||||
* @since 3.6.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Download webfonts locally.
|
||||
*/
|
||||
class Astra_WebFont_Loader {
|
||||
|
||||
/**
|
||||
* The font-format.
|
||||
*
|
||||
* Use "woff" or "woff2".
|
||||
* This will change the user-agent user to make the request.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $font_format = 'woff2';
|
||||
|
||||
/**
|
||||
* The remote URL.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $remote_url;
|
||||
|
||||
/**
|
||||
* Base path.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $base_path;
|
||||
|
||||
/**
|
||||
* Base URL.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $base_url;
|
||||
|
||||
/**
|
||||
* Subfolder name.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $subfolder_name;
|
||||
|
||||
/**
|
||||
* Current blog id.
|
||||
*
|
||||
* @multisite
|
||||
* @since 4.6.0
|
||||
* @var int
|
||||
*/
|
||||
protected $current_blog_id;
|
||||
|
||||
/**
|
||||
* The fonts folder.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $fonts_folder;
|
||||
|
||||
/**
|
||||
* The local stylesheet's path.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $local_stylesheet_path;
|
||||
|
||||
/**
|
||||
* The local stylesheet's URL.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $local_stylesheet_url;
|
||||
|
||||
/**
|
||||
* The remote CSS.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $remote_styles;
|
||||
|
||||
/**
|
||||
* The final CSS.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @var string
|
||||
*/
|
||||
protected $css;
|
||||
|
||||
/**
|
||||
* Cleanup routine frequency.
|
||||
*/
|
||||
const CLEANUP_FREQUENCY = 'monthly';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Get a new instance of the object for a new URL.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @param string $url The remote URL.
|
||||
*/
|
||||
public function __construct( $url = '' ) {
|
||||
$this->remote_url = $url;
|
||||
|
||||
// Add a cleanup routine.
|
||||
$this->schedule_cleanup();
|
||||
add_action( 'astra_delete_fonts_folder', array( $this, 'astra_delete_fonts_folder' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local URL which contains the styles.
|
||||
*
|
||||
* Fallback to the remote URL if we were unable to write the file locally.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_url() {
|
||||
|
||||
// Check if the local stylesheet exists.
|
||||
if ( $this->local_file_exists() ) {
|
||||
|
||||
// Attempt to update the stylesheet. Return the local URL on success.
|
||||
if ( $this->write_stylesheet() ) {
|
||||
return $this->get_local_stylesheet_url();
|
||||
}
|
||||
}
|
||||
|
||||
$astra_font_url = file_exists( $this->get_local_stylesheet_path() ) ? $this->get_local_stylesheet_url() : $this->remote_url;
|
||||
|
||||
// If the local file exists, return its URL, with a fallback to the remote URL.
|
||||
astra_update_option( 'astra_font_url', wp_json_encode( $astra_font_url ) );
|
||||
|
||||
return $astra_font_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local stylesheet URL.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_local_stylesheet_url() {
|
||||
if ( ! $this->local_stylesheet_url ) {
|
||||
$this->local_stylesheet_url = str_replace(
|
||||
$this->get_base_path(),
|
||||
$this->get_base_url(),
|
||||
$this->get_local_stylesheet_path()
|
||||
);
|
||||
}
|
||||
return $this->local_stylesheet_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get styles with fonts downloaded locally.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_styles() {
|
||||
|
||||
// If we already have the local file, return its contents.
|
||||
$local_stylesheet_contents = $this->get_local_stylesheet_contents();
|
||||
if ( $local_stylesheet_contents ) {
|
||||
return $local_stylesheet_contents;
|
||||
}
|
||||
|
||||
// Get the remote URL contents.
|
||||
$this->remote_styles = $this->get_remote_url_contents();
|
||||
|
||||
// Get an array of locally-hosted files.
|
||||
$files = $this->get_local_files_from_css();
|
||||
|
||||
$convert_to_url = apply_filters( 'astra_convert_fonts_to_url', true );
|
||||
|
||||
foreach ( $files as $remote => $local ) {
|
||||
if ( $convert_to_url ) {
|
||||
$url = str_replace(
|
||||
$this->get_base_path(),
|
||||
$this->get_base_url(),
|
||||
$local
|
||||
);
|
||||
} else {
|
||||
$url = $local;
|
||||
}
|
||||
|
||||
$files[ $remote ] = apply_filters( 'astra_webfont_loader_file_url', $url, $remote, $local );
|
||||
}
|
||||
|
||||
$this->css = str_replace(
|
||||
array_keys( $files ),
|
||||
array_values( $files ),
|
||||
$this->remote_styles
|
||||
);
|
||||
|
||||
$this->write_stylesheet();
|
||||
|
||||
return $this->css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local stylesheet contents.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string|false Returns the remote URL contents.
|
||||
*/
|
||||
public function get_local_stylesheet_contents() {
|
||||
$local_path = $this->get_local_stylesheet_path();
|
||||
|
||||
// Check if the local stylesheet exists.
|
||||
if ( $this->local_file_exists() ) {
|
||||
|
||||
// Attempt to update the stylesheet. Return false on fail.
|
||||
if ( ! $this->write_stylesheet() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ob_start();
|
||||
include $local_path; // PHPCS:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote file contents.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string Returns the remote URL contents.
|
||||
*/
|
||||
public function get_remote_url_contents() {
|
||||
|
||||
/**
|
||||
* The user-agent we want to use.
|
||||
*
|
||||
* The default user-agent is the only one compatible with woff (not woff2)
|
||||
* which also supports unicode ranges.
|
||||
*/
|
||||
$user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8';
|
||||
|
||||
// Switch to a user-agent supporting woff2 if we don't need to support IE.
|
||||
if ( 'woff2' === $this->font_format ) {
|
||||
$user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0';
|
||||
}
|
||||
|
||||
// Get the response.
|
||||
$response = wp_remote_get( $this->remote_url, array( 'user-agent' => $user_agent ) );
|
||||
|
||||
// Get the HTTP status code.
|
||||
$status_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
// Early exit if there was an error or the font does not exists on google fonts.
|
||||
if ( is_wp_error( $response ) || 200 !== $status_code ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the CSS from our response.
|
||||
$contents = wp_remote_retrieve_body( $response );
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download files mentioned in our CSS locally.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return array Returns an array of remote URLs and their local counterparts.
|
||||
*/
|
||||
public function get_local_files_from_css() {
|
||||
$font_files = $this->get_remote_files_from_css();
|
||||
$stored = get_site_option( 'ast_downloaded_font_files', array() );
|
||||
$change = false; // If in the end this is true, we need to update the cache option.
|
||||
|
||||
if ( ! defined( 'FS_CHMOD_DIR' ) ) {
|
||||
define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) );
|
||||
}
|
||||
|
||||
// If the fonts folder don't exist, create it.
|
||||
if ( ! file_exists( $this->get_fonts_folder() ) ) {
|
||||
$this->get_filesystem()->mkdir( $this->get_fonts_folder(), FS_CHMOD_DIR );
|
||||
}
|
||||
|
||||
foreach ( $font_files as $font_family => $files ) {
|
||||
|
||||
// The folder path for this font-family.
|
||||
$folder_path = $this->get_fonts_folder() . '/' . $font_family;
|
||||
|
||||
// If the folder doesn't exist, create it.
|
||||
if ( ! file_exists( $folder_path ) ) {
|
||||
$this->get_filesystem()->mkdir( $folder_path, FS_CHMOD_DIR );
|
||||
}
|
||||
|
||||
foreach ( $files as $url ) {
|
||||
|
||||
// Get the filename.
|
||||
$filename = basename( wp_parse_url( $url, PHP_URL_PATH ) );
|
||||
$font_path = $folder_path . '/' . $filename;
|
||||
|
||||
// Check if the file already exists.
|
||||
if ( file_exists( $font_path ) ) {
|
||||
|
||||
// Skip if already cached.
|
||||
if ( isset( $stored[ $url ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add file to the cache and change the $changed var to indicate we need to update the option.
|
||||
$stored[ $url ] = $font_path;
|
||||
$change = true;
|
||||
|
||||
// Since the file exists we don't need to proceed with downloading it.
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we got this far, we need to download the file.
|
||||
*/
|
||||
// require file.php if the download_url function doesn't exist.
|
||||
if ( ! function_exists( 'download_url' ) ) {
|
||||
require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' ); // PHPCS:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound
|
||||
}
|
||||
|
||||
// Download file to temporary location.
|
||||
$tmp_path = download_url( $url );
|
||||
|
||||
// Make sure there were no errors.
|
||||
if ( is_wp_error( $tmp_path ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Move temp file to final destination.
|
||||
$success = $this->get_filesystem()->move( $tmp_path, $font_path, true );
|
||||
if ( $success ) {
|
||||
$stored[ $url ] = $font_path;
|
||||
$change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there were changes, update the option.
|
||||
if ( $change ) {
|
||||
|
||||
// Cleanup the option and then save it.
|
||||
foreach ( $stored as $url => $path ) {
|
||||
if ( ! file_exists( $path ) ) {
|
||||
unset( $stored[ $url ] );
|
||||
}
|
||||
}
|
||||
|
||||
update_site_option( 'ast_downloaded_font_files', $stored );
|
||||
}
|
||||
|
||||
return $stored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the font files and preload them.
|
||||
*/
|
||||
public function preload_local_fonts() {
|
||||
// Make sure variables are set.
|
||||
// Get the remote URL contents.
|
||||
$styles = $this->get_styles();
|
||||
|
||||
// Get an array of locally-hosted files.
|
||||
$local_font = array();
|
||||
$font_files = $this->get_remote_files_from_css( $styles );
|
||||
|
||||
foreach ( $font_files as $font_family => $files ) {
|
||||
if ( is_array( $files ) ) {
|
||||
$local_font[] = end( $files );
|
||||
}
|
||||
}
|
||||
|
||||
// Caching this for further optimization.
|
||||
update_site_option( 'astra_local_font_files', $local_font );
|
||||
|
||||
foreach ( $local_font as $key => $local_font ) {
|
||||
if ( $local_font ) {
|
||||
echo '<link rel="preload" href="' . esc_url( $local_font ) . '" as="font" type="font/' . esc_attr( $this->font_format ) . '" crossorigin>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get font files from the CSS.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @param string $remote_styles Remote stylesheet data.
|
||||
*
|
||||
* @return array Returns an array of font-families and the font-files used.
|
||||
*/
|
||||
public function get_remote_files_from_css( $remote_styles = '' ) {
|
||||
|
||||
if ( '' === $remote_styles ) {
|
||||
$remote_styles = $this->remote_styles;
|
||||
}
|
||||
|
||||
$font_faces = explode( '@font-face', $remote_styles );
|
||||
|
||||
$result = array();
|
||||
|
||||
// Loop all our font-face declarations.
|
||||
foreach ( $font_faces as $font_face ) {
|
||||
|
||||
// Make sure we only process styles inside this declaration.
|
||||
$style = explode( '}', $font_face );
|
||||
$style = isset( $style[0] ) ? $style[0] : '';
|
||||
|
||||
// Sanity check.
|
||||
if ( false === strpos( $style, 'font-family' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get an array of our font-families.
|
||||
preg_match_all( '/font-family.*?\;/', $style, $matched_font_families );
|
||||
|
||||
// Get an array of our font-files.
|
||||
preg_match_all( '/url\(.*?\)/i', $style, $matched_font_files );
|
||||
|
||||
// Get the font-family name.
|
||||
$font_family = 'unknown';
|
||||
if ( isset( $matched_font_families[0] ) && isset( $matched_font_families[0][0] ) ) {
|
||||
$font_family = rtrim( ltrim( $matched_font_families[0][0], 'font-family:' ), ';' );
|
||||
$font_family = trim( str_replace( array( "'", ';' ), '', $font_family ) );
|
||||
$font_family = sanitize_key( strtolower( str_replace( ' ', '-', $font_family ) ) );
|
||||
}
|
||||
|
||||
// Make sure the font-family is set in our array.
|
||||
if ( ! isset( $result[ $font_family ] ) ) {
|
||||
$result[ $font_family ] = array();
|
||||
}
|
||||
|
||||
// Get files for this font-family and add them to the array.
|
||||
foreach ( $matched_font_files as $match ) {
|
||||
|
||||
// Sanity check.
|
||||
if ( ! isset( $match[0] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the file URL.
|
||||
$result[ $font_family ][] = rtrim( ltrim( $match[0], 'url(' ), ')' );
|
||||
}
|
||||
|
||||
// Make sure we have unique items.
|
||||
// We're using array_flip here instead of array_unique for improved performance.
|
||||
$result[ $font_family ] = array_flip( array_flip( $result[ $font_family ] ) );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the CSS to the filesystem.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string|false Returns the absolute path of the file on success, or false on fail.
|
||||
*/
|
||||
protected function write_stylesheet() {
|
||||
$file_path = $this->get_local_stylesheet_path();
|
||||
$filesystem = $this->get_filesystem();
|
||||
|
||||
if ( ! defined( 'FS_CHMOD_DIR' ) ) {
|
||||
define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) );
|
||||
}
|
||||
|
||||
// If the folder doesn't exist, create it.
|
||||
if ( ! file_exists( $this->get_fonts_folder() ) ) {
|
||||
$this->get_filesystem()->mkdir( $this->get_fonts_folder(), FS_CHMOD_DIR );
|
||||
}
|
||||
|
||||
// If the file doesn't exist, create it. Return false if it can not be created.
|
||||
if ( ! $filesystem->exists( $file_path ) && ! $filesystem->touch( $file_path ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we got this far, we need to write the file.
|
||||
// Get the CSS.
|
||||
if ( null === $this->css ) {
|
||||
$this->get_styles();
|
||||
}
|
||||
|
||||
// Put the contents in the file. Return false if that fails.
|
||||
if ( ! $filesystem->put_contents( $file_path, $this->css ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stylesheet path.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_local_stylesheet_path() {
|
||||
if ( ! $this->local_stylesheet_path ) {
|
||||
$this->local_stylesheet_path = $this->get_fonts_folder() . '/' . $this->get_local_stylesheet_filename() . '.css';
|
||||
}
|
||||
return $this->local_stylesheet_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local stylesheet filename.
|
||||
*
|
||||
* This is a hash, generated from the site-URL, the wp-content path and the URL.
|
||||
* This way we can avoid issues with sites changing their URL, or the wp-content path etc.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_local_stylesheet_filename() {
|
||||
return apply_filters( 'astra_local_font_file_name', 'astra-local-fonts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the font-format to be used.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @param string $format The format to be used. Use "woff" or "woff2".
|
||||
* @return void
|
||||
*/
|
||||
public function set_font_format( $format = 'woff2' ) {
|
||||
$this->font_format = apply_filters( 'astra_local_google_fonts_format', $format );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the local stylesheet exists.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return bool
|
||||
*/
|
||||
public function local_file_exists() {
|
||||
return ( ! file_exists( $this->get_local_stylesheet_path() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base path.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_base_path() {
|
||||
if ( ! $this->base_path ) {
|
||||
$this->base_path = apply_filters( 'astra_local_fonts_base_path', $this->get_filesystem()->wp_content_dir() );
|
||||
}
|
||||
return $this->base_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URL.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_base_url() {
|
||||
if ( ! $this->base_url ) {
|
||||
$this->base_url = apply_filters( 'astra_local_fonts_base_url', content_url() );
|
||||
}
|
||||
return $this->base_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subfolder name.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_subfolder_name() {
|
||||
if ( ! $this->subfolder_name ) {
|
||||
$this->subfolder_name = apply_filters( 'astra_local_fonts_directory_name', 'astra-local-fonts' );
|
||||
}
|
||||
return $this->subfolder_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current blog id if current WordPress setup is a multisite setup.
|
||||
*
|
||||
* @since 4.6.0
|
||||
* @return void|int Returns integer if current WP setup is multisite.
|
||||
*/
|
||||
public function get_current_blog_id() {
|
||||
|
||||
if ( ! is_multisite() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->current_blog_id ) {
|
||||
$this->current_blog_id = apply_filters( 'astra_local_fonts_current_blog_id', get_current_blog_id() );
|
||||
}
|
||||
|
||||
return $this->current_blog_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder for fonts.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_fonts_folder() {
|
||||
if ( ! $this->fonts_folder ) {
|
||||
$this->fonts_folder = $this->get_base_path();
|
||||
if ( $this->get_subfolder_name() ) {
|
||||
$this->fonts_folder .= '/' . $this->get_subfolder_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix: Local google fonts issue in multisite.
|
||||
*
|
||||
* This block of code primarily does 3 things:
|
||||
* 1. Checks if we have blog id.
|
||||
* 2. If we have blog id, then checks if subfolder "$this->get_subfolder_name()" exists. If not, creates the subfolder.
|
||||
* 3. Then, finally, creates the child folders inside the subfolder by the current blog id.
|
||||
*
|
||||
* Ref: GH Issue: #5291, [AST-3438]
|
||||
* @since 4.6.0
|
||||
*/
|
||||
if ( $this->get_current_blog_id() ) {
|
||||
if ( ! file_exists( $this->fonts_folder ) ) {
|
||||
// Lets create subfolder first if it does not exists.
|
||||
$this->get_filesystem()->mkdir( $this->get_fonts_folder(), FS_CHMOD_DIR );
|
||||
}
|
||||
|
||||
/**
|
||||
* This helps us to isolate the google fonts files according to the sub sites.
|
||||
* Which will also helps in isolated flushing of local font files without effecting
|
||||
* the font files and generated css files of other sub sites.
|
||||
*/
|
||||
$this->fonts_folder .= '/' . $this->get_current_blog_id();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->fonts_folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a cleanup.
|
||||
*
|
||||
* Deletes the fonts files on a regular basis.
|
||||
* This way font files will get updated regularly,
|
||||
* and we avoid edge cases where unused files remain in the server.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return void
|
||||
*/
|
||||
public function schedule_cleanup() {
|
||||
if ( ! is_multisite() || ( is_multisite() && is_main_site() ) ) {
|
||||
if ( ! wp_next_scheduled( 'astra_delete_fonts_folder' ) && ! wp_installing() ) {
|
||||
wp_schedule_event( time(), self::CLEANUP_FREQUENCY, 'astra_delete_fonts_folder' ); // phpcs:ignore WPThemeReview.PluginTerritory.ForbiddenFunctions.cron_functionality_wp_schedule_event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the fonts folder.
|
||||
*
|
||||
* This runs as part of a cleanup routine.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return bool
|
||||
*/
|
||||
public function astra_delete_fonts_folder() {
|
||||
// Delete previously created supportive options.
|
||||
astra_delete_option( 'astra_font_url' );
|
||||
delete_site_option( 'astra_local_font_files' );
|
||||
return $this->get_filesystem()->delete( $this->get_fonts_folder(), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filesystem.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @return \WP_Filesystem_Base
|
||||
*/
|
||||
protected function get_filesystem() {
|
||||
|
||||
// Using WP_Filesystem to manage the local download of fonts. This ensures proper functionality of the theme by handling file operations securely and consistently -- This is a TRT-recommended webfont library.
|
||||
global $wp_filesystem;
|
||||
|
||||
// If the filesystem has not been instantiated yet, do it here.
|
||||
if ( ! $wp_filesystem ) {
|
||||
if ( ! function_exists( 'WP_Filesystem' ) ) {
|
||||
require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' ); // PHPCS:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound
|
||||
}
|
||||
WP_Filesystem();
|
||||
}
|
||||
return $wp_filesystem;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create instance of Astra_WebFont_Loader class.
|
||||
*
|
||||
* @param string $font_url Google font URL to set data.
|
||||
* @return object
|
||||
* @since 3.6.0
|
||||
*/
|
||||
function astra_webfont_loader_instance( $font_url = '' ) {
|
||||
return new Astra_WebFont_Loader( $font_url );
|
||||
}
|
||||
Reference in New Issue
Block a user