From 1eacdf5bf38fcb89c63f18d4541b5ac0c062350d Mon Sep 17 00:00:00 2001
From: "Md. Asif Hossain Nadim"
<90011088+MdAsifHossainNadim@users.noreply.github.com>
Date: Thu, 29 Feb 2024 12:58:24 +0600
Subject: [PATCH] fix/deprecated error for appsero updater (#194)
* fix: deprecated-error-for-appsero-updater
* enhance: load-appsero-from-wedocs
* release: bump-version-&-updated-changelog
---
composer.json | 1 -
composer.lock | 110 +--
includes/Admin.php | 2 +-
includes/Appsero/Client.php | 250 +++++++
includes/Appsero/Insights.php | 1299 +++++++++++++++++++++++++++++++++
includes/Appsero/License.php | 809 ++++++++++++++++++++
languages/wedocs.pot | 2 +-
package.json | 2 +-
readme.md | 2 +-
readme.txt | 6 +-
tests/bootstrap.php | 2 +-
wedocs.php | 4 +-
12 files changed, 2398 insertions(+), 91 deletions(-)
create mode 100644 includes/Appsero/Client.php
create mode 100644 includes/Appsero/Insights.php
create mode 100644 includes/Appsero/License.php
diff --git a/composer.json b/composer.json
index 500a1fe..8d2f035 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,6 @@
],
"minimum-stability": "dev",
"require": {
- "appsero/client": "^2.0.2",
"woocommerce/action-scheduler": "dev-trunk"
},
"autoload": {
diff --git a/composer.lock b/composer.lock
index 1386d06..1937c00 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,74 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "8424029e90e55c86bf1bed76bb2931dd",
+ "content-hash": "116350e1527c41e68b0c663fd18e52db",
"packages": [
- {
- "name": "appsero/client",
- "version": "v2.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/Appsero/client.git",
- "reference": "b61c3ab21df4d44f805ee9476f9d880f8370a36b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Appsero/client/zipball/b61c3ab21df4d44f805ee9476f9d880f8370a36b",
- "reference": "b61c3ab21df4d44f805ee9476f9d880f8370a36b",
- "shasum": ""
- },
- "require": {
- "php": ">=5.6"
- },
- "require-dev": {
- "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2",
- "phpcompatibility/phpcompatibility-wp": "dev-master",
- "phpunit/phpunit": "^8.5.31",
- "squizlabs/php_codesniffer": "^3.7",
- "tareq1988/wp-php-cs-fixer": "dev-master",
- "wp-coding-standards/wpcs": "dev-develop"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Appsero\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Tareq Hasan",
- "email": "tareq@appsero.com"
- }
- ],
- "description": "Appsero Client",
- "keywords": [
- "analytics",
- "plugin",
- "theme",
- "wordpress"
- ],
- "support": {
- "issues": "https://github.com/Appsero/client/issues",
- "source": "https://github.com/Appsero/client/tree/v2.0.2"
- },
- "time": "2024-01-30T08:15:01+00:00"
- },
{
"name": "woocommerce/action-scheduler",
"version": "dev-trunk",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/action-scheduler.git",
- "reference": "2410f037681195150e08072827fefd846354fe05"
+ "reference": "65b0d7392accd4978c495e4eed4c0281a46eed4a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/woocommerce/action-scheduler/zipball/2410f037681195150e08072827fefd846354fe05",
- "reference": "2410f037681195150e08072827fefd846354fe05",
+ "url": "https://api.github.com/repos/woocommerce/action-scheduler/zipball/65b0d7392accd4978c495e4eed4c0281a46eed4a",
+ "reference": "65b0d7392accd4978c495e4eed4c0281a46eed4a",
"shasum": ""
},
"require": {
@@ -102,7 +48,7 @@
"issues": "https://github.com/woocommerce/action-scheduler/issues",
"source": "https://github.com/woocommerce/action-scheduler/tree/trunk"
},
- "time": "2023-12-14T14:01:47+00:00"
+ "time": "2024-02-22T13:47:42+00:00"
}
],
"packages-dev": [
@@ -230,12 +176,12 @@
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "202aaf6b7c2e1e0a622b0298e9f3f537e4d84018"
+ "reference": "2f5294676c802a62b0549f6bc8983f14294ce369"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/202aaf6b7c2e1e0a622b0298e9f3f537e4d84018",
- "reference": "202aaf6b7c2e1e0a622b0298e9f3f537e4d84018",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/2f5294676c802a62b0549f6bc8983f14294ce369",
+ "reference": "2f5294676c802a62b0549f6bc8983f14294ce369",
"shasum": ""
},
"require": {
@@ -283,7 +229,7 @@
"type": "tidelift"
}
],
- "time": "2023-11-01T08:01:43+00:00"
+ "time": "2024-02-10T11:10:03+00:00"
},
{
"name": "phar-io/manifest",
@@ -518,17 +464,17 @@
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353"
+ "reference": "153ae662783729388a584b4361f2545e4d841e3c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353",
- "reference": "bc3dc91a5e9b14aa06d1d9e90647c5c5a2cc5353",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c",
+ "reference": "153ae662783729388a584b4361f2545e4d841e3c",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
- "php": "^7.4 || ^8.0",
+ "php": "^7.3 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^1.13"
},
@@ -567,9 +513,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.x"
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2"
},
- "time": "2024-01-18T19:15:27+00:00"
+ "time": "2024-02-23T11:10:43+00:00"
},
{
"name": "phpspec/prophecy",
@@ -577,20 +523,20 @@
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "d4f454f7e1193933f04e6500de3e79191648ed0c"
+ "reference": "016d7770cf4ca93ab8fcc30511f31003b1f8bdcd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d4f454f7e1193933f04e6500de3e79191648ed0c",
- "reference": "d4f454f7e1193933f04e6500de3e79191648ed0c",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/016d7770cf4ca93ab8fcc30511f31003b1f8bdcd",
+ "reference": "016d7770cf4ca93ab8fcc30511f31003b1f8bdcd",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.2 || ^2.0",
"php": "^7.2 || 8.0.* || 8.1.* || 8.2.* || 8.3.*",
"phpdocumentor/reflection-docblock": "^5.2",
- "sebastian/comparator": "^3.0 || ^4.0 || ^5.0",
- "sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0"
+ "sebastian/comparator": "^3.0 || ^4.0 || ^5.0 || ^6.0",
+ "sebastian/recursion-context": "^3.0 || ^4.0 || ^5.0 || ^6.0"
},
"require-dev": {
"phpspec/phpspec": "^6.0 || ^7.0",
@@ -637,22 +583,22 @@
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
- "source": "https://github.com/phpspec/prophecy/tree/v1.18.0"
+ "source": "https://github.com/phpspec/prophecy/tree/master"
},
- "time": "2023-12-07T16:22:33+00:00"
+ "time": "2024-02-06T10:23:13+00:00"
},
{
"name": "phpstan/phpdoc-parser",
- "version": "1.25.0",
+ "version": "1.26.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240"
+ "reference": "231e3186624c03d7e7c890ec662b81e6b0405227"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bd84b629c8de41aa2ae82c067c955e06f1b00240",
- "reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/231e3186624c03d7e7c890ec662b81e6b0405227",
+ "reference": "231e3186624c03d7e7c890ec662b81e6b0405227",
"shasum": ""
},
"require": {
@@ -684,9 +630,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/1.25.0"
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/1.26.0"
},
- "time": "2024-01-04T17:06:16+00:00"
+ "time": "2024-02-23T16:05:55+00:00"
},
{
"name": "phpunit/php-code-coverage",
diff --git a/includes/Admin.php b/includes/Admin.php
index e110dfe..8dd0d37 100644
--- a/includes/Admin.php
+++ b/includes/Admin.php
@@ -2,7 +2,7 @@
namespace WeDevs\WeDocs;
-use Appsero\Client as Appsero_Client;
+use \WeDevs\WeDocs\Appsero\Client as Appsero_Client;
/**
* Frontend Handler Class
diff --git a/includes/Appsero/Client.php b/includes/Appsero/Client.php
new file mode 100644
index 0000000..a020e8f
--- /dev/null
+++ b/includes/Appsero/Client.php
@@ -0,0 +1,250 @@
+hash = $hash;
+ $this->name = $name;
+ $this->file = $file;
+
+ $this->set_basename_and_slug();
+ }
+
+ /**
+ * Initialize insights class
+ *
+ * @return Appsero\Insights
+ */
+ public function insights() {
+ // if already instantiated, return the cached one
+ if ( $this->insights ) {
+ return $this->insights;
+ }
+
+ $this->insights = new Insights( $this );
+
+ return $this->insights;
+ }
+
+ /**
+ * Initialize license checker
+ *
+ * @return Appsero\License
+ */
+ public function license() {
+ // if already instantiated, return the cached one
+ if ( $this->license ) {
+ return $this->license;
+ }
+
+ $this->license = new License( $this );
+
+ return $this->license;
+ }
+
+ /**
+ * API Endpoint
+ *
+ * @return string
+ */
+ public function endpoint() {
+ $endpoint = apply_filters( 'appsero_endpoint', 'https://api.appsero.com' );
+
+ return trailingslashit( $endpoint );
+ }
+
+ /**
+ * Set project basename, slug and version
+ *
+ * @return void
+ */
+ protected function set_basename_and_slug() {
+ if ( strpos( $this->file, WP_CONTENT_DIR . '/themes/' ) === false ) {
+ $this->basename = plugin_basename( $this->file );
+
+ list( $this->slug, $mainfile ) = explode( '/', $this->basename );
+
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
+
+ $plugin_data = get_plugin_data( $this->file );
+
+ $this->project_version = $plugin_data['Version'];
+ $this->type = 'plugin';
+ } else {
+ $this->basename = str_replace( WP_CONTENT_DIR . '/themes/', '', $this->file );
+
+ list( $this->slug, $mainfile ) = explode( '/', $this->basename );
+
+ $theme = wp_get_theme( $this->slug );
+
+ $this->project_version = $theme->version;
+ $this->type = 'theme';
+ }
+
+ $this->textdomain = $this->slug;
+ }
+
+ /**
+ * Send request to remote endpoint
+ *
+ * @param array $params
+ * @param string $route
+ *
+ * @return array|WP_Error array of results including HTTP headers or WP_Error if the request failed
+ */
+ public function send_request( $params, $route, $blocking = false ) {
+ $url = $this->endpoint() . $route;
+
+ $headers = [
+ 'user-agent' => 'Appsero/' . md5( esc_url( home_url() ) ) . ';',
+ 'Accept' => 'application/json',
+ ];
+
+ $response = wp_remote_post(
+ $url,
+ [
+ 'method' => 'POST',
+ 'timeout' => 30,
+ 'redirection' => 5,
+ 'httpversion' => '1.0',
+ 'blocking' => $blocking,
+ 'headers' => $headers,
+ 'body' => array_merge( $params, [ 'client' => $this->version ] ),
+ 'cookies' => [],
+ ]
+ );
+
+ return $response;
+ }
+
+ /**
+ * Check if the current server is localhost
+ *
+ * @return bool
+ */
+ public function is_local_server() {
+ $is_local = isset( $_SERVER['REMOTE_ADDR'] ) && in_array( $_SERVER['REMOTE_ADDR'], [ '127.0.0.1', '::1' ], true );
+
+ return apply_filters( 'appsero_is_local', $is_local );
+ }
+
+ /**
+ * Translate function _e()
+ */
+ // phpcs:ignore
+ public function _etrans( $text ) {
+ call_user_func( '_e', $text, $this->textdomain );
+ }
+
+ /**
+ * Translate function __()
+ */
+ // phpcs:ignore
+ public function __trans( $text ) {
+ return call_user_func( '__', $text, $this->textdomain );
+ }
+
+ /**
+ * Set project textdomain
+ */
+ public function set_textdomain( $textdomain ) {
+ $this->textdomain = $textdomain;
+ }
+}
diff --git a/includes/Appsero/Insights.php b/includes/Appsero/Insights.php
new file mode 100644
index 0000000..a3ecec3
--- /dev/null
+++ b/includes/Appsero/Insights.php
@@ -0,0 +1,1299 @@
+client = $client;
+ }
+ }
+
+ /**
+ * Don't show the notice
+ *
+ * @return \self
+ */
+ public function hide_notice()
+ {
+ $this->show_notice = false;
+
+ return $this;
+ }
+
+ /**
+ * Add plugin data if needed
+ *
+ * @return \self
+ */
+ public function add_plugin_data()
+ {
+ $this->plugin_data = true;
+
+ return $this;
+ }
+
+ /**
+ * Add extra data if needed
+ *
+ * @param array $data
+ *
+ * @return \self
+ */
+ public function add_extra($data = [])
+ {
+ $this->extra_data = $data;
+
+ return $this;
+ }
+
+ /**
+ * Set custom notice text
+ *
+ * @param string $text
+ *
+ * @return \self
+ */
+ public function notice($text = '')
+ {
+ $this->notice = $text;
+
+ return $this;
+ }
+
+ /**
+ * Initialize insights
+ *
+ * @return void
+ */
+ public function init()
+ {
+ if ($this->client->type === 'plugin') {
+ $this->init_plugin();
+ } elseif ($this->client->type === 'theme') {
+ $this->init_theme();
+ }
+ }
+
+ /**
+ * Initialize theme hooks
+ *
+ * @return void
+ */
+ public function init_theme()
+ {
+ $this->init_common();
+
+ add_action('switch_theme', [$this, 'deactivation_cleanup']);
+ add_action('switch_theme', [$this, 'theme_deactivated'], 12, 3);
+ }
+
+ /**
+ * Initialize plugin hooks
+ *
+ * @return void
+ */
+ public function init_plugin()
+ {
+ // plugin deactivate popup
+ // if ( ! $this->is_local_server() ) {
+ // add_filter( 'plugin_action_links_' . $this->client->basename, [ $this, 'plugin_action_links' ] );
+ // add_action( 'admin_footer', [ $this, 'deactivate_scripts' ] );
+ // }
+
+ add_filter('plugin_action_links_' . $this->client->basename, [$this, 'plugin_action_links']);
+ add_action('admin_footer', [$this, 'deactivate_scripts']);
+
+ $this->init_common();
+
+ register_activation_hook($this->client->file, [$this, 'activate_plugin']);
+ register_deactivation_hook($this->client->file, [$this, 'deactivation_cleanup']);
+ }
+
+ /**
+ * Initialize common hooks
+ *
+ * @return void
+ */
+ protected function init_common()
+ {
+ if ($this->show_notice) {
+ // tracking notice
+ add_action('admin_notices', [$this, 'admin_notice']);
+ }
+
+ add_action('admin_init', [$this, 'handle_optin_optout']);
+
+ // uninstall reason
+ add_action('wp_ajax_' . $this->client->slug . '_submit-uninstall-reason', [$this, 'uninstall_reason_submission']);
+
+ // cron events
+ add_filter('cron_schedules', [$this, 'add_weekly_schedule']);
+ add_action($this->client->slug . '_tracker_send_event', [$this, 'send_tracking_data']);
+ // add_action( 'admin_init', array( $this, 'send_tracking_data' ) ); // test
+ }
+
+ /**
+ * Send tracking data to AppSero server
+ *
+ * @param bool $override
+ *
+ * @return void
+ */
+ public function send_tracking_data($override = false)
+ {
+ if (!$this->tracking_allowed() && !$override) {
+ return;
+ }
+
+ // Send a maximum of once per week
+ $last_send = $this->get_last_send();
+
+ if ($last_send && $last_send > strtotime('-1 week')) {
+ return;
+ }
+
+ $tracking_data = $this->get_tracking_data();
+
+ $response = $this->client->send_request($tracking_data, 'track');
+
+ update_option($this->client->slug . '_tracking_last_send', time());
+ }
+
+ /**
+ * Get the tracking data points
+ *
+ * @return array
+ */
+ protected function get_tracking_data()
+ {
+ $all_plugins = $this->get_all_plugins();
+
+ $users = get_users(
+ [
+ 'role' => 'administrator',
+ 'orderby' => 'ID',
+ 'order' => 'ASC',
+ 'number' => 1,
+ 'paged' => 1,
+ ]
+ );
+
+ $admin_user = (is_array($users) && !empty($users)) ? $users[0] : false;
+ $first_name = '';
+ $last_name = '';
+
+ if ($admin_user) {
+ $first_name = $admin_user->first_name ? $admin_user->first_name : $admin_user->display_name;
+ $last_name = $admin_user->last_name;
+ }
+
+ $data = [
+ 'url' => esc_url(home_url()),
+ 'site' => $this->get_site_name(),
+ 'admin_email' => get_option('admin_email'),
+ 'first_name' => $first_name,
+ 'last_name' => $last_name,
+ 'hash' => $this->client->hash,
+ 'server' => $this->get_server_info(),
+ 'wp' => $this->get_wp_info(),
+ 'users' => $this->get_user_counts(),
+ 'active_plugins' => count($all_plugins['active_plugins']),
+ 'inactive_plugins' => count($all_plugins['inactive_plugins']),
+ 'ip_address' => $this->get_user_ip_address(),
+ 'project_version' => $this->client->project_version,
+ 'tracking_skipped' => false,
+ 'is_local' => $this->is_local_server(),
+ ];
+
+ // Add Plugins
+ if ($this->plugin_data) {
+ $plugins_data = [];
+
+ foreach ($all_plugins['active_plugins'] as $slug => $plugin) {
+ $slug = strstr($slug, '/', true);
+
+ if (!$slug) {
+ continue;
+ }
+
+ $plugins_data[$slug] = [
+ 'name' => isset($plugin['name']) ? $plugin['name'] : '',
+ 'version' => isset($plugin['version']) ? $plugin['version'] : '',
+ ];
+ }
+
+ if (array_key_exists($this->client->slug, $plugins_data)) {
+ unset($plugins_data[$this->client->slug]);
+ }
+
+ $data['plugins'] = $plugins_data;
+ }
+
+ // Add Metadata
+ $extra = $this->get_extra_data();
+
+ if ($extra) {
+ $data['extra'] = $extra;
+ }
+
+ // Check this has previously skipped tracking
+ $skipped = get_option($this->client->slug . '_tracking_skipped');
+
+ if ($skipped === 'yes') {
+ delete_option($this->client->slug . '_tracking_skipped');
+
+ $data['tracking_skipped'] = true;
+ }
+
+ return apply_filters($this->client->slug . '_tracker_data', $data);
+ }
+
+ /**
+ * If a child class wants to send extra data
+ *
+ * @return mixed
+ */
+ protected function get_extra_data()
+ {
+ if (is_callable($this->extra_data)) {
+ return call_user_func($this->extra_data);
+ }
+
+ if (is_array($this->extra_data)) {
+ return $this->extra_data;
+ }
+
+ return [];
+ }
+
+ /**
+ * Explain the user which data we collect
+ *
+ * @return array
+ */
+ protected function data_we_collect()
+ {
+ $data = [
+ 'Server environment details (php, mysql, server, WordPress versions)',
+ 'Number of users in your site',
+ 'Site language',
+ 'Number of active and inactive plugins',
+ 'Site name and URL',
+ 'Your name and email address',
+ ];
+
+ if ($this->plugin_data) {
+ array_splice($data, 4, 0, ["active plugins' name"]);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Check if the user has opted into tracking
+ *
+ * @return bool
+ */
+ public function tracking_allowed()
+ {
+ $allow_tracking = get_option($this->client->slug . '_allow_tracking', 'no');
+
+ return $allow_tracking === 'yes';
+ }
+
+ /**
+ * Get the last time a tracking was sent
+ *
+ * @return false|string
+ */
+ private function get_last_send()
+ {
+ return get_option($this->client->slug . '_tracking_last_send', false);
+ }
+
+ /**
+ * Check if the notice has been dismissed or enabled
+ *
+ * @return bool
+ */
+ public function notice_dismissed()
+ {
+ $hide_notice = get_option($this->client->slug . '_tracking_notice', null);
+
+ if ('hide' === $hide_notice) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if the current server is localhost
+ *
+ * @return bool
+ */
+ private function is_local_server()
+ {
+ $host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : 'localhost';
+ $ip = isset($_SERVER['SERVER_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_ADDR'])) : '127.0.0.1';
+ $is_local = false;
+
+ if (
+ in_array($ip, ['127.0.0.1', '::1'], true)
+ || !strpos($host, '.')
+ || in_array(strrchr($host, '.'), ['.test', '.testing', '.local', '.localhost', '.localdomain'], true)
+ ) {
+ $is_local = true;
+ }
+
+ return apply_filters('appsero_is_local', $is_local);
+ }
+
+ /**
+ * Schedule the event weekly
+ *
+ * @return void
+ */
+ private function schedule_event()
+ {
+ $hook_name = wp_unslash($this->client->slug . '_tracker_send_event');
+
+ if (!wp_next_scheduled($hook_name)) {
+ wp_schedule_event(time(), 'weekly', $hook_name);
+ }
+ }
+
+ /**
+ * Clear any scheduled hook
+ *
+ * @return void
+ */
+ private function clear_schedule_event()
+ {
+ wp_clear_scheduled_hook($this->client->slug . '_tracker_send_event');
+ }
+
+ /**
+ * Display the admin notice to users that have not opted-in or out
+ *
+ * @return void
+ */
+ public function admin_notice()
+ {
+ if ($this->notice_dismissed()) {
+ return;
+ }
+
+ if ($this->tracking_allowed()) {
+ return;
+ }
+
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+
+ // don't show tracking if a local server
+ // if ( $this->is_local_server() ) {
+ // return;
+ // }
+
+ $optin_url = wp_nonce_url(add_query_arg($this->client->slug . '_tracker_optin', 'true'), '_wpnonce');
+ $optout_url = wp_nonce_url(add_query_arg($this->client->slug . '_tracker_optout', 'true'), '_wpnonce');
+
+ if (empty($this->notice)) {
+ $notice = sprintf($this->client->__trans('Want to help make %1$s even more awesome? Allow %1$s to collect diagnostic data and usage information.'), $this->client->name);
+ } else {
+ $notice = $this->notice;
+ }
+
+ $policy_url = 'https://appsero.com/privacy-policy/';
+
+ $notice .= ' (' . $this->client->__trans('what we collect') . ' )';
+ $notice .= '
' . implode(', ', $this->data_we_collect()) . '. ';
+ $notice .= 'We are using Appsero to collect your data. Learn more about how Appsero collects and handle your data.
';
+
+ echo '';
+
+ echo "
+ ";
+ }
+
+ /**
+ * Handle the optin/optout
+ *
+ * @return void
+ */
+ public function handle_optin_optout()
+ {
+ if (!isset($_GET['_wpnonce'])) {
+ return;
+ }
+
+ if (!wp_verify_nonce(sanitize_key($_GET['_wpnonce']), '_wpnonce')) {
+ return;
+ }
+
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+
+ if (isset($_GET[$this->client->slug . '_tracker_optin']) && $_GET[$this->client->slug . '_tracker_optin'] === 'true') {
+ $this->optin();
+
+ wp_safe_redirect(remove_query_arg($this->client->slug . '_tracker_optin'));
+ exit;
+ }
+
+ if (isset($_GET[$this->client->slug . '_tracker_optout']) && isset($_GET[$this->client->slug . '_tracker_optout']) && $_GET[$this->client->slug . '_tracker_optout'] === 'true') {
+ $this->optout();
+
+ wp_safe_redirect(remove_query_arg($this->client->slug . '_tracker_optout'));
+ exit;
+ }
+ }
+
+ /**
+ * Tracking optin
+ *
+ * @return void
+ */
+ public function optin()
+ {
+ update_option($this->client->slug . '_allow_tracking', 'yes');
+ update_option($this->client->slug . '_tracking_notice', 'hide');
+
+ $this->clear_schedule_event();
+ $this->schedule_event();
+ $this->send_tracking_data();
+
+ /*
+ * Fires when the user has opted in tracking.
+ */
+ do_action($this->client->slug . '_tracker_optin', $this->get_tracking_data());
+ }
+
+ /**
+ * Optout from tracking
+ *
+ * @return void
+ */
+ public function optout()
+ {
+ update_option($this->client->slug . '_allow_tracking', 'no');
+ update_option($this->client->slug . '_tracking_notice', 'hide');
+
+ $this->send_tracking_skipped_request();
+
+ $this->clear_schedule_event();
+
+ /*
+ * Fires when the user has opted out tracking.
+ */
+ do_action($this->client->slug . '_tracker_optout');
+ }
+
+ /**
+ * Get the number of post counts
+ *
+ * @param string $post_type
+ *
+ * @return int
+ */
+ public function get_post_count($post_type)
+ {
+ global $wpdb;
+
+ return (int) $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT count(ID) FROM $wpdb->posts WHERE post_type = %s and post_status = %s",
+ [$post_type, 'publish']
+ )
+ );
+ }
+
+ /**
+ * Get server related info.
+ *
+ * @return array
+ */
+ private static function get_server_info()
+ {
+ global $wpdb;
+
+ $server_data = [];
+
+ if (isset($_SERVER['SERVER_SOFTWARE']) && !empty($_SERVER['SERVER_SOFTWARE'])) {
+ // phpcs:ignore
+ $server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
+ }
+
+ if (function_exists('phpversion')) {
+ $server_data['php_version'] = phpversion();
+ }
+
+ $server_data['mysql_version'] = $wpdb->db_version();
+
+ $server_data['php_max_upload_size'] = size_format(wp_max_upload_size());
+ $server_data['php_default_timezone'] = date_default_timezone_get();
+ $server_data['php_soap'] = class_exists('SoapClient') ? 'Yes' : 'No';
+ $server_data['php_fsockopen'] = function_exists('fsockopen') ? 'Yes' : 'No';
+ $server_data['php_curl'] = function_exists('curl_init') ? 'Yes' : 'No';
+
+ return $server_data;
+ }
+
+ /**
+ * Get WordPress related data.
+ *
+ * @return array
+ */
+ private function get_wp_info()
+ {
+ $wp_data = [];
+
+ $wp_data['memory_limit'] = WP_MEMORY_LIMIT;
+ $wp_data['debug_mode'] = (defined('WP_DEBUG') && WP_DEBUG) ? 'Yes' : 'No';
+ $wp_data['locale'] = get_locale();
+ $wp_data['version'] = get_bloginfo('version');
+ $wp_data['multisite'] = is_multisite() ? 'Yes' : 'No';
+ $wp_data['theme_slug'] = get_stylesheet();
+
+ $theme = wp_get_theme($wp_data['theme_slug']);
+
+ $wp_data['theme_name'] = $theme->get('Name');
+ $wp_data['theme_version'] = $theme->get('Version');
+ $wp_data['theme_uri'] = $theme->get('ThemeURI');
+ $wp_data['theme_author'] = $theme->get('Author');
+
+ return $wp_data;
+ }
+
+ /**
+ * Get the list of active and inactive plugins
+ *
+ * @return array
+ */
+ private function get_all_plugins()
+ {
+ // Ensure get_plugins function is loaded
+ if (!function_exists('get_plugins')) {
+ include ABSPATH . '/wp-admin/includes/plugin.php';
+ }
+
+ $plugins = get_plugins();
+ $active_plugins_keys = get_option('active_plugins', []);
+ $active_plugins = [];
+
+ foreach ($plugins as $k => $v) {
+ // Take care of formatting the data how we want it.
+ $formatted = [];
+ $formatted['name'] = wp_strip_all_tags($v['Name']);
+
+ if (isset($v['Version'])) {
+ $formatted['version'] = wp_strip_all_tags($v['Version']);
+ }
+
+ if (isset($v['Author'])) {
+ $formatted['author'] = wp_strip_all_tags($v['Author']);
+ }
+
+ if (isset($v['Network'])) {
+ $formatted['network'] = wp_strip_all_tags($v['Network']);
+ }
+
+ if (isset($v['PluginURI'])) {
+ $formatted['plugin_uri'] = wp_strip_all_tags($v['PluginURI']);
+ }
+
+ if (in_array($k, $active_plugins_keys, true)) {
+ // Remove active plugins from list so we can show active and inactive separately
+ unset($plugins[$k]);
+ $active_plugins[$k] = $formatted;
+ } else {
+ $plugins[$k] = $formatted;
+ }
+ }
+
+ return [
+ 'active_plugins' => $active_plugins,
+ 'inactive_plugins' => $plugins,
+ ];
+ }
+
+ /**
+ * Get user totals based on user role.
+ *
+ * @return array
+ */
+ public function get_user_counts()
+ {
+ $user_count = [];
+ $user_count_data = count_users();
+ $user_count['total'] = $user_count_data['total_users'];
+
+ // Get user count based on user role
+ foreach ($user_count_data['avail_roles'] as $role => $count) {
+ if (!$count) {
+ continue;
+ }
+
+ $user_count[$role] = $count;
+ }
+
+ return $user_count;
+ }
+
+ /**
+ * Add weekly cron schedule
+ *
+ * @param array $schedules
+ *
+ * @return array
+ */
+ public function add_weekly_schedule($schedules)
+ {
+ $schedules['weekly'] = [
+ 'interval' => DAY_IN_SECONDS * 7,
+ 'display' => 'Once Weekly',
+ ];
+
+ return $schedules;
+ }
+
+ /**
+ * Plugin activation hook
+ *
+ * @return void
+ */
+ public function activate_plugin()
+ {
+ $allowed = get_option($this->client->slug . '_allow_tracking', 'no');
+
+ // if it wasn't allowed before, do nothing
+ if ('yes' !== $allowed) {
+ return;
+ }
+
+ // re-schedule and delete the last sent time so we could force send again
+ $hook_name = $this->client->slug . '_tracker_send_event';
+
+ if (!wp_next_scheduled($hook_name)) {
+ wp_schedule_event(time(), 'weekly', $hook_name);
+ }
+
+ delete_option($this->client->slug . '_tracking_last_send');
+
+ $this->send_tracking_data(true);
+ }
+
+ /**
+ * Clear our options upon deactivation
+ *
+ * @return void
+ */
+ public function deactivation_cleanup()
+ {
+ $this->clear_schedule_event();
+
+ if ('theme' === $this->client->type) {
+ delete_option($this->client->slug . '_tracking_last_send');
+ delete_option($this->client->slug . '_allow_tracking');
+ }
+
+ delete_option($this->client->slug . '_tracking_notice');
+ }
+
+ /**
+ * Hook into action links and modify the deactivate link
+ *
+ * @param array $links
+ *
+ * @return array
+ */
+ public function plugin_action_links($links)
+ {
+ if (array_key_exists('deactivate', $links)) {
+ $links['deactivate'] = str_replace(' 'could-not-understand',
+ 'text' => $this->client->__trans("Couldn't understand"),
+ 'placeholder' => $this->client->__trans('Would you like us to assist you?'),
+ 'icon' => ' ',
+ ],
+ [
+ 'id' => 'found-better-plugin',
+ 'text' => $this->client->__trans('Found a better plugin'),
+ 'placeholder' => $this->client->__trans('Which plugin?'),
+ 'icon' => ' ',
+ ],
+ [
+ 'id' => 'not-have-that-feature',
+ 'text' => $this->client->__trans('Missing a specific feature'),
+ 'placeholder' => $this->client->__trans('Could you tell us more about that feature?'),
+ 'icon' => ' ',
+ ],
+ [
+ 'id' => 'is-not-working',
+ 'text' => $this->client->__trans('Not working'),
+ 'placeholder' => $this->client->__trans('Could you tell us a bit more whats not working?'),
+ 'icon' => ' ',
+ ],
+ [
+ 'id' => 'looking-for-other',
+ 'text' => $this->client->__trans('Not what I was looking'),
+ 'placeholder' => $this->client->__trans('Could you tell us a bit more?'),
+ 'icon' => ' ',
+ ],
+ [
+ 'id' => 'did-not-work-as-expected',
+ 'text' => $this->client->__trans("Didn't work as expected"),
+ 'placeholder' => $this->client->__trans('What did you expect?'),
+ 'icon' => ' ',
+ ],
+ [
+ 'id' => 'other',
+ 'text' => $this->client->__trans('Others'),
+ 'placeholder' => $this->client->__trans('Could you tell us a bit more?'),
+ 'icon' => ' ',
+ ],
+ ];
+
+ return $reasons;
+ }
+
+ /**
+ * Plugin deactivation uninstall reason submission
+ *
+ * @return void
+ */
+ public function uninstall_reason_submission()
+ {
+ if (!isset($_POST['nonce'])) {
+ return;
+ }
+
+ if (!isset($_POST['reason_id'])) {
+ wp_send_json_error();
+ }
+
+ if (!wp_verify_nonce(sanitize_key(wp_unslash($_POST['nonce'])), 'appsero-security-nonce')) {
+ wp_send_json_error('Nonce verification failed');
+ }
+
+ if (!current_user_can('manage_options')) {
+ wp_send_json_error('You are not allowed for this task');
+ }
+
+ $data = $this->get_tracking_data();
+ $data['reason_id'] = sanitize_text_field(wp_unslash($_POST['reason_id']));
+ $data['reason_info'] = isset($_REQUEST['reason_info']) ? trim(sanitize_text_field(wp_unslash($_REQUEST['reason_info']))) : '';
+
+ $this->client->send_request($data, 'deactivate');
+
+ /*
+ * Fire after the plugin _uninstall_reason_submitted
+ */
+ do_action($this->client->slug . '_uninstall_reason_submitted', $data);
+
+ wp_send_json_success();
+ }
+
+ /**
+ * Handle the plugin deactivation feedback
+ *
+ * @return void
+ */
+ public function deactivate_scripts()
+ {
+ global $pagenow;
+
+ if ('plugins.php' !== $pagenow) {
+ return;
+ }
+
+ $this->deactivation_modal_styles();
+ $reasons = $this->get_uninstall_reasons();
+ $custom_reasons = apply_filters('appsero_custom_deactivation_reasons', [], $this->client);
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+ client->__trans('We share your data with Appsero to troubleshoot problems & make product improvements. Learn more about how Appsero handles your data.'),
+ esc_url('https://appsero.com/'),
+ esc_url('https://appsero.com/privacy-policy')
+ );
+ ?>
+
+
+
+
+
+
+
+
+
+ get_template() === $this->client->slug) {
+ $this->client->send_request($this->get_tracking_data(), 'deactivate');
+ }
+ }
+
+ /**
+ * Get user IP Address
+ */
+ private function get_user_ip_address()
+ {
+ $response = wp_remote_get('https://icanhazip.com/');
+
+ if (is_wp_error($response)) {
+ return '';
+ }
+
+ $ip = trim(wp_remote_retrieve_body($response));
+
+ if (!filter_var($ip, FILTER_VALIDATE_IP)) {
+ return '';
+ }
+
+ return $ip;
+ }
+
+ /**
+ * Get site name
+ */
+ private function get_site_name()
+ {
+ $site_name = get_bloginfo('name');
+
+ if (empty($site_name)) {
+ $site_name = get_bloginfo('description');
+ $site_name = wp_trim_words($site_name, 3, '');
+ }
+
+ if (empty($site_name)) {
+ $site_name = esc_url(home_url());
+ }
+
+ return $site_name;
+ }
+
+ /**
+ * Send request to appsero if user skip to send tracking data
+ */
+ private function send_tracking_skipped_request()
+ {
+ $skipped = get_option($this->client->slug . '_tracking_skipped');
+
+ $data = [
+ 'hash' => $this->client->hash,
+ 'previously_skipped' => false,
+ ];
+
+ if ($skipped === 'yes') {
+ $data['previously_skipped'] = true;
+ } else {
+ update_option($this->client->slug . '_tracking_skipped', 'yes');
+ }
+
+ $this->client->send_request($data, 'tracking-skipped');
+ }
+
+ /**
+ * Deactivation modal styles
+ */
+ private function deactivation_modal_styles()
+ {
+ ?>
+
+client = $client;
+
+ $this->option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license';
+
+ $this->schedule_hook = $this->client->slug . '_license_check_event';
+
+ // Creating WP Ajax Endpoint to refresh license remotely
+ add_action( 'wp_ajax_appsero_refresh_license_' . $this->client->hash, [ $this, 'refresh_license_api' ] );
+
+ // Run hook to check license status daily
+ add_action( $this->schedule_hook, [ $this, 'check_license_status' ] );
+
+ // Active/Deactive corn schedule
+ $this->run_schedule();
+ }
+
+ /**
+ * Set the license option key.
+ *
+ * If someone wants to override the default generated key.
+ *
+ * @param string $key
+ *
+ * @since 1.3.0
+ *
+ * @return License
+ */
+ public function set_option_key( $key ) {
+ $this->option_key = $key;
+
+ return $this;
+ }
+
+ /**
+ * Get the license key
+ *
+ * @since 1.3.0
+ *
+ * @return string|null
+ */
+ public function get_license() {
+ return get_option( $this->option_key, null );
+ }
+
+ /**
+ * Check license
+ *
+ * @return array
+ */
+ public function check( $license_key ) {
+ $route = 'public/license/' . $this->client->hash . '/check';
+
+ return $this->send_request( $license_key, $route );
+ }
+
+ /**
+ * Active a license
+ *
+ * @return array
+ */
+ public function activate( $license_key ) {
+ $route = 'public/license/' . $this->client->hash . '/activate';
+
+ return $this->send_request( $license_key, $route );
+ }
+
+ /**
+ * Deactivate a license
+ *
+ * @return array
+ */
+ public function deactivate( $license_key ) {
+ $route = 'public/license/' . $this->client->hash . '/deactivate';
+
+ return $this->send_request( $license_key, $route );
+ }
+
+ /**
+ * Send common request
+ *
+ * @return array
+ */
+ protected function send_request( $license_key, $route ) {
+ $params = [
+ 'license_key' => $license_key,
+ 'url' => esc_url( home_url() ),
+ 'is_local' => $this->client->is_local_server(),
+ ];
+
+ $response = $this->client->send_request( $params, $route, true );
+
+ if ( is_wp_error( $response ) ) {
+ return [
+ 'success' => false,
+ 'error' => $response->get_error_message(),
+ ];
+ }
+
+ $response = json_decode( wp_remote_retrieve_body( $response ), true );
+
+ if ( empty( $response ) || isset( $response['exception'] ) ) {
+ return [
+ 'success' => false,
+ 'error' => $this->client->__trans( 'Unknown error occurred, Please try again.' ),
+ ];
+ }
+
+ if ( isset( $response['errors'] ) && isset( $response['errors']['license_key'] ) ) {
+ $response = [
+ 'success' => false,
+ 'error' => $response['errors']['license_key'][0],
+ ];
+ }
+
+ return $response;
+ }
+
+ /**
+ * License Refresh Endpoint
+ */
+ public function refresh_license_api() {
+ $this->check_license_status();
+
+ wp_send_json_success(
+ [
+ 'message' => 'License refreshed successfully.',
+ ],
+ 200
+ );
+ }
+
+ /**
+ * Add settings page for license
+ *
+ * @param array $args
+ *
+ * @return void
+ */
+ public function add_settings_page( $args = [] ) {
+ $defaults = [
+ 'type' => 'menu', // Can be: menu, options, submenu
+ 'page_title' => 'Manage License',
+ 'menu_title' => 'Manage License',
+ 'capability' => 'manage_options',
+ 'menu_slug' => $this->client->slug . '-manage-license',
+ 'icon_url' => '',
+ 'position' => null,
+ 'parent_slug' => '',
+ ];
+
+ $this->menu_args = wp_parse_args( $args, $defaults );
+
+ add_action( 'admin_menu', [ $this, 'admin_menu' ], 99 );
+ }
+
+ /**
+ * Admin Menu hook
+ *
+ * @return void
+ */
+ public function admin_menu() {
+ switch ( $this->menu_args['type'] ) {
+ case 'menu':
+ $this->create_menu_page();
+ break;
+
+ case 'submenu':
+ $this->create_submenu_page();
+ break;
+
+ case 'options':
+ $this->create_options_page();
+ break;
+ }
+ }
+
+ /**
+ * License menu output
+ */
+ public function menu_output() {
+ // process form data if submitted
+ if ( isset( $_POST['_nonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_nonce'] ) ), $this->client->name ) ) {
+ $form_data = [
+ '_nonce' => sanitize_key( wp_unslash( $_POST['_nonce'] ) ),
+ '_action' => isset( $_POST['_action'] ) ? sanitize_text_field( wp_unslash( $_POST['_action'] ) ) : '',
+ 'license_key' => isset( $_POST['license_key'] ) ? sanitize_text_field( wp_unslash( $_POST['license_key'] ) ) : '',
+ ];
+ $this->license_form_submit( $form_data );
+ }
+
+ $license = $this->get_license();
+ $action = ( $license && isset( $license['status'] ) && 'activate' === $license['status'] ) ? 'deactive' : 'active';
+ $this->licenses_style();
+ ?>
+
+
+
License Settings
+
+ show_license_page_notices();
+ do_action( 'before_appsero_license_section' );
+ ?>
+
+
+ show_license_page_card_header( $license ); ?>
+
+
+
+ client->__trans( 'Activate %s by your license key to get professional support and automatic update from your WordPress dashboard.' ), $this->client->name ); ?>
+
+
+
+ show_active_license_info( $license );
+ }
+ ?>
+
+
+
+
+
+ client->name ) ) {
+ $this->error = $this->client->__trans( 'Nonce vefification failed.' );
+
+ return;
+ }
+
+ if ( ! current_user_can( 'manage_options' ) ) {
+ $this->error = $this->client->__trans( 'You don\'t have permission to manage license.' );
+
+ return;
+ }
+
+ $license_key = ! empty( $form_data['license_key'] ) ? sanitize_text_field( wp_unslash( $form_data['license_key'] ) ) : '';
+ $action = ! empty( $form_data['_action'] ) ? sanitize_text_field( wp_unslash( $form_data['_action'] ) ) : '';
+
+ switch ( $action ) {
+ case 'active':
+ $this->active_client_license( $license_key );
+ break;
+
+ case 'deactive':
+ $this->deactive_client_license();
+ break;
+
+ case 'refresh':
+ $this->refresh_client_license();
+ break;
+ }
+ }
+
+ /**
+ * Check license status on schedule
+ */
+ public function check_license_status() {
+ $license = $this->get_license();
+
+ if ( isset( $license['key'] ) && ! empty( $license['key'] ) ) {
+ $response = $this->check( $license['key'] );
+
+ if ( isset( $response['success'] ) && $response['success'] ) {
+ $license['status'] = 'activate';
+ $license['remaining'] = $response['remaining'];
+ $license['activation_limit'] = $response['activation_limit'];
+ $license['expiry_days'] = $response['expiry_days'];
+ $license['title'] = $response['title'];
+ $license['source_id'] = $response['source_identifier'];
+ $license['recurring'] = $response['recurring'];
+ } else {
+ $license['status'] = 'deactivate';
+ $license['expiry_days'] = 0;
+ }
+
+ update_option( $this->option_key, $license, false );
+ }
+ }
+
+ /**
+ * Check this is a valid license
+ */
+ public function is_valid() {
+ if ( null !== $this->is_valid_license ) {
+ return $this->is_valid_license;
+ }
+
+ $license = $this->get_license();
+
+ if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] === 'activate' ) {
+ $this->is_valid_license = true;
+ } else {
+ $this->is_valid_license = false;
+ }
+
+ return $this->is_valid_license;
+ }
+
+ /**
+ * Check this is a valid license
+ */
+ public function is_valid_by( $option, $value ) {
+ $license = $this->get_license();
+
+ if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] === 'activate' ) {
+ if ( isset( $license[ $option ] ) && $license[ $option ] === $value ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Styles for licenses page
+ */
+ private function licenses_style() {
+ ?>
+
+
+
+
+
client->_etrans( 'Activations Remaining' ); ?>
+
+
client->_etrans( 'Unlimited' ); ?>
+
+
+ client->__trans( '%1$d out of %2$d' ), $license['remaining'], $license['activation_limit'] ); ?>
+
+
+
+
+
client->_etrans( 'Expires in' ); ?>
+ 21 ? '' : 'occupied';
+ echo '
' . $license['expiry_days'] . ' days
';
+ } else {
+ echo '
' . $this->client->__trans( 'Never' ) . '
';
+ }
+ ?>
+
+
+ error ) ) {
+ ?>
+
+ success ) ) {
+ ?>
+
+ ';
+ }
+
+ /**
+ * Card header
+ */
+ private function show_license_page_card_header( $license ) {
+ ?>
+
+
+
+
+
+
+
client->__trans( 'Activate License' ); ?>
+
+
+
+
+
+
+ error = $this->client->__trans( 'The license key field is required.' );
+
+ return;
+ }
+
+ $response = $this->activate( $license_key );
+
+ if ( ! $response['success'] ) {
+ $this->error = $response['error'] ? $response['error'] : $this->client->__trans( 'Unknown error occurred.' );
+
+ return;
+ }
+
+ $data = [
+ 'key' => $license_key,
+ 'status' => 'activate',
+ 'remaining' => $response['remaining'],
+ 'activation_limit' => $response['activation_limit'],
+ 'expiry_days' => $response['expiry_days'],
+ 'title' => $response['title'],
+ 'source_id' => $response['source_identifier'],
+ 'recurring' => $response['recurring'],
+ ];
+
+ update_option( $this->option_key, $data, false );
+
+ $this->success = $this->client->__trans( 'License activated successfully.' );
+ }
+
+ /**
+ * Deactive client license
+ */
+ private function deactive_client_license() {
+ $license = $this->get_license();
+
+ if ( empty( $license['key'] ) ) {
+ $this->error = $this->client->__trans( 'License key not found.' );
+
+ return;
+ }
+
+ $response = $this->deactivate( $license['key'] );
+
+ $data = [
+ 'key' => '',
+ 'status' => 'deactivate',
+ ];
+
+ update_option( $this->option_key, $data, false );
+
+ if ( ! $response['success'] ) {
+ $this->error = $response['error'] ? $response['error'] : $this->client->__trans( 'Unknown error occurred.' );
+
+ return;
+ }
+
+ $this->success = $this->client->__trans( 'License deactivated successfully.' );
+ }
+
+ /**
+ * Refresh Client License
+ */
+ private function refresh_client_license() {
+ $license = $this->get_license();
+
+ if ( ! $license || ! isset( $license['key'] ) || empty( $license['key'] ) ) {
+ $this->error = $this->client->__trans( 'License key not found' );
+
+ return;
+ }
+
+ $this->check_license_status();
+
+ $this->success = $this->client->__trans( 'License refreshed successfully.' );
+ }
+
+ /**
+ * Add license menu page
+ */
+ private function create_menu_page() {
+ call_user_func(
+ 'add_menu_page',
+ $this->menu_args['page_title'],
+ $this->menu_args['menu_title'],
+ $this->menu_args['capability'],
+ $this->menu_args['menu_slug'],
+ [ $this, 'menu_output' ],
+ $this->menu_args['icon_url'],
+ $this->menu_args['position']
+ );
+ }
+
+ /**
+ * Add submenu page
+ */
+ private function create_submenu_page() {
+ call_user_func(
+ 'add_submenu_page',
+ $this->menu_args['parent_slug'],
+ $this->menu_args['page_title'],
+ $this->menu_args['menu_title'],
+ $this->menu_args['capability'],
+ $this->menu_args['menu_slug'],
+ [ $this, 'menu_output' ],
+ $this->menu_args['position']
+ );
+ }
+
+ /**
+ * Add submenu page
+ */
+ private function create_options_page() {
+ call_user_func(
+ 'add_options_page',
+ $this->menu_args['page_title'],
+ $this->menu_args['menu_title'],
+ $this->menu_args['capability'],
+ $this->menu_args['menu_slug'],
+ [ $this, 'menu_output' ],
+ $this->menu_args['position']
+ );
+ }
+
+ /**
+ * Schedule daily sicense checker event
+ */
+ public function schedule_cron_event() {
+ if ( ! wp_next_scheduled( $this->schedule_hook ) ) {
+ wp_schedule_event( time(), 'daily', $this->schedule_hook );
+
+ wp_schedule_single_event( time() + 20, $this->schedule_hook );
+ }
+ }
+
+ /**
+ * Clear any scheduled hook
+ */
+ public function clear_scheduler() {
+ wp_clear_scheduled_hook( $this->schedule_hook );
+ }
+
+ /**
+ * Enable/Disable schedule
+ */
+ private function run_schedule() {
+ switch ( $this->client->type ) {
+ case 'plugin':
+ register_activation_hook( $this->client->file, [ $this, 'schedule_cron_event' ] );
+ register_deactivation_hook( $this->client->file, [ $this, 'clear_scheduler' ] );
+ break;
+
+ case 'theme':
+ add_action( 'after_switch_theme', [ $this, 'schedule_cron_event' ] );
+ add_action( 'switch_theme', [ $this, 'clear_scheduler' ] );
+ break;
+ }
+ }
+
+ /**
+ * Get input license key
+ *
+ * @return $license
+ */
+ private function get_input_license_value( $action, $license ) {
+ if ( 'active' === $action ) {
+ return isset( $license['key'] ) ? $license['key'] : '';
+ }
+
+ if ( 'deactive' === $action ) {
+ $key_length = strlen( $license['key'] );
+
+ return str_pad(
+ substr( $license['key'], 0, $key_length / 2 ),
+ $key_length,
+ '*'
+ );
+ }
+
+ return '';
+ }
+}
diff --git a/languages/wedocs.pot b/languages/wedocs.pot
index 8b6a2da..efcc382 100644
--- a/languages/wedocs.pot
+++ b/languages/wedocs.pot
@@ -9,7 +9,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"POT-Creation-Date: 2024-02-06T05:14:35+00:00\n"
+"POT-Creation-Date: 2024-02-27T14:13:40+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.8.1\n"
"X-Domain: wedocs\n"
diff --git a/package.json b/package.json
index 97ef363..e4bb943 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "weDocs",
- "version": "2.1.3",
+ "version": "2.1.4",
"description": "A documentation plugin for WordPress",
"author": "Tareq Hasan",
"license": "GPL",
diff --git a/readme.md b/readme.md
index 1ddd3e7..7b2a43e 100644
--- a/readme.md
+++ b/readme.md
@@ -2,7 +2,7 @@
The documentation plugin for WordPress. Create great looking documentation for your products.
-![WordPress Plugin Version](https://img.shields.io/badge/PLUGIN_VERSION-V2.1.3-blue) ![WordPress Plugin Active Installs](https://img.shields.io/badge/ACTIVE_INSTALLS-6K-green) ![WordPress Plugin Rating](https://img.shields.io/badge/RATING-4.8/5_(61)-green) ![WordPress Plugin: Tested WP Version](https://img.shields.io/badge/WORDPRESS-V6.4.2_TESTED-orange) ![WordPress Plugin Last Updated](https://img.shields.io/badge/LAST_UPDATED-FEBRUARY_2024-orange)
+![WordPress Plugin Version](https://img.shields.io/badge/PLUGIN_VERSION-V2.1.4-blue) ![WordPress Plugin Active Installs](https://img.shields.io/badge/ACTIVE_INSTALLS-6K-green) ![WordPress Plugin Rating](https://img.shields.io/badge/RATING-4.8/5_(61)-green) ![WordPress Plugin: Tested WP Version](https://img.shields.io/badge/WORDPRESS-V6.4.2_TESTED-orange) ![WordPress Plugin Last Updated](https://img.shields.io/badge/LAST_UPDATED-FEBRUARY_2024-orange)
## Description ##
diff --git a/readme.txt b/readme.txt
index c515bbb..a2627dc 100644
--- a/readme.txt
+++ b/readme.txt
@@ -5,7 +5,7 @@ Tags: WordPress documentation plugin, WordPress docs plugin, Documentation, Know
Requires at least: 5.6
Tested up to: 6.4.2
Requires PHP: 7.4
-Stable tag: 2.1.3
+Stable tag: 2.1.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -343,6 +343,10 @@ Can’t wait to join us?
== Changelog ==
+= v2.1.4 (29th February, 2024) =
+
+ * **Fix:** Update appsero sdk, manage from wedocs & handle deprecation error.
+
= v2.1.3 (6th February, 2024) =
* **Fix:** Updated Appsero Client SDK library to version 2.0.2 which will fix a security issue with the previous version of the library and a fatal error caused by the library.
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index a6567c7..cdac40a 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -12,7 +12,7 @@
$_tests_dir = getenv( 'WP_TESTS_DIR' );
if ( !$_tests_dir ) {
- $_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib';
+ $_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-Appsero';
}
if ( !file_exists( $_tests_dir . '/includes/functions.php' ) ) {
diff --git a/wedocs.php b/wedocs.php
index b169ad2..8361d7c 100644
--- a/wedocs.php
+++ b/wedocs.php
@@ -3,7 +3,7 @@
Plugin Name: weDocs
Plugin URI: https://wedocs.co/
Description: A documentation plugin for WordPress
-Version: 2.1.3
+Version: 2.1.4
Author: weDevs
Author URI: https://wedocs.co/?utm_source=wporg&utm_medium=banner&utm_campaign=author-uri
License: GPL2
@@ -58,7 +58,7 @@ final class WeDocs {
*
* @var string
*/
- const VERSION = '2.1.3';
+ const VERSION = '2.1.4';
/**
* The plugin url.