diff --git a/packages/nextgenthemes/wp-shared/composer.json b/packages/nextgenthemes/wp-shared/composer.json
new file mode 100644
index 00000000..11c7a1c5
--- /dev/null
+++ b/packages/nextgenthemes/wp-shared/composer.json
@@ -0,0 +1,33 @@
+{
+ "name": "nextgenthemes/wp-shared",
+ "type": "wp-package",
+ "license": "GPL-3.0",
+ "autoload": {
+ "psr-4": {
+ "WP\\": "includes/WP"
+ },
+ "files": [
+ "includes/WP/fn-asset-helpers.php",
+ "includes/WP/fn-compat.php",
+ "includes/WP/fn-deprecated.php",
+ "includes/WP/fn-array.php",
+ "includes/WP/fn-string.php",
+ "includes/WP/fn-misc.php",
+ "includes/WP/fn-settings.php",
+ "includes/WP/fn-license.php",
+ "includes/WP/fn-remote-get.php",
+ "includes/WP/Admin/load-admin-files.php"
+ ]
+ },
+ "authors": [
+ {
+ "name": "Nicolas Jonas"
+ }
+ ],
+ "require": {
+ "php": ">=7.4"
+ },
+ "scripts": {
+ "update": "wget https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js -O ./includes/WP/Admin/alpine.js"
+ }
+}
diff --git a/packages/nextgenthemes/wp-shared/includes/WP/Admin/EDD/PluginUpdater.php b/packages/nextgenthemes/wp-shared/includes/WP/Admin/EDD/PluginUpdater.php
new file mode 100755
index 00000000..914f9080
--- /dev/null
+++ b/packages/nextgenthemes/wp-shared/includes/WP/Admin/EDD/PluginUpdater.php
@@ -0,0 +1,644 @@
+api_url = trailingslashit( $_api_url );
+ $this->api_data = $_api_data;
+ $this->plugin_file = $_plugin_file;
+ $this->name = plugin_basename( $_plugin_file );
+ $this->slug = basename( $_plugin_file, '.php' );
+ $this->version = $_api_data['version'];
+ $this->wp_override = isset( $_api_data['wp_override'] ) ? (bool) $_api_data['wp_override'] : false;
+ $this->beta = ! empty( $this->api_data['beta'] ) ? true : false;
+ $this->failed_request_cache_key = 'edd_sl_failed_http_' . md5( $this->api_url );
+
+ $edd_plugin_data[ $this->slug ] = $this->api_data;
+
+ /**
+ * Fires after the $edd_plugin_data is setup.
+ *
+ * @since x.x.x
+ *
+ * @param array $edd_plugin_data Array of EDD SL plugin data.
+ */
+ do_action( 'post_edd_sl_plugin_updater_setup', $edd_plugin_data );
+
+ // Set up hooks.
+ $this->init();
+
+ }
+
+ /**
+ * Set up WordPress filters to hook into WP's update process.
+ *
+ * @uses add_filter()
+ *
+ * @return void
+ */
+ public function init() {
+
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_update' ) );
+ add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
+ add_action( 'after_plugin_row', array( $this, 'show_update_notification' ), 10, 2 );
+ add_action( 'admin_init', array( $this, 'show_changelog' ) );
+
+ }
+
+ /**
+ * Check for Updates at the defined API endpoint and modify the update array.
+ *
+ * This function dives into the update API just when WordPress creates its update array,
+ * then adds a custom API call and injects the custom plugin data retrieved from the API.
+ * It is reassembled from parts of the native WordPress plugin update code.
+ * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
+ *
+ * @uses api_request()
+ *
+ * @param array $_transient_data Update array build by WordPress.
+ * @return array Modified update array with custom plugin data.
+ */
+ public function check_update( $_transient_data ) {
+
+ global $pagenow;
+
+ if ( ! is_object( $_transient_data ) ) {
+ $_transient_data = new \stdClass();
+ }
+
+ if ( ! empty( $_transient_data->response ) && ! empty( $_transient_data->response[ $this->name ] ) && false === $this->wp_override ) {
+ return $_transient_data;
+ }
+
+ $current = $this->get_repo_api_data();
+ if ( false !== $current && is_object( $current ) && isset( $current->new_version ) ) {
+ if ( version_compare( $this->version, $current->new_version, '<' ) ) {
+ $_transient_data->response[ $this->name ] = $current;
+ } else {
+ // Populating the no_update information is required to support auto-updates in WordPress 5.5.
+ $_transient_data->no_update[ $this->name ] = $current;
+ }
+ }
+ $_transient_data->last_checked = time();
+ $_transient_data->checked[ $this->name ] = $this->version;
+
+ return $_transient_data;
+ }
+
+ /**
+ * Get repo API data from store.
+ * Save to cache.
+ *
+ * @return \stdClass
+ */
+ public function get_repo_api_data() {
+ $version_info = $this->get_cached_version_info();
+
+ if ( false === $version_info ) {
+ $version_info = $this->api_request(
+ 'plugin_latest_version',
+ array(
+ 'slug' => $this->slug,
+ 'beta' => $this->beta,
+ )
+ );
+ if ( ! $version_info ) {
+ return false;
+ }
+
+ // This is required for your plugin to support auto-updates in WordPress 5.5.
+ $version_info->plugin = $this->name;
+ $version_info->id = $this->name;
+
+ $this->set_version_info_cache( $version_info );
+ }
+
+ return $version_info;
+ }
+
+ /**
+ * Show the update notification on multisite subsites.
+ *
+ * @param string $file
+ * @param array $plugin
+ */
+ public function show_update_notification( $file, $plugin ) {
+
+ // Return early if in the network admin, or if this is not a multisite install.
+ if ( is_network_admin() || ! is_multisite() ) {
+ return;
+ }
+
+ // Allow single site admins to see that an update is available.
+ if ( ! current_user_can( 'activate_plugins' ) ) {
+ return;
+ }
+
+ if ( $this->name !== $file ) {
+ return;
+ }
+
+ // Do not print any message if update does not exist.
+ $update_cache = get_site_transient( 'update_plugins' );
+
+ if ( ! isset( $update_cache->response[ $this->name ] ) ) {
+ if ( ! is_object( $update_cache ) ) {
+ $update_cache = new \stdClass();
+ }
+ $update_cache->response[ $this->name ] = $this->get_repo_api_data();
+ }
+
+ // Return early if this plugin isn't in the transient->response or if the site is running the current or newer version of the plugin.
+ if ( empty( $update_cache->response[ $this->name ] ) || version_compare( $this->version, $update_cache->response[ $this->name ]->new_version, '>=' ) ) {
+ return;
+ }
+
+ printf(
+ '
',
+ $this->slug,
+ $file,
+ in_array( $this->name, $this->get_active_plugins(), true ) ? 'active' : 'inactive'
+ );
+
+ echo '';
+ echo '';
+
+ $changelog_link = '';
+ if ( ! empty( $update_cache->response[ $this->name ]->sections->changelog ) ) {
+ $changelog_link = add_query_arg(
+ array(
+ 'edd_sl_action' => 'view_plugin_changelog',
+ 'plugin' => urlencode( $this->name ),
+ 'slug' => urlencode( $this->slug ),
+ 'TB_iframe' => 'true',
+ 'width' => 77,
+ 'height' => 911,
+ ),
+ self_admin_url( 'index.php' )
+ );
+ }
+ $update_link = add_query_arg(
+ array(
+ 'action' => 'upgrade-plugin',
+ 'plugin' => urlencode( $this->name ),
+ ),
+ self_admin_url( 'update.php' )
+ );
+
+ printf(
+ /* translators: the plugin name. */
+ esc_html__( 'There is a new version of %1$s available.', 'easy-digital-downloads' ),
+ esc_html( $plugin['Name'] )
+ );
+
+ if ( ! current_user_can( 'update_plugins' ) ) {
+ echo ' ';
+ esc_html_e( 'Contact your network administrator to install the update.', 'easy-digital-downloads' );
+ } elseif ( empty( $update_cache->response[ $this->name ]->package ) && ! empty( $changelog_link ) ) {
+ echo ' ';
+ printf(
+ /* translators: 1. opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate. */
+ __( '%1$sView version %2$s details%3$s.', 'easy-digital-downloads' ),
+ '',
+ esc_html( $update_cache->response[ $this->name ]->new_version ),
+ ''
+ );
+ } elseif ( ! empty( $changelog_link ) ) {
+ echo ' ';
+ printf(
+ __( '%1$sView version %2$s details%3$s or %4$supdate now%5$s.', 'easy-digital-downloads' ),
+ '',
+ esc_html( $update_cache->response[ $this->name ]->new_version ),
+ '',
+ '',
+ ''
+ );
+ } else {
+ printf(
+ ' %1$s%2$s%3$s',
+ '',
+ esc_html__( 'Update now.', 'easy-digital-downloads' ),
+ ''
+ );
+ }
+
+ do_action( "in_plugin_update_message-{$file}", $plugin, $plugin );
+
+ echo ' |
';
+ }
+
+ /**
+ * Gets the plugins active in a multisite network.
+ *
+ * @return array
+ */
+ private function get_active_plugins() {
+ $active_plugins = (array) get_option( 'active_plugins' );
+ $active_network_plugins = (array) get_site_option( 'active_sitewide_plugins' );
+
+ return array_merge( $active_plugins, array_keys( $active_network_plugins ) );
+ }
+
+ /**
+ * Updates information on the "View version x.x details" page with custom data.
+ *
+ * @uses api_request()
+ *
+ * @param mixed $_data
+ * @param string $_action
+ * @param object $_args
+ * @return object $_data
+ */
+ public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
+
+ if ( 'plugin_information' !== $_action ) {
+
+ return $_data;
+
+ }
+
+ if ( ! isset( $_args->slug ) || ( $_args->slug !== $this->slug ) ) {
+
+ return $_data;
+
+ }
+
+ $to_send = array(
+ 'slug' => $this->slug,
+ 'is_ssl' => is_ssl(),
+ 'fields' => array(
+ 'banners' => array(),
+ 'reviews' => false,
+ 'icons' => array(),
+ ),
+ );
+
+ // Get the transient where we store the api request for this plugin for 24 hours
+ $edd_api_request_transient = $this->get_cached_version_info();
+
+ //If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now.
+ if ( empty( $edd_api_request_transient ) ) {
+
+ $api_response = $this->api_request( 'plugin_information', $to_send );
+
+ // Expires in 3 hours
+ $this->set_version_info_cache( $api_response );
+
+ if ( false !== $api_response ) {
+ $_data = $api_response;
+ }
+ } else {
+ $_data = $edd_api_request_transient;
+ }
+
+ // Convert sections into an associative array, since we're getting an object, but Core expects an array.
+ if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) {
+ $_data->sections = $this->convert_object_to_array( $_data->sections );
+ }
+
+ // Convert banners into an associative array, since we're getting an object, but Core expects an array.
+ if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) {
+ $_data->banners = $this->convert_object_to_array( $_data->banners );
+ }
+
+ // Convert icons into an associative array, since we're getting an object, but Core expects an array.
+ if ( isset( $_data->icons ) && ! is_array( $_data->icons ) ) {
+ $_data->icons = $this->convert_object_to_array( $_data->icons );
+ }
+
+ // Convert contributors into an associative array, since we're getting an object, but Core expects an array.
+ if ( isset( $_data->contributors ) && ! is_array( $_data->contributors ) ) {
+ $_data->contributors = $this->convert_object_to_array( $_data->contributors );
+ }
+
+ if ( ! isset( $_data->plugin ) ) {
+ $_data->plugin = $this->name;
+ }
+
+ return $_data;
+ }
+
+ /**
+ * Convert some objects to arrays when injecting data into the update API
+ *
+ * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON
+ * decoding, they are objects. This method allows us to pass in the object and return an associative array.
+ *
+ * @since 3.6.5
+ *
+ * @param stdClass $data
+ *
+ * @return array
+ */
+ private function convert_object_to_array( $data ) {
+ if ( ! is_array( $data ) && ! is_object( $data ) ) {
+ return array();
+ }
+ $new_data = array();
+ foreach ( $data as $key => $value ) {
+ $new_data[ $key ] = is_object( $value ) ? $this->convert_object_to_array( $value ) : $value;
+ }
+
+ return $new_data;
+ }
+
+ /**
+ * Disable SSL verification in order to prevent download update failures
+ *
+ * @param array $args
+ * @param string $url
+ * @return object $array
+ */
+ public function http_request_args( $args, $url ) {
+
+ if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
+ $args['sslverify'] = $this->verify_ssl();
+ }
+ return $args;
+
+ }
+
+ /**
+ * Calls the API and, if successfull, returns the object delivered by the API.
+ *
+ * @uses get_bloginfo()
+ * @uses wp_remote_post()
+ * @uses is_wp_error()
+ *
+ * @param string $_action The requested action.
+ * @param array $_data Parameters for the API action.
+ * @return false|object|void
+ */
+ private function api_request( $_action, $_data ) {
+ $data = array_merge( $this->api_data, $_data );
+
+ if ( $data['slug'] !== $this->slug ) {
+ return;
+ }
+
+ // Don't allow a plugin to ping itself
+ if ( trailingslashit( home_url() ) === $this->api_url ) {
+ return false;
+ }
+
+ if ( $this->request_recently_failed() ) {
+ return false;
+ }
+
+ return $this->get_version_from_remote();
+ }
+
+ /**
+ * Determines if a request has recently failed.
+ *
+ * @since 1.9.1
+ *
+ * @return bool
+ */
+ private function request_recently_failed() {
+ $failed_request_details = get_option( $this->failed_request_cache_key );
+
+ // Request has never failed.
+ if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) {
+ return false;
+ }
+
+ /*
+ * Request previously failed, but the timeout has expired.
+ * This means we're allowed to try again.
+ */
+ if ( time() > $failed_request_details ) {
+ delete_option( $this->failed_request_cache_key );
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Logs a failed HTTP request for this API URL.
+ * We set a timestamp for 1 hour from now. This prevents future API requests from being
+ * made to this domain for 1 hour. Once the timestamp is in the past, API requests
+ * will be allowed again. This way if the site is down for some reason we don't bombard
+ * it with failed API requests.
+ *
+ * @see EDD_SL_Plugin_Updater::request_recently_failed
+ *
+ * @since 1.9.1
+ */
+ private function log_failed_request() {
+ update_option( $this->failed_request_cache_key, strtotime( '+1 hour' ) );
+ }
+
+ /**
+ * If available, show the changelog for sites in a multisite install.
+ */
+ public function show_changelog() {
+
+ if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) {
+ return;
+ }
+
+ if ( empty( $_REQUEST['plugin'] ) ) {
+ return;
+ }
+
+ if ( empty( $_REQUEST['slug'] ) || $this->slug !== $_REQUEST['slug'] ) {
+ return;
+ }
+
+ if ( ! current_user_can( 'update_plugins' ) ) {
+ wp_die( esc_html__( 'You do not have permission to install plugin updates', 'easy-digital-downloads' ), esc_html__( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
+ }
+
+ $version_info = $this->get_repo_api_data();
+ if ( isset( $version_info->sections ) ) {
+ $sections = $this->convert_object_to_array( $version_info->sections );
+ if ( ! empty( $sections['changelog'] ) ) {
+ echo '' . wp_kses_post( $sections['changelog'] ) . '
';
+ }
+ }
+
+ exit;
+ }
+
+ /**
+ * Gets the current version information from the remote site.
+ *
+ * @return array|false
+ */
+ private function get_version_from_remote() {
+ $api_params = array(
+ 'edd_action' => 'get_version',
+ 'license' => ! empty( $this->api_data['license'] ) ? $this->api_data['license'] : '',
+ 'item_name' => isset( $this->api_data['item_name'] ) ? $this->api_data['item_name'] : false,
+ 'item_id' => isset( $this->api_data['item_id'] ) ? $this->api_data['item_id'] : false,
+ 'version' => isset( $this->api_data['version'] ) ? $this->api_data['version'] : false,
+ 'slug' => $this->slug,
+ 'author' => $this->api_data['author'],
+ 'url' => home_url(),
+ 'beta' => $this->beta,
+ 'php_version' => phpversion(),
+ 'wp_version' => get_bloginfo( 'version' ),
+ );
+
+ /**
+ * Filters the parameters sent in the API request.
+ *
+ * @param array $api_params The array of data sent in the request.
+ * @param array $this->api_data The array of data set up in the class constructor.
+ * @param string $this->plugin_file The full path and filename of the file.
+ */
+ $api_params = apply_filters( 'edd_sl_plugin_updater_api_params', $api_params, $this->api_data, $this->plugin_file );
+
+ $request = wp_remote_post(
+ $this->api_url,
+ array(
+ 'timeout' => 15,
+ 'sslverify' => $this->verify_ssl(),
+ 'body' => $api_params,
+ )
+ );
+
+ if ( is_wp_error( $request ) || ( 200 !== wp_remote_retrieve_response_code( $request ) ) ) {
+ $this->log_failed_request();
+
+ return false;
+ }
+
+ $request = json_decode( wp_remote_retrieve_body( $request ) );
+
+ if ( $request && isset( $request->sections ) ) {
+ $request->sections = maybe_unserialize( $request->sections );
+ } else {
+ $request = false;
+ }
+
+ if ( $request && isset( $request->banners ) ) {
+ $request->banners = maybe_unserialize( $request->banners );
+ }
+
+ if ( $request && isset( $request->icons ) ) {
+ $request->icons = maybe_unserialize( $request->icons );
+ }
+
+ if ( ! empty( $request->sections ) ) {
+ foreach ( $request->sections as $key => $section ) {
+ $request->$key = (array) $section;
+ }
+ }
+
+ return $request;
+ }
+
+ /**
+ * Get the version info from the cache, if it exists.
+ *
+ * @param string $cache_key
+ * @return object
+ */
+ public function get_cached_version_info( $cache_key = '' ) {
+
+ if ( empty( $cache_key ) ) {
+ $cache_key = $this->get_cache_key();
+ }
+
+ $cache = get_option( $cache_key );
+
+ // Cache is expired
+ if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
+ return false;
+ }
+
+ // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
+ $cache['value'] = json_decode( $cache['value'] );
+ if ( ! empty( $cache['value']->icons ) ) {
+ $cache['value']->icons = (array) $cache['value']->icons;
+ }
+
+ return $cache['value'];
+
+ }
+
+ /**
+ * Adds the plugin version information to the database.
+ *
+ * @param string $value
+ * @param string $cache_key
+ */
+ public function set_version_info_cache( $value = '', $cache_key = '' ) {
+
+ if ( empty( $cache_key ) ) {
+ $cache_key = $this->get_cache_key();
+ }
+
+ $data = array(
+ 'timeout' => strtotime( '+3 hours', time() ),
+ 'value' => wp_json_encode( $value ),
+ );
+
+ update_option( $cache_key, $data, 'no' );
+
+ // Delete the duplicate option
+ delete_option( 'edd_api_request_' . md5( serialize( $this->slug . $this->api_data['license'] . $this->beta ) ) );
+ }
+
+ /**
+ * Returns if the SSL of the store should be verified.
+ *
+ * @since 1.6.13
+ * @return bool
+ */
+ private function verify_ssl() {
+ return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
+ }
+
+ /**
+ * Gets the unique key (option name) for a plugin.
+ *
+ * @since 1.9.0
+ * @return string
+ */
+ private function get_cache_key() {
+ $string = $this->slug . $this->api_data['license'] . $this->beta;
+
+ return 'edd_sl_' . md5( serialize( $string ) );
+ }
+
+}
diff --git a/packages/nextgenthemes/wp-shared/includes/WP/Admin/EDD/ThemeUpdater.php b/packages/nextgenthemes/wp-shared/includes/WP/Admin/EDD/ThemeUpdater.php
new file mode 100755
index 00000000..4410b59c
--- /dev/null
+++ b/packages/nextgenthemes/wp-shared/includes/WP/Admin/EDD/ThemeUpdater.php
@@ -0,0 +1,160 @@
+ 'http://easydigitaldownloads.com',
+ 'request_data' => array(),
+ 'theme_slug' => get_template(),
+ 'item_name' => '',
+ 'license' => '',
+ 'version' => '',
+ 'author' => '',
+ )
+ );
+ extract( $args );
+
+ $this->license = $license;
+ $this->item_name = $item_name;
+ $this->version = $version;
+ $this->theme_slug = sanitize_key( $theme_slug );
+ $this->author = $author;
+ $this->remote_api_url = $remote_api_url;
+ $this->response_key = $this->theme_slug . '-update-response';
+ $this->strings = $strings;
+
+ add_filter( 'site_transient_update_themes', array( &$this, 'theme_update_transient' ) );
+ add_filter( 'delete_site_transient_update_themes', array( &$this, 'delete_theme_update_transient' ) );
+ add_action( 'load-update-core.php', array( &$this, 'delete_theme_update_transient' ) );
+ add_action( 'load-themes.php', array( &$this, 'delete_theme_update_transient' ) );
+ add_action( 'load-themes.php', array( &$this, 'load_themes_screen' ) );
+ }
+
+ function load_themes_screen() {
+ add_thickbox();
+ add_action( 'admin_notices', array( &$this, 'update_nag' ) );
+ }
+
+ function update_nag() {
+
+ $strings = $this->strings;
+
+ $theme = wp_get_theme( $this->theme_slug );
+
+ $api_response = get_transient( $this->response_key );
+
+ if ( false === $api_response ) {
+ return;
+ }
+
+ $update_url = wp_nonce_url( 'update.php?action=upgrade-theme&theme=' . urlencode( $this->theme_slug ), 'upgrade-theme_' . $this->theme_slug );
+ $update_onclick = ' onclick="if ( confirm(\'' . esc_js( $strings['update-notice'] ) . '\') ) {return true;}return false;"';
+
+ if ( version_compare( $this->version, $api_response->new_version, '<' ) ) {
+
+ echo '';
+ printf(
+ $strings['update-available'],
+ $theme->get( 'Name' ),
+ $api_response->new_version,
+ '#TB_inline?width=640&inlineId=' . $this->theme_slug . '_changelog',
+ $theme->get( 'Name' ),
+ $update_url,
+ $update_onclick
+ );
+ echo '
';
+ echo '';
+ echo wpautop( $api_response->sections['changelog'] );
+ echo '
';
+ }
+ }
+
+ function theme_update_transient( $value ) {
+ $update_data = $this->check_for_update();
+ if ( $update_data ) {
+ $value->response[ $this->theme_slug ] = $update_data;
+ }
+ return $value;
+ }
+
+ function delete_theme_update_transient() {
+ delete_transient( $this->response_key );
+ }
+
+ function check_for_update() {
+
+ $update_data = get_transient( $this->response_key );
+
+ if ( false === $update_data ) {
+ $failed = false;
+
+ $api_params = array(
+ 'edd_action' => 'get_version',
+ 'license' => $this->license,
+ 'name' => $this->item_name,
+ 'slug' => $this->theme_slug,
+ 'author' => $this->author,
+ );
+
+ $response = wp_remote_post(
+ $this->remote_api_url,
+ array(
+ 'timeout' => 15,
+ 'body' => $api_params,
+ )
+ );
+
+ // Make sure the response was successful
+ if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) {
+ $failed = true;
+ }
+
+ $update_data = json_decode( wp_remote_retrieve_body( $response ) );
+
+ if ( ! is_object( $update_data ) ) {
+ $failed = true;
+ }
+
+ // If the response failed, try again in 30 minutes
+ if ( $failed ) {
+ $data = new \stdClass();
+ $data->new_version = $this->version;
+ set_transient( $this->response_key, $data, strtotime( '+30 minutes' ) );
+ return false;
+ }
+
+ // If the status is 'ok', return the update arguments
+ if ( ! $failed ) {
+ $update_data->sections = maybe_unserialize( $update_data->sections );
+ set_transient( $this->response_key, $update_data, strtotime( '+12 hours' ) );
+ }
+ }
+
+ if ( version_compare( $this->version, $update_data->new_version, '>=' ) ) {
+ return false;
+ }
+
+ return (array) $update_data;
+ }
+
+}
diff --git a/packages/nextgenthemes/wp-shared/includes/WP/Admin/Notices.php b/packages/nextgenthemes/wp-shared/includes/WP/Admin/Notices.php
new file mode 100755
index 00000000..d4408c30
--- /dev/null
+++ b/packages/nextgenthemes/wp-shared/includes/WP/Admin/Notices.php
@@ -0,0 +1,587 @@
+
+ *
+ * @author Nicolas Jonas
+ * @author Julien Liabeuf
+ * @version 1.2.1
+ * @license GPL-3.0
+ * @link https://nextgenthemes.com
+ * @link https://github.com/julien731/WP-Dismissible-Notices-Handler/blob/develop/handler.php
+ * @copyright 2021 Nicolas Jonas, 2018 Julien Liabeuf
+ */
+
+if ( 'always' ) {
+
+ final class Notices {
+
+ /**
+ * @var Notices Holds the unique instance of the handler
+ * @since 1.0
+ */
+ private static $instance;
+
+ /**
+ * Library version
+ *
+ * @since 1.0
+ * @var string
+ */
+ public $version = '1.2.1';
+
+ /**
+ * Required version of PHP.
+ *
+ * @since 1.0
+ * @var string
+ */
+ public $php_version_required = '5.5';
+
+ /**
+ * Minimum version of WordPress required to use the library
+ *
+ * @since 1.0
+ * @var string
+ */
+ public $wordpress_version_required = '4.7';
+
+ /**
+ * @var array Holds all our registered notices
+ * @since 1.0
+ */
+ private $notices;
+
+ /**
+ * Instantiate and return the unique Notices object
+ *
+ * @since 1.0
+ * @return object Notices Unique instance of the handler
+ */
+ public static function instance(): object {
+
+ if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Notices ) ) {
+ self::$instance = new Notices();
+ self::$instance->init();
+ }
+
+ return self::$instance;
+
+ }
+
+ /**
+ * Initialize the library
+ *
+ * @since 1.0
+ */
+ private function init(): void {
+
+ // Make sure WordPress is compatible
+ if ( ! self::$instance->is_wp_compatible() ) {
+ self::$instance->spit_error(
+ sprintf(
+ /* translators: %s: required WordPress version */
+ esc_html__( 'The library can not be used because your version of WordPress is too old. You need version %s at least.', 'advanced-responsive-video-embedder' ),
+ self::$instance->wordpress_version_required
+ )
+ );
+
+ return;
+ }
+
+ // Make sure PHP is compatible
+ if ( ! self::$instance->is_php_compatible() ) {
+ self::$instance->spit_error(
+ sprintf(
+ /* translators: %s: required php version */
+ esc_html__( 'The library can not be used because your version of PHP is too old. You need version %s at least.', 'advanced-responsive-video-embedder' ),
+ self::$instance->php_version_required
+ )
+ );
+
+ return;
+ }
+
+ add_action( 'admin_notices', array( self::$instance, 'display' ) );
+ add_action( 'wp_ajax_dnh_dismiss_notice', array( self::$instance, 'dismiss_notice_ajax' ) );
+
+ }
+
+ /**
+ * Check if the current WordPress version fits the requirements
+ *
+ * @since 1.0
+ */
+ private function is_wp_compatible(): bool {
+
+ if ( version_compare( get_bloginfo( 'version' ), self::$instance->wordpress_version_required, '<' ) ) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Check if the version of PHP is compatible with this library
+ *
+ * @since 1.0
+ */
+ private function is_php_compatible(): bool {
+
+ if ( version_compare( phpversion(), self::$instance->php_version_required, '<' ) ) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Display all the registered notices
+ *
+ * @since 1.0
+ */
+ public function display(): void {
+
+ if ( is_null( self::$instance->notices ) || empty( self::$instance->notices ) ) {
+ return;
+ }
+
+ foreach ( self::$instance->notices as $id => $notice ) {
+
+ $id = self::$instance->get_id( $id );
+
+ // Check if the notice was dismissed
+ if ( self::$instance->is_dismissed( $id ) ) {
+ continue;
+ }
+
+ // Check if the current user has required capability
+ if ( ! empty( $notice['cap'] ) && ! current_user_can( $notice['cap'] ) ) {
+ continue;
+ }
+
+ $class = array(
+ 'notice',
+ $notice['type'],
+ 'is-dismissible',
+ $notice['class'],
+ );
+
+ printf(
+ '',
+ esc_attr( "dnh-$id" ),
+ esc_attr( trim( implode( ' ', $class ) ) ),
+ wp_kses_post( $notice['content'] )
+ );
+
+ }
+
+ }
+
+ /**
+ * Spits an error message at the top of the admin screen
+ *
+ * @since 1.0
+ *
+ * @param string $error Error message to spit
+ *
+ */
+ protected function spit_error( string $error ): void {
+ printf(
+ '%1$s %2$s
',
+ esc_html__( 'Dismissible Notices Handler Error:', 'advanced-responsive-video-embedder' ),
+ wp_kses_post( $error )
+ );
+ }
+
+ /**
+ * Sanitize a notice ID and return it
+ *
+ * @since 1.0
+ *
+ *
+ */
+ public function get_id( string $id ): string {
+ return sanitize_key( $id );
+ }
+
+ /**
+ * Get available notice types
+ *
+ * @since 1.0
+ * @return array
+ */
+ public function get_types(): array {
+
+ $types = array(
+ 'error',
+ 'updated',
+ // New types of notification style.
+ 'notice-error',
+ 'notice-warning',
+ 'notice-success',
+ 'notice-info',
+ );
+
+ return apply_filters( 'dnh_notice_types', $types );
+
+ }
+
+ /**
+ * Get the default arguments for a notice
+ *
+ * @since 1.0
+ * @return array
+ */
+ private function default_args(): array {
+
+ $args = array(
+ 'screen' => '', // Coming soon
+ 'scope' => 'user', // Scope of the dismissal. Either user or global
+ 'cap' => '', // Required user capability
+ 'class' => '', // Additional class to add to the notice
+ );
+
+ return apply_filters( 'dnh_default_args', $args );
+
+ }
+
+ /**
+ * Register a new notice
+ *
+ * @since 1.0
+ *
+ * @param string $id Notice ID, used to identify it
+ * @param string $type Type of notice to display
+ * @param string $content Notice content
+ * @param array $args Additional parameters
+ *
+ */
+ public function register_notice( string $id, string $type, string $content, array $args = array() ): bool {
+
+ if ( is_null( self::$instance->notices ) ) {
+ self::$instance->notices = array();
+ }
+
+ $t = sanitize_text_field( $type );
+ $id = self::$instance->get_id( $id );
+ $type = in_array( $t, self::$instance->get_types(), true ) ? $t : 'updated';
+ $content = wp_kses_post( $content );
+ $args = wp_parse_args( $args, self::$instance->default_args() );
+
+ if ( array_key_exists( $id, self::$instance->notices ) ) {
+
+ self::$instance->spit_error(
+ sprintf(
+ /* translators: %s: required php version */
+ esc_html__( 'A notice with the ID %s has already been registered.', 'advanced-responsive-video-embedder' ),
+ "$id
"
+ )
+ );
+
+ return false;
+ }
+
+ $notice = array(
+ 'type' => $type,
+ 'content' => $content,
+ );
+
+ $notice = array_merge( $notice, $args );
+
+ self::$instance->notices[ $id ] = $notice;
+
+ return true;
+
+ }
+
+ /**
+ * Notice dismissal triggered by Ajax
+ *
+ * @since 1.0
+ */
+ public function dismiss_notice_ajax(): void {
+
+ // phpcs:disable WordPress.Security.NonceVerification.Missing
+ if ( ! isset( $_POST['id'] ) ) {
+ echo 0;
+ exit;
+ }
+
+ if ( empty( $_POST['id'] ) || false === strpos( $_POST['id'], 'dnh-' ) ) {
+ echo 0;
+ exit;
+ }
+
+ $id = self::$instance->get_id( str_replace( 'dnh-', '', $_POST['id'] ) );
+ // phpcs:enable
+
+ echo wp_kses_post( self::$instance->dismiss_notice( $id ) );
+ exit;
+ }
+
+ /**
+ * Dismiss a notice
+ *
+ * @since 1.0
+ *
+ * @param string $id ID of the notice to dismiss
+ *
+ */
+ public function dismiss_notice( string $id ): bool {
+
+ $notice = self::$instance->get_notice( self::$instance->get_id( $id ) );
+
+ if ( false === $notice ) {
+ return false;
+ }
+
+ if ( self::$instance->is_dismissed( $id ) ) {
+ return false;
+ }
+
+ return 'user' === $notice['scope'] ? self::$instance->dismiss_user( $id ) : self::$instance->dismiss_global( $id );
+
+ }
+
+ /**
+ * Dismiss notice for the current user
+ *
+ * @since 1.0
+ *
+ * @param string $id Notice ID
+ *
+ * @return int|bool
+ */
+ private function dismiss_user( string $id ) {
+
+ $dismissed = self::$instance->dismissed_user();
+
+ if ( in_array( $id, $dismissed, true ) ) {
+ return false;
+ }
+
+ array_push( $dismissed, $id );
+
+ return update_user_meta( get_current_user_id(), 'dnh_dismissed_notices', $dismissed );
+
+ }
+
+ /**
+ * Dismiss notice globally on the site
+ *
+ * @since 1.0
+ *
+ * @param string $id Notice ID
+ *
+ */
+ private function dismiss_global( string $id ): bool {
+
+ $dismissed = self::$instance->dismissed_global();
+
+ if ( in_array( $id, $dismissed, true ) ) {
+ return false;
+ }
+
+ array_push( $dismissed, $id );
+
+ return update_option( 'dnh_dismissed_notices', $dismissed );
+
+ }
+
+ /**
+ * Restore a dismissed notice
+ *
+ * @since 1.0
+ *
+ * @param string $id ID of the notice to restore
+ *
+ */
+ public function restore_notice( string $id ): bool {
+
+ $id = self::$instance->get_id( $id );
+ $notice = self::$instance->get_notice( $id );
+
+ if ( false === $notice ) {
+ return false;
+ }
+
+ return 'user' === $notice['scope'] ? self::$instance->restore_user( $id ) : self::$instance->restore_global( $id );
+
+ }
+
+ /**
+ * Restore a notice dismissed by the current user
+ *
+ * @since 1.0
+ *
+ * @param string $id ID of the notice to restore
+ *
+ */
+ private function restore_user( string $id ): bool {
+
+ $id = self::$instance->get_id( $id );
+ $notice = self::$instance->get_notice( $id );
+
+ if ( false === $notice ) {
+ return false;
+ }
+
+ $dismissed = self::$instance->dismissed_user();
+
+ if ( ! in_array( $id, $dismissed, true ) ) {
+ return false;
+ }
+
+ $flip = array_flip( $dismissed );
+ $key = $flip[ $id ];
+
+ unset( $dismissed[ $key ] );
+
+ return update_user_meta( get_current_user_id(), 'dnh_dismissed_notices', $dismissed );
+
+ }
+
+ /**
+ * Restore a notice dismissed globally
+ *
+ * @since 1.0
+ *
+ * @param string $id ID of the notice to restore
+ *
+ */
+ private function restore_global( string $id ): bool {
+
+ $id = self::$instance->get_id( $id );
+ $notice = self::$instance->get_notice( $id );
+
+ if ( false === $notice ) {
+ return false;
+ }
+
+ $dismissed = self::$instance->dismissed_global();
+
+ if ( ! in_array( $id, $dismissed, true ) ) {
+ return false;
+ }
+
+ $flip = array_flip( $dismissed );
+ $key = $flip[ $id ];
+
+ unset( $dismissed[ $key ] );
+
+ return update_option( 'dnh_dismissed_notices', $dismissed );
+
+ }
+
+ /**
+ * Get all dismissed notices
+ *
+ * This includes notices dismissed globally or per user.
+ *
+ * @since 1.0
+ * @return array
+ */
+ public function dismissed_notices(): array {
+
+ $user = self::$instance->dismissed_user();
+ $global = self::$instance->dismissed_global();
+
+ return array_merge( $user, $global );
+
+ }
+
+ /**
+ * Get user dismissed notices
+ *
+ * @since 1.0
+ * @return array
+ */
+ private function dismissed_user(): array {
+
+ $dismissed = get_user_meta( get_current_user_id(), 'dnh_dismissed_notices', true );
+
+ if ( '' === $dismissed ) {
+ $dismissed = array();
+ }
+
+ return $dismissed;
+
+ }
+
+ /**
+ * Get globally dismissed notices
+ *
+ * @since 1.0
+ * @return array
+ */
+ private function dismissed_global(): array {
+ return get_option( 'dnh_dismissed_notices', array() );
+ }
+
+ /**
+ * Check if a notice has been dismissed
+ *
+ * @since 1.0
+ *
+ * @param string $id Notice ID
+ *
+ */
+ public function is_dismissed( string $id ): bool {
+
+ $dismissed = self::$instance->dismissed_notices();
+
+ if ( ! in_array( self::$instance->get_id( $id ), $dismissed, true ) ) {
+ return false;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Get all the registered notices
+ *
+ * @since 1.0
+ * @return array|null
+ */
+ public function get_notices(): ?array {
+ return self::$instance->notices;
+ }
+
+ /**
+ * Return a specific notice
+ *
+ * @since 1.0
+ *
+ * @param string $id Notice ID
+ *
+ * @return array|false
+ */
+ public function get_notice( string $id ) {
+
+ $id = self::$instance->get_id( $id );
+
+ if ( ! is_array( self::$instance->notices ) || ! array_key_exists( $id, self::$instance->notices ) ) {
+ return false;
+ }
+
+ return self::$instance->notices[ $id ];
+
+ }
+
+ }
+
+}
diff --git a/packages/nextgenthemes/wp-shared/includes/WP/Admin/alpine.js b/packages/nextgenthemes/wp-shared/includes/WP/Admin/alpine.js
new file mode 100644
index 00000000..2f644907
--- /dev/null
+++ b/packages/nextgenthemes/wp-shared/includes/WP/Admin/alpine.js
@@ -0,0 +1,5 @@
+(()=>{var Ze=!1,Qe=!1,V=[],et=-1;function Kt(e){wn(e)}function wn(e){V.includes(e)||V.push(e),En()}function we(e){let t=V.indexOf(e);t!==-1&&t>et&&V.splice(t,1)}function En(){!Qe&&!Ze&&(Ze=!0,queueMicrotask(vn))}function vn(){Ze=!1,Qe=!0;for(let e=0;ee.effect(t,{scheduler:r=>{tt?Kt(r):r()}}),rt=e.raw}function nt(e){I=e}function Vt(e){let t=()=>{};return[n=>{let i=I(n);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),L(i))},i},()=>{t()}]}function q(e,t,r={}){e.dispatchEvent(new CustomEvent(t,{detail:r,bubbles:!0,composed:!0,cancelable:!0}))}function O(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>O(i,t));return}let r=!1;if(t(e,()=>r=!0),r)return;let n=e.firstElementChild;for(;n;)O(n,t,!1),n=n.nextElementSibling}function v(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var qt=!1;function Ut(){qt&&v("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),qt=!0,document.body||v("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's `