From ecbcaaf45309cab1ae11bfd5da9d153e5bcb5135 Mon Sep 17 00:00:00 2001
From: Martin Nestorov
Date: Tue, 19 Nov 2024 15:11:40 +0200
Subject: [PATCH 1/9] Initial commit
---
.gitignore | 43 +
CHANGELOG.md | 7 +-
admin/class-smarty-vslm-admin.php | 1360 +++++++++++++++++
admin/css/smarty-vslm-admin.css | 373 +++++
admin/index.php | 1 +
admin/js/smarty-vslm-admin.js | 63 +
admin/js/smarty-vslm-ajax.js | 67 +
admin/js/smarty-vslm-json.js | 36 +
admin/partials/smarty-vslm-admin-display.php | 27 +
includes/functions.php | 57 +
includes/index.php | 1 +
public/class-smarty-vslm-public.php | 77 +
public/css/smarty-vslm-public.css | 3 +
public/js/smarty-vslm-public.js | 30 +
.../partials/smarty-vslm-public-display.php | 14 +
uninstall.php | 28 +
16 files changed, 2185 insertions(+), 2 deletions(-)
create mode 100644 .gitignore
create mode 100644 admin/class-smarty-vslm-admin.php
create mode 100644 admin/css/smarty-vslm-admin.css
create mode 100644 admin/index.php
create mode 100644 admin/js/smarty-vslm-admin.js
create mode 100644 admin/js/smarty-vslm-ajax.js
create mode 100644 admin/js/smarty-vslm-json.js
create mode 100644 admin/partials/smarty-vslm-admin-display.php
create mode 100644 includes/functions.php
create mode 100644 includes/index.php
create mode 100644 public/class-smarty-vslm-public.php
create mode 100644 public/css/smarty-vslm-public.css
create mode 100644 public/js/smarty-vslm-public.js
create mode 100644 public/partials/smarty-vslm-public-display.php
create mode 100644 uninstall.php
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4637370
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,43 @@
+# Files not to ignore
+!.gitignore
+!README.md
+
+# Files to ignore
+package-lock.json
+
+# Ignore extensions
+*.diff
+*.err
+*.orig
+*.rej
+*.swo
+*.swp
+*.vi
+*~
+*.sass-cache
+
+# Ignore log files and databases
+*.log
+*.sql
+*.sqlite
+
+# OS or Editor folders
+.DS_Store
+Thumbs.db
+.cache
+.project
+.settings
+.tmproj
+*.esproj
+nbproject
+*.sublime-project
+*.sublime-workspace
+
+# Folders to ignore
+.hg
+.svn
+.CVS
+intermediate
+.idea
+cache
+node_modules/
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 27ec30d..dfc1321 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,7 @@
# Changelog
-### 1.0 (2024.11.12)
-- Initial release.
\ No newline at end of file
+### 1.0.0 (2024.11.12)
+- Initial release.
+
+### 1.0.1 (2024.11.19)
+- Code refactoring.
\ No newline at end of file
diff --git a/admin/class-smarty-vslm-admin.php b/admin/class-smarty-vslm-admin.php
new file mode 100644
index 0000000..da7d247
--- /dev/null
+++ b/admin/class-smarty-vslm-admin.php
@@ -0,0 +1,1360 @@
+plugin_name = $plugin_name;
+ $this->version = $version;
+
+ // Include and instantiate the Activity Logging class
+ $this->activity_logging = new Smarty_Vslm_Activity_Logging();
+ }
+
+ /**
+ * Register the stylesheets for the admin area.
+ *
+ * @since 1.0.1
+ */
+ public function enqueue_styles() {
+ /**
+ * This function enqueues custom CSS for the plugin settings in WordPress admin.
+ *
+ * An instance of this class should be passed to the run() function
+ * defined in Smarty_Form_Submissions_Loader as all of the hooks are defined
+ * in that particular class.
+ *
+ * The Smarty_Form_Submissions_Loader will then create the relationship
+ * between the defined hooks and the functions defined in this
+ * class.
+ */
+
+ wp_enqueue_style($this->plugin_name, plugin_dir_url(__FILE__) . 'css/smarty-vslm-admin.css', array(), $this->version, false);
+ }
+
+ /**
+ * Register the JavaScript for the admin area.
+ *
+ * @since 1.0.1
+ */
+ public function enqueue_scripts() {
+ /**
+ * This function enqueues custom JavaScript for the plugin settings in WordPress admin.
+ *
+ * An instance of this class should be passed to the run() function
+ * defined in Smarty_Form_Submissions_Loader as all of the hooks are defined
+ * in that particular class.
+ *
+ * The Smarty_Form_Submissions_Loader will then create the relationship
+ * between the defined hooks and the functions defined in this
+ * class.
+ */
+
+ global $post_type;
+
+ // Check if we're on the License Manager settings page
+ if ($hook === 'settings_page_smarty-vslm-settings') {
+ // Enqueue AJAX script for the settings page
+ wp_enqueue_script('vslm-ajax', plugin_dir_url(__FILE__) . 'js/smarty-vslm-ajax.js', array('jquery'), $this->version, true);
+
+ // Localize AJAX URL for the JavaScript
+ wp_localize_script('vslm-ajax', 'smarty_vslm_ajax', array(
+ 'ajax_url' => admin_url('admin-ajax.php')
+ ));
+ }
+
+ // Check if we're on any license-related pages (edit, add, or post screen)
+ if ($hook === 'edit.php' || $hook === 'post.php' || $hook === 'post-new.php') {
+ if ($post_type === 'vslm-licenses' || get_post_type() === 'vslm-licenses') {
+ // Enqueue CSS and JS files for license post type
+ wp_enqueue_script('vslm-admin-js', plugin_dir_url(__FILE__) . 'js/smarty-vslm-admin.js', array(), $this->version, true);
+ wp_enqueue_script('vslm-json-js', plugin_dir_url(__FILE__) . 'js/smarty-vslm-json.js', array(), $this->version, true);
+ }
+ }
+ }
+
+ /**
+ * Register the custom dashboard widget.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_add_dashboard_widget() {
+ wp_add_dashboard_widget(
+ 'smarty_vslm_dashboard_widget', // Widget ID
+ 'License Manager Overview', // Widget Title
+ 'smarty_vslm_dashboard_widget_render' // Callback function to display content
+ );
+ }
+ add_action('wp_dashboard_setup', 'smarty_vslm_add_dashboard_widget');
+
+ /**
+ * Render the content of the custom dashboard widget with a centered icon and link.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_dashboard_widget_render() {
+ // Query for licenses and count statuses
+ $total_count = wp_count_posts('vslm-licenses')->publish; // Get total published licenses
+ $active_count = smarty_vslm_get_license_count_by_status('active');
+ $inactive_count = smarty_vslm_get_license_count_by_status('inactive');
+ $expired_count = smarty_vslm_get_license_count_by_status('expired'); ?>
+
+
+
+
+
+
+
+ Status
+ Count
+
+
+
+
+ Active Licenses
+
+
+
+ Inactive Licenses
+
+
+
+ Expired Licenses
+
+
+
+
+
array(
+ 'name' => 'Licenses',
+ 'singular_name' => 'License',
+ 'add_new' => 'Add New License',
+ 'add_new_item' => 'Add New License',
+ 'edit_item' => 'Edit License',
+ 'new_item' => 'New License',
+ 'view_item' => 'View License',
+ 'search_items' => 'Search Licenses',
+ 'not_found' => 'No licenses found',
+ 'not_found_in_trash' => 'No licenses found in Trash',
+ ),
+ 'public' => true,
+ 'has_archive' => true,
+ 'supports' => array('title'), // Only 'title' support, no editor
+ 'menu_icon' => 'dashicons-admin-network',
+ 'show_in_rest' => true,
+ ));
+ }
+ add_action('init', 'vslm_register_license_post_type');
+
+ /**
+ * Customize the update messages for the License custom post type.
+ *
+ * @since 1.0.1
+ * @param array $messages Default update messages.
+ * @return array Modified update messages.
+ */
+ public function vslm_license_post_updated_messages($messages) {
+ global $post, $post_ID;
+
+ $messages['vslm-licenses'] = array(
+ 0 => '', // Unused. Messages start from index 1.
+ 1 => 'License updated.', // Updated
+ 2 => 'Custom field updated.',
+ 3 => 'Custom field deleted.',
+ 4 => 'License updated.',
+ 5 => isset($_GET['revision']) ? sprintf('License restored to revision from %s', wp_post_revision_title((int) $_GET['revision'], false)) : false,
+ 6 => 'License published.',
+ 7 => 'License saved.',
+ 8 => 'License submitted.',
+ 9 => sprintf(
+ 'License scheduled for: %1$s .',
+ date_i18n('M j, Y @ G:i', strtotime($post->post_date))
+ ),
+ 10 => 'License draft updated.'
+ );
+
+ return $messages;
+ }
+ add_filter('post_updated_messages', 'vslm_license_post_updated_messages');
+
+ /**
+ * Add custom meta boxes for license details in the license edit screen, with status dot after the title.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_add_license_meta_boxes() {
+ add_meta_box(
+ 'license_details',
+ vslm_license_meta_box_title(), // Set title with dynamic status dot
+ 'smarty_vslm_license_details_callback',
+ 'vslm-licenses',
+ 'normal',
+ 'default'
+ );
+ }
+ add_action('add_meta_boxes', 'vslm_add_license_meta_boxes');
+
+ /**
+ * Generate the title for the license meta box with a colored status dot.
+ *
+ * @since 1.0.1
+ * @return string The meta box title with a status dot.
+ */
+ public function vslm_license_meta_box_title() {
+ global $post;
+
+ // Get the license status
+ $status = get_post_meta($post->ID, '_status', true) ?: 'new';
+
+ // Determine the color for the dot based on status
+ $dot_color = $status === 'active' ? '#28a745' : '#dc3545'; // Green if active, red if inactive
+
+ // Set class based on status to handle the pulse effect only for 'active'
+ $status_class = 'smarty-vslm-status-circle-container--' . $status;
+
+ // Return the title with a container for the pulsing effect
+ return 'LICENSE ' . '#' . $post->ID . ' ';
+ }
+
+ /**
+ * Add a meta box for displaying the JSON response from the plugin status endpoint.
+ *
+ * @since 1.0.1
+ */
+ function vslm_add_json_response_meta_box() {
+ add_meta_box(
+ 'smarty_vslm_json_response',
+ __('Product Status (JSON)', 'smarty-very-simple-license-manager'),
+ 'smarty_vslm_json_response_meta_box_callback',
+ 'vslm-licenses',
+ 'normal',
+ 'default'
+ );
+ }
+ add_action('add_meta_boxes', 'vslm_add_json_response_meta_box');
+
+ /**
+ * Callback for the Plugin Status JSON Response meta box.
+ *
+ * @since 1.0.1
+ * @param WP_Post $post The current post object.
+ */
+ public function smarty_vslm_json_response_meta_box_callback($post) {
+ // Retrieve meta data
+ $multi_domain = get_post_meta($post->ID, '_multi_domain', true);
+ $usage_url = get_post_meta($post->ID, '_usage_url', true);
+ $usage_urls = get_post_meta($post->ID, '_usage_urls', true) ?: [];
+ $plugin_name = get_post_meta($post->ID, '_plugin_name', true);
+ $json_response_info = __('This is the product status JSON response from client site.', 'smarty-very-simple-license-manager');
+
+ // Validate plugin name
+ if (empty($plugin_name)) {
+ echo '' . __('Plugin Name is missing.', 'smarty-very-simple-license-manager') . '
';
+ return;
+ }
+
+ // Handle single-domain usage
+ if ($multi_domain !== '1') {
+ if (empty($usage_url)) {
+ echo '' . __('Usage URL is missing for single-domain usage.', 'smarty-very-simple-license-manager') . '
';
+ return;
+ }
+
+ $endpoint = trailingslashit(esc_url($usage_url)) . 'wp-json/' . sanitize_title($plugin_name) . '/v1/plugin-status';
+ ?>
+
+
+
+
+
+
+
+ ' . __('No usage URLs available for multi-domain usage.', 'smarty-very-simple-license-manager') . '
';
+ return;
+ } ?>
+
+
+
+
+
+
+
+ ' . __('Invalid or missing URL in multi-domain configuration.', 'smarty-very-simple-license-manager') . '';
+ }
+ }
+ }
+ }
+
+ /**
+ * Callback function to render the license details meta box.
+ *
+ * @since 1.0.1
+ * @param WP_Post $post The current post object.
+ */
+ public function smarty_vslm_license_details_callback($post) {
+ // Retrieve existing values from the post meta, if available
+ $product_terms = get_the_terms($post->ID, 'product'); // Get assigned product terms
+ $license_key = get_post_meta($post->ID, '_license_key', true);
+ $client_name = get_post_meta($post->ID, '_client_name', true);
+ $client_email = get_post_meta($post->ID, '_client_email', true);
+ $purchase_date = get_post_meta($post->ID, '_purchase_date', true);
+ $expiration_date = get_post_meta($post->ID, '_expiration_date', true);
+ $status = get_post_meta($post->ID, '_status', true);
+ $usage_url = get_post_meta($post->ID, '_usage_url', true); // Retrieve the usage URL
+ $usage_urls = get_post_meta($post->ID, '_usage_urls', true) ?: array();
+ $multi_domain = get_post_meta($post->ID, '_multi_domain', true);
+ $wp_version = get_post_meta($post->ID, '_wp_version', true); // Retrieve the WordPress version
+
+ // Retrieve plugin information
+ $plugin_name = get_post_meta($post->ID, '_plugin_name', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
+ $plugin_version = get_post_meta($post->ID, '_plugin_version', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
+
+ // Retrieve additional server information
+ $web_server = get_post_meta($post->ID, '_web_server', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
+ $server_ip = get_post_meta($post->ID, '_server_ip', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
+ $php_version = get_post_meta($post->ID, '_php_version', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
+
+ // Retrieve additional user info
+ $user_ip = get_post_meta($post->ID, '_user_ip', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
+ $browser = get_post_meta($post->ID, '_browser', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
+ $device_type = get_post_meta($post->ID, '_device_type', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
+ $os = get_post_meta($post->ID, '_os', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager')); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ post_type === 'vslm-licenses') {
+ // Verify nonce for security
+ if (!isset($_POST['smarty_vslm_license_nonce']) || !wp_verify_nonce($_POST['smarty_vslm_license_nonce'], 'smarty_vslm_save_license_meta')) {
+ return $post_id;
+ }
+
+ // Save multi-domain setting
+ $multi_domain = isset($_POST['multi_domain']) ? '1' : '0';
+ update_post_meta($post_id, '_multi_domain', $multi_domain);
+
+ if ($multi_domain !== '1') {
+ // Single-domain usage
+ if (isset($_POST['usage_url'])) {
+ $usage_url = esc_url_raw($_POST['usage_url']);
+ update_post_meta($post_id, '_usage_url', $usage_url);
+ }
+ // Delete the multi-domain usage URLs
+ delete_post_meta($post_id, '_usage_urls');
+ } else {
+ // Multi-domain usage
+ // Delete the single usage URL meta
+ delete_post_meta($post_id, '_usage_url');
+ // The _usage_urls meta will be managed via the REST API
+ }
+
+ // Auto-generate license key if none exists
+ $license_key = sanitize_text_field($_POST['license_key']);
+ if (empty($license_key)) {
+ $license_key = strtoupper(wp_generate_password(16, false, false));
+ }
+ update_post_meta($post_id, '_license_key', $license_key);
+
+ // Update other fields
+ update_post_meta($post_id, '_client_name', sanitize_text_field($_POST['client_name']));
+ update_post_meta($post_id, '_client_email', sanitize_email($_POST['client_email']));
+ update_post_meta($post_id, '_purchase_date', sanitize_text_field($_POST['purchase_date']));
+ update_post_meta($post_id, '_expiration_date', sanitize_text_field($_POST['expiration_date']));
+ update_post_meta($post_id, '_status', sanitize_text_field($_POST['status']));
+
+ if (isset($_POST['product'])) {
+ wp_set_post_terms($post_id, array(intval($_POST['product'])), 'product');
+ }
+ }
+ }
+ add_action('save_post', 'smarty_vslm_save_license_meta', 10, 2);
+
+ /**
+ * Set a numeric slug for licenses instead of a title-based slug.
+ *
+ * @since 1.0.1
+ * @param array $data The array of sanitized post data.
+ * @param array $postarr The array of unsanitized post data.
+ * @return array Modified post data with a numeric slug.
+ */
+ public function smarty_vslm_set_numeric_slug($data, $postarr) {
+ if ($data['post_type'] === 'vslm-licenses' && $data['post_status'] === 'publish') {
+ // Generate a unique numeric slug based on the post ID
+ if (empty($postarr['ID'])) {
+ // If it's a new post, use the current timestamp
+ $numeric_slug = time();
+ } else {
+ // For existing posts, use the post ID
+ $numeric_slug = $postarr['ID'];
+ }
+ $data['post_name'] = $numeric_slug; // Set the slug to be the numeric value
+ }
+ return $data;
+ }
+ add_filter('wp_insert_post_data', 'smarty_vslm_set_numeric_slug', 10, 2);
+
+ /**
+ * Register the 'Products' taxonomy for licenses.
+ *
+ * @since 1.0.1
+ */
+ public function smarty_vslm_register_product_taxonomy() {
+ register_taxonomy('product', 'vslm-licenses', array(
+ 'labels' => array(
+ 'name' => esc_html(__('Products', 'smarty-very-simple-license-manager')),
+ 'singular_name' => esc_html(__('Product', 'smarty-very-simple-license-manager')),
+ 'search_items' => esc_html(__('Search Products', 'smarty-very-simple-license-manager')),
+ 'all_items' => esc_html(__('All Products', 'smarty-very-simple-license-manager')),
+ 'edit_item' => esc_html(__('Edit Product', 'smarty-very-simple-license-manager')),
+ 'view_item' => esc_html(__('View Product', 'smarty-very-simple-license-manager')),
+ 'add_new_item' => esc_html(__('Add New Product', 'smarty-very-simple-license-manager')),
+ 'new_item_name' => esc_html(__('New Product Name', 'smarty-very-simple-license-manager')),
+ 'menu_name' => esc_html(__('Products', 'smarty-very-simple-license-manager')),
+ ),
+ 'hierarchical' => true,
+ 'show_ui' => true,
+ 'show_in_rest' => true,
+ 'query_var' => true,
+ 'rewrite' => array('slug' => 'product'),
+ ));
+ }
+ add_action('init', 'smarty_vslm_register_product_taxonomy');
+
+ /**
+ * Remove the "View Posts" link from the admin bar for the License post type.
+ *
+ * @since 1.0.1
+ * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar instance.
+ */
+ public function smarty_vslm_remove_admin_bar_view_posts($wp_admin_bar) {
+ // Check if we're in the License custom post type or editing it
+ global $post_type, $post;
+
+ // Only proceed if we're in the admin area and dealing with the "vslm-licenses" post type
+ if (is_admin() && ($post_type === 'vslm-licenses' || (isset($post) && $post->post_type === 'vslm-licenses'))) {
+ // Remove any "View Posts" or similar links in the admin bar related to this post type
+ $wp_admin_bar->remove_node('edit'); // Standard "Edit" node ID
+ $wp_admin_bar->remove_node('view'); // Commonly used for "View" link in admin bar
+ $wp_admin_bar->remove_node('archive'); // Possible ID for "Archive" links
+ $wp_admin_bar->remove_menu('view'); // Extra attempt in case `remove_node` does not cover all cases
+ }
+ }
+ add_action('admin_bar_menu', 'smarty_vslm_remove_admin_bar_view_posts', 999);
+
+ /**
+ * Remove the "View" link from the row actions for licenses in the admin list.
+ *
+ * @since 1.0.1
+ * @param array $actions The current row actions.
+ * @param WP_Post $post The current post object.
+ * @return array Modified row actions without the "View" link.
+ */
+ function smarty_vslm_remove_view_link($actions, $post) {
+ // Check if the current post type is "license"
+ if ($post->post_type === 'vslm-licenses') {
+ unset($actions['view']); // Remove the "View" action
+ }
+ return $actions;
+ }
+ add_filter('post_row_actions', 'smarty_vslm_remove_view_link', 10, 2);
+
+ /**
+ * Remove "Quick Edit" from the row actions in the licenses list.
+ *
+ * @since 1.0.1
+ * @param array $actions The current row actions.
+ * @param WP_Post $post The current post object.
+ * @return array Modified row actions without the "Quick Edit" option.
+ */
+ function smarty_vslm_remove_quick_edit($actions, $post) {
+ if ($post->post_type === 'vslm-licenses') {
+ unset($actions['inline hide-if-no-js']); // Remove the "Quick Edit" action
+ }
+ return $actions;
+ }
+ add_filter('post_row_actions', 'smarty_vslm_remove_quick_edit', 10, 2);
+
+ /**
+ * Add custom columns for License Key, Status, Expiration Date, and User Email in the licenses list table.
+ *
+ * @since 1.0.1
+ * @param array $columns The current list of columns.
+ * @return array Modified list of columns.
+ */
+ public function smarty_vslm_add_license_columns($columns) {
+ unset($columns['title']);
+ // Define the new columns order, placing "Product" first
+ $new_columns = array(
+ 'product' => esc_html(__('Product', 'smarty-very-simple-license-manager')),
+ 'product_version' => esc_html(__('Version', 'smarty-very-simple-license-manager')),
+ 'license_key' => esc_html(__('License Key', 'smarty-very-simple-license-manager')),
+ 'purchase_date' => esc_html(__('Purchase Date', 'smarty-very-simple-license-manager')),
+ 'expiration_date' => esc_html(__('Expiration Date', 'smarty-very-simple-license-manager')),
+ 'client_name' => esc_html(__('Client Name', 'smarty-very-simple-license-manager')),
+ 'client_email' => esc_html(__('Client Email', 'smarty-very-simple-license-manager')),
+ 'usage_urls' => esc_html(__('Usage URL(s)', 'smarty-very-simple-license-manager')),
+ 'license_status' => esc_html(__('Status', 'smarty-very-simple-license-manager')),
+ );
+
+ return $new_columns;
+ }
+ add_filter('manage_vslm-licenses_posts_columns', 'smarty_vslm_add_license_columns');
+
+ /**
+ * Populate the custom columns for License Key, Status, Expiration Date, and User Email.
+ *
+ * @since 1.0.1
+ * @param string $column The name of the column.
+ * @param int $post_id The ID of the current post.
+ */
+ public function smarty_vslm_fill_license_columns($column, $post_id) {
+ if ($column === 'license_key') {
+ $license_key = get_post_meta($post_id, '_license_key', true);
+ $masked_key = substr($license_key, 0, 4) . '-XXXX-XXXX-XXXX';
+
+ echo '';
+
+ // Masked key
+ echo '
' . esc_html($masked_key) . ' ';
+ echo '
';
+
+ // Show/Hide and Copy links
+ echo '
';
+ echo '
Show ';
+ echo '
Hide ';
+ echo '
| ';
+ echo '
Copy ';
+ echo '
';
+
+ echo '
';
+ } elseif ($column === 'license_status') {
+ $status = get_post_meta($post_id, '_status', true);
+ $status_text = ucfirst($status);
+
+ if ($status === 'active') {
+ echo '' . $status_text . ' ';
+ } elseif ($status === 'inactive') {
+ echo '' . $status_text . ' ';
+ } elseif ($status === 'expired') {
+ echo '' . $status_text . ' ';
+ } else {
+ echo '' . $status_text . ' ';
+ }
+ } elseif ($column === 'purchase_date') {
+ $purchase_date = get_post_meta($post_id, '_purchase_date', true);
+ $formatted_purchase_date = date('Y/m/d', strtotime($purchase_date)); // Format as YYYY/MM/DD
+ echo esc_html($formatted_purchase_date);
+ } elseif ($column === 'expiration_date') {
+ $expiration_date = get_post_meta($post_id, '_expiration_date', true);
+ $formatted_expiration_date = date('Y/m/d', strtotime($expiration_date));
+ echo esc_html($formatted_expiration_date);
+
+ // Calculate days left if the expiration date is valid
+ $current_date = new DateTime();
+ $expiration = new DateTime($expiration_date);
+ $interval = $current_date->diff($expiration);
+
+ if ($interval->invert === 0) { // Not expired yet
+ echo '' . $interval->days . ' days left ';
+ } else {
+ echo '0 days left ';
+ }
+ } elseif ($column === 'client_name') {
+ echo esc_html(get_post_meta($post_id, '_client_name', true));
+ } elseif ($column === 'client_email') {
+ echo esc_html(get_post_meta($post_id, '_client_email', true));
+ } elseif ($column === 'usage_urls') {
+ $multi_domain = get_post_meta($post_id, '_multi_domain', true);
+ if ($multi_domain === '1') {
+ $usage_urls = get_post_meta($post_id, '_usage_urls', true) ?: array();
+ if (!empty($usage_urls)) {
+ foreach ($usage_urls as $url_data) {
+ if (is_array($url_data) && isset($url_data['site_url'])) {
+ echo '' . esc_html($url_data['site_url']) . '
';
+ }
+ }
+ } else {
+ echo '—';
+ }
+ } else {
+ $usage_url = get_post_meta($post_id, '_usage_url', true);
+ echo $usage_url ? esc_url($usage_url) : '—';
+ }
+ } elseif ($column === 'product') {
+ // Display the product name(s)
+ $product_terms = get_the_terms($post_id, 'product');
+ if (!empty($product_terms) && !is_wp_error($product_terms)) {
+ $product_names = wp_list_pluck($product_terms, 'name');
+ echo '' . esc_html(implode(', ', $product_names)) . ' ';
+ } else {
+ echo '—'; // Display a dash if no product is assigned
+ }
+ } elseif ($column === 'product_version') {
+ // Retrieve the product version from the post meta
+ $product_version = get_post_meta($post_id, '_plugin_version', true);
+
+ // Display the product version or a placeholder if not available
+ echo $product_version ? esc_html($product_version) : esc_html(__('Not recorded', 'smarty-very-simple-license-manager'));
+ }
+ }
+ add_action('manage_vslm-licenses_posts_custom_column', 'smarty_vslm_fill_license_columns', 10, 2);
+
+ /**
+ * Define sortable columns for License Key and Status.
+ *
+ * @since 1.0.1
+ * @param array $columns The current list of sortable columns.
+ * @return array Modified list of sortable columns.
+ */
+ public function smarty_vslm_sortable_license_columns($columns) {
+ $columns['license_key'] = 'license_key';
+ $columns['license_status'] = 'license_status';
+ return $columns;
+ }
+ add_filter('manage_edit-vslm-licenses_sortable_columns', 'smarty_vslm_sortable_license_columns');
+
+ /**
+ * Make the Status column sortable in the admin.
+ *
+ * @since 1.0.1
+ * @param array $columns List of sortable columns.
+ * @return array Updated sortable columns.
+ */
+ public function smarty_vslm_license_sortable_columns($columns) {
+ $columns['license_status'] = 'license_status';
+ return $columns;
+ }
+ add_filter('manage_edit-license_sortable_columns', 'smarty_vslm_license_sortable_columns');
+
+ /**
+ * Sort the licenses by status in the admin.
+ *
+ * @since 1.0.1
+ * @param WP_Query $query The current WP_Query object.
+ */
+ public function smarty_vslm_license_orderby_status($query) {
+ if (!is_admin()) {
+ return;
+ }
+
+ $orderby = $query->get('orderby');
+ if ('license_status' === $orderby) {
+ $query->set('meta_key', '_status');
+ $query->set('orderby', 'meta_value');
+ }
+ }
+ add_action('pre_get_posts', 'smarty_vslm_license_orderby_status');
+
+ /**
+ * Modify the query to handle sorting by license key and status.
+ *
+ * @since 1.0.1
+ * @param WP_Query $query The current WP_Query instance.
+ */
+ public function smarty_vslm_orderby_license_columns($query) {
+ if (!is_admin()) return;
+ if ($query->get('orderby') === 'license_key') {
+ $query->set('meta_key', '_license_key');
+ $query->set('orderby', 'meta_value');
+ }
+ if ($query->get('orderby') === 'license_status') {
+ $query->set('meta_key', '_status');
+ $query->set('orderby', 'meta_value');
+ }
+ }
+ add_action('pre_get_posts', 'smarty_vslm_orderby_license_columns');
+
+ /**
+ * @since 1.0.1
+ */
+ public function smarty_vslm_custom_admin_styles() {
+ global $post_type;
+
+ if ('vslm-licenses' === $post_type) {
+ echo '';
+ }
+ }
+ add_action('admin_head', 'smarty_vslm_custom_admin_styles');
+
+ /**
+ * Adds an options page for the plugin in the WordPress admin menu.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_add_settings_page() {
+ add_submenu_page(
+ 'options-general.php',
+ __('License Manager | Settings', 'smarty-very-simple-license-manager'),
+ __('License Manager', 'smarty-very-simple-license-manager'),
+ 'manage_options',
+ 'smarty-vslm-settings',
+ 'smarty_vslm_settings_page_html'
+ );
+ add_submenu_page(
+ 'options-general.php',
+ __('Form Submissions | Settings', 'smarty-form-submissions'),
+ __('Form Submissions', 'smarty-form-submissions'),
+ 'manage_options',
+ 'smarty-fs-settings',
+ array($this, 'fs_display_settings_page')
+ );
+ }
+
+ /**
+ * Outputs the HTML for the settings page.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_display_settings_page() {
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+
+ // Define the path to the external file
+ $partial_file = plugin_dir_path(__FILE__) . 'partials/smarty-vslm-admin-display.php';
+
+ if (file_exists($partial_file) && is_readable($partial_file)) {
+ include_once $partial_file;
+ } else {
+ _vslm_write_logs("Unable to include: '$partial_file'");
+ }
+ }
+
+ /**
+ * Initializes the plugin settings by registering the settings, sections, and fields.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_settings_init() {
+ register_setting('smarty_vslm_settings', 'smarty_vslm_ck_key');
+ register_setting('smarty_vslm_settings', 'smarty_vslm_cs_key');
+
+ // Add General section
+ add_settings_section(
+ 'smarty_vslm_section_general', // ID of the section
+ __('General', 'smarty-very-simple-license-manager'), // Title of the section
+ 'smarty_vslm_section_general_callback', // Callback function that fills the section with the desired content
+ 'smarty_vslm_settings' // Page on which to add the section
+ );
+
+ add_settings_field(
+ 'smarty_vslm_ck_key',
+ __('Consumer Key', 'smarty-very-simple-license-manager'),
+ 'smarty_vslm_ck_key_callback',
+ 'smarty_vslm_settings',
+ 'smarty_vslm_section_general'
+ );
+
+ add_settings_field(
+ 'smarty_vslm_cs_key',
+ __('Consumer Secret', 'smarty-very-simple-license-manager'),
+ 'smarty_vslm_cs_key_callback',
+ 'smarty_vslm_settings',
+ 'smarty_vslm_section_general'
+ );
+ }
+
+ /**
+ * General section callback for the License Manager.
+ *
+ * @since 1.0.1
+ */
+ public function smarty_vslm_section_general_callback() { ?>
+
+
+
+
+
+
+
+
'GET',
+ 'callback' => 'smarty_vslm_check_license_status',
+ 'permission_callback' => 'smarty_vslm_basic_auth_permission_check',
+ ));
+ }
+ add_action('rest_api_init', 'smarty_vslm_register_license_status_endpoint');
+
+ /**
+ * Permission callback for Basic Auth.
+ *
+ * @since 1.0.1
+ * @return bool True if authentication is successful, false otherwise.
+ */
+ public function smarty_vslm_basic_auth_permission_check() {
+ $headers = getallheaders();
+ if (isset($headers['Authorization'])) {
+ $auth_header = $headers['Authorization'];
+ if (strpos($auth_header, 'Basic ') === 0) {
+ $encoded_credentials = substr($auth_header, 6);
+ $decoded_credentials = base64_decode($encoded_credentials);
+ list($provided_ck_key, $provided_cs_key) = explode(':', $decoded_credentials, 2);
+
+ // Retrieve the stored keys
+ $stored_ck_key = get_option('smarty_vslm_ck_key');
+ $stored_cs_key = get_option('smarty_vslm_cs_key');
+
+ // Validate credentials
+ if ($provided_ck_key === $stored_ck_key && $provided_cs_key === $stored_cs_key) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Callback for the REST API endpoint to check license status.
+ *
+ * @since 1.0.1
+ * @param WP_REST_Request $request The REST request object.
+ * @return WP_REST_Response The REST response with license status, expiration date, usage URL, and WordPress version.
+ */
+ public function smarty_vslm_check_license_status(WP_REST_Request $request) {
+ $license_key = $request->get_param('license_key');
+ $site_url = $request->get_param('site_url');
+ $wp_version = $request->get_param('wp_version');
+ $web_server = $request->get_param('web_server');
+ $server_ip = $request->get_param('server_ip');
+ $php_version = $request->get_param('php_version');
+ $plugin_name = $request->get_param('plugin_name');
+ $plugin_version = $request->get_param('plugin_version');
+ $user_ip = $request->get_param('user_ip');
+ $browser = $request->get_param('browser');
+ $device_type = $request->get_param('device_type');
+ $os = $request->get_param('os');
+
+ // Find the license by key
+ $license_posts = get_posts(array(
+ 'post_type' => 'vslm-licenses',
+ 'meta_query' => array(
+ array(
+ 'key' => '_license_key',
+ 'value' => $license_key,
+ 'compare' => '='
+ )
+ )
+ ));
+
+ if (empty($license_posts)) {
+ return new WP_REST_Response([
+ 'status' => 'rest_no_route',
+ 'message' => 'The requested route does not exist.',
+ ], 404);
+ }
+
+ $license_id = $license_posts[0]->ID;
+ $multi_domain = get_post_meta($license_id, '_multi_domain', true);
+
+ if (!empty($site_url) && filter_var($site_url, FILTER_VALIDATE_URL)) {
+ if ($multi_domain === '1') {
+ // Multi-domain handling
+ $usage_urls = get_post_meta($license_id, '_usage_urls', true) ?: [];
+
+ // Check if the URL already exists
+ $existing_key = array_search($site_url, array_column($usage_urls, 'site_url'));
+
+ $url_data = [
+ 'site_url' => $site_url,
+ 'wp_version' => $wp_version,
+ 'plugin_version' => $plugin_version,
+ 'web_server' => $web_server,
+ 'server_ip' => $server_ip,
+ 'php_version' => $php_version,
+ 'user_ip' => $user_ip,
+ 'browser' => $browser,
+ 'device_type' => $device_type,
+ 'os' => $os,
+ ];
+
+ if ($existing_key !== false) {
+ // Update existing entry
+ $usage_urls[$existing_key] = $url_data;
+ } else {
+ // Add new entry
+ $usage_urls[] = $url_data;
+ }
+
+ update_post_meta($license_id, '_usage_urls', $usage_urls);
+ } else {
+ // Single-domain usage
+ $existing_usage_url = get_post_meta($license_id, '_usage_url', true);
+
+ if (empty($existing_usage_url) || $existing_usage_url === $site_url) {
+ update_post_meta($license_id, '_usage_url', esc_url_raw($site_url));
+ } else {
+ return new WP_REST_Response([
+ 'status' => 'error',
+ 'message' => 'License already activated on another domain.',
+ ], 403);
+ }
+ }
+ }
+
+ if (!empty($wp_version)) {
+ update_post_meta($license_id, '_wp_version', sanitize_text_field($wp_version));
+ }
+
+ if (!empty($plugin_name)) {
+ update_post_meta($license_id, '_plugin_name', sanitize_text_field($plugin_name));
+ }
+
+ if (!empty($plugin_version)) {
+ update_post_meta($license_id, '_plugin_version', sanitize_text_field($plugin_version));
+ }
+
+ if (!empty($web_server)) {
+ update_post_meta($license_id, '_web_server', sanitize_text_field($web_server));
+ }
+
+ if (!empty($server_ip)) {
+ update_post_meta($license_id, '_server_ip', sanitize_text_field($server_ip));
+ }
+
+ if (!empty($php_version)) {
+ update_post_meta($license_id, '_php_version', sanitize_text_field($php_version));
+ }
+
+ if (!empty($user_ip)) {
+ update_post_meta($license_id, '_user_ip', sanitize_text_field($user_ip));
+ }
+
+ if (!empty($browser)) {
+ update_post_meta($license_id, '_browser', sanitize_text_field($browser));
+ }
+
+ if (!empty($device_type)) {
+ update_post_meta($license_id, '_device_type', sanitize_text_field($device_type));
+ }
+
+ if (!empty($os)) {
+ update_post_meta($license_id, '_os', sanitize_text_field($os));
+ }
+
+ // Retrieve license status, expiration date, usage URL, WP version, Web server and Server IP
+ $license_status = get_post_meta($license_id, '_status', true);
+ $expiration_date = get_post_meta($license_id, '_expiration_date', true);
+ $stored_wp_version = get_post_meta($license_id, '_wp_version', true);
+ $stored_web_server = get_post_meta($license_id, '_web_server', true);
+ $stored_server_ip = get_post_meta($license_id, '_server_ip', true);
+ $stored_php_version = get_post_meta($license_id, '_php_version', true);
+ $stored_plugin_name = get_post_meta($license_id, '_plugin_name', true);
+ $stored_plugin_version = get_post_meta($license_id, '_plugin_version', true);
+ $stored_user_ip = get_post_meta($license_id, '_user_ip', true);
+ $stored_browser = get_post_meta($license_id, '_browser', true);
+ $stored_device_type = get_post_meta($license_id, '_device_type', true);
+ $stored_os = get_post_meta($license_id, '_os', true);
+
+ $response_data = array(
+ 'status' => $license_status,
+ 'expiration_date' => $expiration_date,
+ 'multi_domain' => $multi_domain === '1',
+ 'wp_version' => $stored_wp_version,
+ 'web_server' => $stored_web_server,
+ 'server_ip' => $stored_server_ip,
+ 'php_version' => $stored_php_version,
+ 'plugin_name' => $stored_plugin_name,
+ 'plugin_version' => $stored_plugin_version,
+ 'user_ip' => $stored_user_ip,
+ 'browser' => $stored_browser,
+ 'device_type' => $stored_device_type,
+ 'os' => $stored_os,
+ );
+
+ if ($multi_domain === '1') {
+ $response_data['usage_urls'] = get_post_meta($license_id, '_usage_urls', true) ?: array();
+ } else {
+ $response_data['usage_url'] = get_post_meta($license_id, '_usage_url', true);
+ }
+
+ return new WP_REST_Response([
+ 'status' => $license_status ? $license_status : 'inactive',
+ 'expiration_date' => $expiration_date,
+ 'message' => 'License status retrieved successfully.',
+ ], 200);
+ }
+
+ /**
+ * Schedule a daily cron job to check for expired licenses.
+ *
+ * @since 1.0.1
+ */
+ public function smarty_vslm_schedule_cron_job() {
+ if (!wp_next_scheduled('smarty_vslm_license_check')) {
+ wp_schedule_event(time(), 'daily', 'smarty_vslm_license_check');
+ }
+ }
+ add_action('wp', 'smarty_vslm_schedule_cron_job');
+
+ /**
+ * Cron job function to mark expired licenses as expired.
+ *
+ * @since 1.0.1
+ */
+ public function smarty_vslm_check_expired_licenses() {
+ $licenses = get_posts(array('post_type' => 'vslm-licenses', 'posts_per_page' => -1));
+ foreach ($licenses as $license) {
+ $expiration_date = get_post_meta($license->ID, '_expiration_date', true);
+ if (strtotime($expiration_date) < time()) {
+ update_post_meta($license->ID, '_status', 'expired');
+ }
+ }
+ }
+ add_action('smarty_vslm_license_check', 'smarty_vslm_check_expired_licenses');
+}
\ No newline at end of file
diff --git a/admin/css/smarty-vslm-admin.css b/admin/css/smarty-vslm-admin.css
new file mode 100644
index 0000000..4691271
--- /dev/null
+++ b/admin/css/smarty-vslm-admin.css
@@ -0,0 +1,373 @@
+/**
+ * All of the CSS for plugin admin functionality should be included in this file.
+ */
+
+.smarty-vslm-status-circle {
+ width: 15px;
+ height: 15px;
+ border-radius: 50%;
+ margin-left: 8px;
+}
+
+/* Checkbox Styling */
+.smarty-vslm-checkbox {
+ display: inline-block;
+ position: relative;
+ width: 24px;
+ height: 24px;
+}
+
+.smarty-vslm-checkbox input[type="checkbox"] {
+ opacity: 0;
+ width: 24px;
+ height: 24px;
+ position: absolute;
+ cursor: pointer;
+}
+
+.smarty-vslm-checkbox .checkmark {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 20px;
+ height: 20px;
+ background-color: #e6e6e6;
+ border-radius: 4px;
+ transition: background-color 0.3s ease;
+}
+
+.smarty-vslm-checkbox input[type="checkbox"]:checked ~ .checkmark {
+ background-color: #28a745; /* Change color when checked */
+}
+
+.smarty-vslm-checkbox .checkmark::after {
+ content: "";
+ position: absolute;
+ display: none;
+}
+
+.smarty-vslm-checkbox input[type="checkbox"]:checked ~ .checkmark::after {
+ display: block;
+}
+
+.smarty-vslm-checkbox .checkmark::after {
+ left: 7px;
+ top: 3px;
+ width: 4px;
+ height: 10px;
+ border: solid white;
+ border-top-width: medium;
+ border-right-width: medium;
+ border-bottom-width: medium;
+ border-left-width: medium;
+ border-width: 0 2px 2px 0;
+ transform: rotate(45deg);
+}
+
+/* Two-column Layout */
+.smarty-vslm-two-col {
+ display: flex;
+ gap: 10px;
+}
+
+.smarty-vslm-left-col, .smarty-vslm-right-col {
+ flex: 1;
+ border-left: 1px solid #ddd;
+}
+
+.smarty-vslm-left-col {
+ border-left: none;
+}
+
+/* Table styling */
+.smarty-vslm-license-table {
+ width: 100%;
+ max-width: 100%;
+ border-collapse: collapse;
+}
+
+.smarty-vslm-license-table td {
+ padding: 10px 15px;
+ vertical-align: middle;
+}
+
+.smarty-vslm-license-table label {
+ font-weight: bold;
+ display: inline-block;
+ text-align: right;
+ vertical-align: middle;
+ vertical-align: -moz-middle-with-baseline;
+ width: 100%;
+}
+
+.smarty-vslm-license-table .smarty-vslm-field-wrapper {
+ display: flex;
+ align-items: center;
+}
+
+.smarty-vslm-license-table input,
+.smarty-vslm-license-table select {
+ width: 100%;
+}
+
+.smarty-vslm-license-table input[type="checkbox"] {
+ width: auto;
+}
+
+.smarty-vslm-license-table .usage-urls br:first-of-type {
+ margin-bottom: 10px;
+ }
+
+.smarty-vslm-license-table .usage-urls br:last-of-type {
+ display: none;
+}
+
+/* Inner (nested) table styling */
+.smarty-vslm-nested-table {
+ border-collapse: collapse;
+ width: 100%;
+ margin: 10px 0;
+ text-align: left;
+ border: 1px solid #ccc;
+}
+
+.smarty-vslm-nested-table td {
+ padding: 8px 10px;
+ border: 1px solid #ccc;
+}
+
+.smarty-vslm-nested-table tr:nth-child(even) {
+ background-color: #f9f9f9;
+}
+
+.smarty-vslm-nested-table tr:nth-child(odd) {
+ background-color: #fff;
+}
+
+.smarty-vslm-generate-key-button {
+ margin-left: 10px;
+ white-space: nowrap;
+}
+
+@media (max-width: 600px) {
+ .smarty-vslm-license-table td {
+ display: block;
+ width: 100%;
+ }
+ .smarty-vslm-generate-key-button {
+ margin-top: 5px;
+ margin-left: 0;
+ }
+}
+
+.smarty-vslm-license-key-wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+}
+
+.smarty-vslm-masked-key {
+ border: 1px solid #ededf0;
+ border-radius: 3px;
+ padding: 2px 4px;
+ background-color: #fefefe;
+ width: 160px;
+}
+
+.smarty-vslm-key-toggle-links a {
+ color: #2271b1;
+ cursor: pointer;
+ text-decoration: none;
+ margin-right: 5px;
+}
+
+.smarty-vslm-key-toggle-links a:hover {
+ color: #135e96;
+ text-decoration: none;
+}
+
+/* License Status Styling */
+.smarty-vslm-status-badge.active {
+ background-color: #d9f2d9; /* Light green background */
+ color: #28a745; /* Darker green text */
+ font-weight: bold;
+ padding: 4px 8px;
+ border-radius: 4px;
+}
+
+.smarty-vslm-status-badge.inactive {
+ background-color: #f8d7da; /* Light red background */
+ color: #dc3545; /* Darker red text */
+ font-weight: bold;
+ padding: 4px 8px;
+ border-radius: 4px;
+}
+
+.smarty-vslm-status-badge.expired {
+ background-color: #b3cbdd;
+ color: #2e5877;
+ font-weight: bold;
+ padding: 4px 8px;
+ border-radius: 4px;
+}
+
+/* Outer container to position the circles */
+.smarty-vslm-status-circle-container {
+ position: relative;
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ vertical-align: middle;
+}
+
+/* Main status circle */
+.smarty-vslm-status-circle {
+ position: relative;
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ z-index: 2;
+}
+
+/* Active status with pulsing effect */
+.smarty-vslm-status-circle-container--active .smarty-vslm-status-circle {
+ background-color: #28a745; /* Active color */
+}
+.smarty-vslm-status-circle-container--active::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 10px;
+ width: 80%;
+ height: 80%;
+ border-radius: 50%;
+ background-color: rgba(40, 167, 69, 0.9); /* Slightly lighter green for pulse */
+ z-index: 1;
+ animation: pulse-active 1.9s infinite ease-out;
+}
+
+/* Inactive status with pulsing effect */
+.smarty-vslm-status-circle-container--inactive .smarty-vslm-status-circle {
+ background-color: #dc3545; /* Inactive color */
+}
+
+.smarty-vslm-status-circle-container--inactive::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 10px;
+ width: 80%;
+ height: 80%;
+ border-radius: 50%;
+ background-color: rgba(220, 53, 69, 0.9); /* Slightly lighter red for pulse */
+ z-index: 1;
+ animation: pulse-inactive 1.9s infinite ease-out;
+}
+
+/* Expired status with pulsing effect */
+.smarty-vslm-status-circle-container--expired .smarty-vslm-status-circle {
+ background-color: #427eab; /* Expired color */
+}
+
+.smarty-vslm-status-circle-container--expired::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 10px;
+ width: 80%;
+ height: 80%;
+ border-radius: 50%;
+ background-color: rgba(66, 126, 171, 0.9); /* Slightly lighter blue for pulse */
+ z-index: 1;
+ animation: pulse-expired 1.9s infinite ease-out;
+}
+
+/* Keyframes for pulsing effects */
+@keyframes pulse-active {
+ 0% {
+ transform: scale(1);
+ opacity: 0.8;
+ }
+ 50% {
+ transform: scale(1.8);
+ opacity: 0.4;
+ }
+ 100% {
+ transform: scale(2.2);
+ opacity: 0;
+ }
+}
+
+@keyframes pulse-inactive {
+ 0% {
+ transform: scale(1);
+ opacity: 0.7;
+ }
+ 50% {
+ transform: scale(1.5);
+ opacity: 0.3;
+ }
+ 100% {
+ transform: scale(2);
+ opacity: 0;
+ }
+}
+
+@keyframes pulse-expired {
+ 0% {
+ transform: scale(1);
+ opacity: 0.6;
+ }
+ 50% {
+ transform: scale(1.6);
+ opacity: 0.3;
+ }
+ 100% {
+ transform: scale(2.1);
+ opacity: 0;
+ }
+}
+
+/* Styling for the Copy link */
+.smarty-vslm-copy-key-link {
+ margin-left: 5px;
+ cursor: pointer;
+ color: #0073aa;
+}
+
+.smarty-vslm-copy-key-link:hover {
+ color: #005177;
+}
+
+/* Helpers */
+.active {
+ color: #28a745;
+ font-weight: bold;
+}
+
+.inactive {
+ color: #dc3545;
+ font-weight: bold;
+}
+
+.smarty-json-response,
+.smarty-json-container pre {
+ background: #333333;
+ max-height: 150px;
+ border-radius: 5px;
+ padding: 5px;
+ overflow: auto;
+}
+
+.smarty-json-container pre {
+ color: #d9f2d9;
+ font-family: 'Courier New', Courier, monospace;
+}
+
+.smarty-json-container .success {
+ color: #d9f2d9;
+}
+
+.smarty-json-container .error {
+ color: #f8d7da;
+}
\ No newline at end of file
diff --git a/admin/index.php b/admin/index.php
new file mode 100644
index 0000000..bacffcc
--- /dev/null
+++ b/admin/index.php
@@ -0,0 +1 @@
+
+ Math.random().toString(36).substring(2, 6).toUpperCase()
+ ).join("-");
+ document.getElementById("smarty_vslm_license_key").value = key;
+ }
+
+ function copyLicenseKey(element, licenseKey) {
+ navigator.clipboard.writeText(licenseKey).then(function() {
+ alert('License key copied to clipboard');
+ }, function(err) {
+ console.error('Could not copy text: ', err);
+ });
+ }
+
+ $(document).ready(function($) {
+ $('.smarty-vslm-show-key-link').on('click', function(event) {
+ event.preventDefault();
+ var $wrapper = $(this).closest('.smarty-vslm-license-key-wrapper');
+ $wrapper.find('.smarty-vslm-masked-key').text($wrapper.find('.smarty-vslm-full-key').val());
+ $(this).hide();
+ $wrapper.find('.smarty-vslm-hide-key-link').show();
+ });
+
+ $('.smarty-vslm-hide-key-link').on('click', function(event) {
+ event.preventDefault();
+ var $wrapper = $(this).closest('.smarty-vslm-license-key-wrapper');
+ var maskedKey = $wrapper.find('.smarty-vslm-full-key').val().substring(0, 4) + '-XXXX-XXXX-XXXX';
+ $wrapper.find('.smarty-vslm-masked-key').text(maskedKey);
+ $(this).hide();
+ $wrapper.find('.smarty-vslm-show-key-link').show();
+ });
+ });
+})(jQuery);
\ No newline at end of file
diff --git a/admin/js/smarty-vslm-ajax.js b/admin/js/smarty-vslm-ajax.js
new file mode 100644
index 0000000..4d7c242
--- /dev/null
+++ b/admin/js/smarty-vslm-ajax.js
@@ -0,0 +1,67 @@
+(function ($) {
+ 'use strict';
+
+ /**
+ * All of the code for plugin admin JavaScript source
+ * should reside in this file.
+ *
+ * Note: It has been assumed we will write jQuery code here, so the
+ * $ function reference has been prepared for usage within the scope
+ * of this function.
+ *
+ * This enables us to define handlers, for when the DOM is ready:
+ *
+ * $(function() {
+ *
+ * });
+ *
+ * When the window is loaded:
+ *
+ * $( window ).load(function() {
+ *
+ * });
+ *
+ * ...and/or other possibilities.
+ *
+ * Ideally, it is not considered best practise to attach more than a
+ * single DOM-ready or window-load handler for a particular page.
+ */
+
+ $(document).ready(function ($) {
+ // Handle CK Key generation
+ $('#smarty_vslm_generate_ck_key').on('click', function (e) {
+ e.preventDefault(); // Prevent the default form action
+
+ $.ajax({
+ url: smarty_vslm_ajax.ajax_url,
+ method: 'POST',
+ data: {
+ action: 'smarty_vslm_generate_ck_key'
+ },
+ success: function (response) {
+ if (response.success) {
+ $('#smarty_vslm_ck_key').val(response.data); // Update the CK Key field with the new value
+ }
+ }
+ });
+ });
+
+ // Handle CS Key generation
+ $('#smarty_vslm_generate_cs_key').on('click', function (e) {
+ e.preventDefault(); // Prevent the default form action
+
+ $.ajax({
+ url: smarty_vslm_ajax.ajax_url,
+ method: 'POST',
+ data: {
+ action: 'smarty_vslm_generate_cs_key'
+ },
+ success: function (response) {
+ if (response.success) {
+ $('#smarty_vslm_cs_key').val(response.data); // Update the CS Key field with the new value
+ }
+ }
+ });
+ });
+ });
+})(jQuery);
\ No newline at end of file
diff --git a/admin/js/smarty-vslm-json.js b/admin/js/smarty-vslm-json.js
new file mode 100644
index 0000000..9e1cc2c
--- /dev/null
+++ b/admin/js/smarty-vslm-json.js
@@ -0,0 +1,36 @@
+document.addEventListener('DOMContentLoaded', function () {
+ console.log('DOMContentLoaded triggered');
+ const jsonContainers = document.querySelectorAll('[data-json-endpoint]');
+
+ console.log('Found containers:', jsonContainers);
+
+ jsonContainers.forEach(container => {
+ const endpoint = container.dataset.jsonEndpoint;
+ console.log('Fetching from endpoint:', endpoint);
+
+ fetch(endpoint)
+ .then(response => {
+ if (!response.ok) {
+ if (response.status === 404) {
+ return { status: 'rest_no_route', message: 'REST route not found.' };
+ }
+ throw new Error(`HTTP Error: ${response.status}`);
+ }
+ return response.json();
+ })
+ .then(data => {
+ console.log('Data received:', data);
+ const formattedJson = JSON.stringify(data, null, 2);
+ container.innerHTML = `${formattedJson} `;
+ })
+ .catch(error => {
+ console.error('Error fetching JSON:', error);
+ const errorJson = {
+ status: 'error',
+ message: error.message || 'Unknown error occurred.',
+ };
+ const formattedErrorJson = JSON.stringify(errorJson, null, 2);
+ container.innerHTML = `${formattedErrorJson} `;
+ });
+ });
+});
diff --git a/admin/partials/smarty-vslm-admin-display.php b/admin/partials/smarty-vslm-admin-display.php
new file mode 100644
index 0000000..6d14b16
--- /dev/null
+++ b/admin/partials/smarty-vslm-admin-display.php
@@ -0,0 +1,27 @@
+
+
+
\ No newline at end of file
diff --git a/includes/functions.php b/includes/functions.php
new file mode 100644
index 0000000..79af3ea
--- /dev/null
+++ b/includes/functions.php
@@ -0,0 +1,57 @@
+ 'vslm-licenses',
+ 'meta_key' => '_status',
+ 'meta_value' => $status,
+ 'posts_per_page' => -1,
+ 'fields' => 'ids', // Only retrieve IDs for efficiency
+ ));
+ return $query->found_posts;
+ }
+}
+
+if (!function_exists('_vslm_write_logs')) {
+ /**
+ * Writes logs for the plugin.
+ *
+ * @since 1.0.1
+ * @param string $message Message to be logged.
+ * @param mixed $data Additional data to log, optional.
+ */
+ function _vslm_write_logs($message, $data = null) {
+ $log_entry = '[' . current_time('mysql') . '] ' . $message;
+
+ if (!is_null($data)) {
+ $log_entry .= ' - ' . print_r($data, true);
+ }
+
+ $logs_file = fopen(VSLM_BASE_DIR . DIRECTORY_SEPARATOR . "logs.txt", "a+");
+ fwrite($logs_file, $log_entry . "\n");
+ fclose($logs_file);
+ }
+}
\ No newline at end of file
diff --git a/includes/index.php b/includes/index.php
new file mode 100644
index 0000000..bacffcc
--- /dev/null
+++ b/includes/index.php
@@ -0,0 +1 @@
+plugin_name, plugin_dir_url(__FILE__) . 'css/smarty-vslm-public.css', array(), $this->version, 'all');
+ }
+
+ /**
+ * Register the JavaScript for the public-facing side of the site.
+ *
+ * @since 1.0.1
+ */
+ public function enqueue_scripts() {
+ /**
+ * This function enqueues custom JavaScript for the WooCommerce checkout page.
+ *
+ * An instance of this class should be passed to the run() function
+ * defined in Smarty_Form_Submissions_Loader as all of the hooks are defined
+ * in that particular class.
+ *
+ * The Smarty_Form_Submissions_Loader will then create the relationship
+ * between the defined hooks and the functions defined in this
+ * class.
+ */
+
+ wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/smarty-vslm-public.js', array('jquery'), $this->version, true);
+ }
+}
\ No newline at end of file
diff --git a/public/css/smarty-vslm-public.css b/public/css/smarty-vslm-public.css
new file mode 100644
index 0000000..3397386
--- /dev/null
+++ b/public/css/smarty-vslm-public.css
@@ -0,0 +1,3 @@
+/**
+ * All of the CSS for plugin public functionality should be included in this file.
+ */
\ No newline at end of file
diff --git a/public/js/smarty-vslm-public.js b/public/js/smarty-vslm-public.js
new file mode 100644
index 0000000..8b9f300
--- /dev/null
+++ b/public/js/smarty-vslm-public.js
@@ -0,0 +1,30 @@
+(function ($) {
+ 'use strict';
+
+ /**
+ * All of the code for plugin public JavaScript source
+ * should reside in this file.
+ *
+ * Note: It has been assumed we will write jQuery code here, so the
+ * $ function reference has been prepared for usage within the scope
+ * of this function.
+ *
+ * This enables us to define handlers, for when the DOM is ready:
+ *
+ * $(function() {
+ *
+ * });
+ *
+ * When the window is loaded:
+ *
+ * $( window ).load(function() {
+ *
+ * });
+ *
+ * ...and/or other possibilities.
+ *
+ * Ideally, it is not considered best practise to attach more than a
+ * single DOM-ready or window-load handler for a particular page.
+ */
+
+})(jQuery);
\ No newline at end of file
diff --git a/public/partials/smarty-vslm-public-display.php b/public/partials/smarty-vslm-public-display.php
new file mode 100644
index 0000000..1c9bf12
--- /dev/null
+++ b/public/partials/smarty-vslm-public-display.php
@@ -0,0 +1,14 @@
+
\ No newline at end of file
diff --git a/uninstall.php b/uninstall.php
new file mode 100644
index 0000000..eb44cf5
--- /dev/null
+++ b/uninstall.php
@@ -0,0 +1,28 @@
+
Date: Wed, 20 Nov 2024 15:18:27 +0200
Subject: [PATCH 2/9] Added additional files
---
admin/class-smarty-vslm-admin.php | 8 +-
.../classes/class-smarty-vslm-activator.php | 27 +
.../classes/class-smarty-vslm-deactivator.php | 27 +
includes/classes/class-smarty-vslm-i18n.php | 30 +
includes/classes/class-smarty-vslm-loader.php | 114 ++
.../classes/class-smarty-vslm-locator.php | 224 +++
public/class-smarty-vslm-public.php | 8 +-
smarty-very-simple-license-manager.php | 1466 ++---------------
8 files changed, 541 insertions(+), 1363 deletions(-)
create mode 100644 includes/classes/class-smarty-vslm-activator.php
create mode 100644 includes/classes/class-smarty-vslm-deactivator.php
create mode 100644 includes/classes/class-smarty-vslm-i18n.php
create mode 100644 includes/classes/class-smarty-vslm-loader.php
create mode 100644 includes/classes/class-smarty-vslm-locator.php
diff --git a/admin/class-smarty-vslm-admin.php b/admin/class-smarty-vslm-admin.php
index da7d247..9c5e865 100644
--- a/admin/class-smarty-vslm-admin.php
+++ b/admin/class-smarty-vslm-admin.php
@@ -66,10 +66,10 @@ public function enqueue_styles() {
* This function enqueues custom CSS for the plugin settings in WordPress admin.
*
* An instance of this class should be passed to the run() function
- * defined in Smarty_Form_Submissions_Loader as all of the hooks are defined
+ * defined in Smarty_Vslm_Loader as all of the hooks are defined
* in that particular class.
*
- * The Smarty_Form_Submissions_Loader will then create the relationship
+ * The Smarty_Vslm_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* class.
*/
@@ -87,10 +87,10 @@ public function enqueue_scripts() {
* This function enqueues custom JavaScript for the plugin settings in WordPress admin.
*
* An instance of this class should be passed to the run() function
- * defined in Smarty_Form_Submissions_Loader as all of the hooks are defined
+ * defined in Smarty_Vslm_Loader as all of the hooks are defined
* in that particular class.
*
- * The Smarty_Form_Submissions_Loader will then create the relationship
+ * The Smarty_Vslm_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* class.
*/
diff --git a/includes/classes/class-smarty-vslm-activator.php b/includes/classes/class-smarty-vslm-activator.php
new file mode 100644
index 0000000..a43b66c
--- /dev/null
+++ b/includes/classes/class-smarty-vslm-activator.php
@@ -0,0 +1,27 @@
+actions = array();
+ $this->filters = array();
+ }
+
+ /**
+ * Add a new action to the collection to be registered with WordPress.
+ *
+ * @since 1.0.1
+ * @param string $hook The name of the WordPress action that is being registered.
+ * @param object $component A reference to the instance of the object on which the action is defined.
+ * @param string $callback The name of the function definition on the $component.
+ * @param int $priority Optional. The priority at which the function should be fired. Default is 10.
+ * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1.
+ */
+ public function add_action($hook, $component, $callback, $priority = 10, $accepted_args = 1) {
+ $this->actions = $this->add($this->actions, $hook, $component, $callback, $priority, $accepted_args);
+ }
+
+ /**
+ * Add a new filter to the collection to be registered with WordPress.
+ *
+ * @since 1.0.1
+ * @param string $hook The name of the WordPress filter that is being registered.
+ * @param object $component A reference to the instance of the object on which the filter is defined.
+ * @param string $callback The name of the function definition on the $component.
+ * @param int $priority Optional. The priority at which the function should be fired. Default is 10.
+ * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1
+ */
+ public function add_filter($hook, $component, $callback, $priority = 10, $accepted_args = 1) {
+ $this->filters = $this->add($this->filters, $hook, $component, $callback, $priority, $accepted_args);
+ }
+
+ /**
+ * A utility function that is used to register the actions and hooks into a single collection.
+ *
+ * @since 1.0.1
+ * @access private
+ * @param array $hooks The collection of hooks that is being registered (that is, actions or filters).
+ * @param string $hook The name of the WordPress filter that is being registered.
+ * @param object $component A reference to the instance of the object on which the filter is defined.
+ * @param string $callback The name of the function definition on the $component.
+ * @param int $priority The priority at which the function should be fired.
+ * @param int $accepted_args The number of arguments that should be passed to the $callback.
+ * @return array The collection of actions and filters registered with WordPress.
+ */
+ private function add($hooks, $hook, $component, $callback, $priority, $accepted_args) {
+ $hooks[] = array(
+ 'hook' => $hook,
+ 'component' => $component,
+ 'callback' => $callback,
+ 'priority' => $priority,
+ 'accepted_args' => $accepted_args,
+ );
+
+ return $hooks;
+ }
+
+ /**
+ * Register the filters and actions with WordPress.
+ *
+ * @since 1.0.1
+ */
+ public function run() {
+ foreach ($this->filters as $hook) {
+ add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']);
+ }
+
+ foreach ($this->actions as $hook) {
+ add_action($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']);
+ }
+ }
+}
\ No newline at end of file
diff --git a/includes/classes/class-smarty-vslm-locator.php b/includes/classes/class-smarty-vslm-locator.php
new file mode 100644
index 0000000..ad40cfa
--- /dev/null
+++ b/includes/classes/class-smarty-vslm-locator.php
@@ -0,0 +1,224 @@
+version = VSLM_VERSION;
+ } else {
+ $this->version = '1.0.1';
+ }
+
+ $this->plugin_name = 'smarty-very-simple-license-manager';
+
+ $this->load_dependencies();
+ $this->set_locale();
+ $this->define_admin_hooks();
+ $this->define_public_hooks();
+ }
+
+ /**
+ * Load the required dependencies for this plugin.
+ *
+ * Include the following files that make up the plugin:
+ *
+ * - Smarty_Vslm_Loader. Orchestrates the hooks of the plugin.
+ * - Smarty_Vslm_i18n. Defines internationalization functionality.
+ * - Smarty_Vslm_Admin. Defines all hooks for the admin area.
+ * - Smarty_Vslm_Public. Defines all hooks for the public side of the site.
+ *
+ * Create an instance of the loader which will be used to register the hooks
+ * with WordPress.
+ *
+ * @since 1.0.1
+ * @access private
+ */
+ private function load_dependencies() {
+ /**
+ * The class responsible for orchestrating the actions and filters of the core plugin.
+ */
+ require_once plugin_dir_path(dirname(__FILE__)) . 'classes/class-smarty-vslm-loader.php';
+
+ /**
+ * The class responsible for defining internationalization functionality of the plugin.
+ */
+ require_once plugin_dir_path(dirname(__FILE__)) . 'classes/class-smarty-vslm-i18n.php';
+
+ /**
+ * The class responsible for defining all actions that occur in the admin area.
+ */
+ require_once plugin_dir_path(dirname(__FILE__)) . '../admin/class-smarty-vslm-admin.php';
+
+ /**
+ * The class responsible for Activity & Logging functionality in the admin area.
+ */
+ require_once plugin_dir_path(dirname(__FILE__)) . '../admin/tabs/class-smarty-vslm-activity-logging.php';
+
+ /**
+ * The class responsible for defining all actions that occur in the public-facing side of the site.
+ */
+ require_once plugin_dir_path(dirname(__FILE__)) . '../public/class-smarty-vslm-public.php';
+
+ // Run the loader
+ $this->loader = new Smarty_Vslm_Loader();
+ }
+
+ /**
+ * Define the locale for this plugin for internationalization.
+ *
+ * Uses the Smarty_Vslm_I18n class in order to set the domain and to
+ * register the hook with WordPress.
+ *
+ * @since 1.0.1
+ * @access private
+ */
+ private function set_locale() {
+ $plugin_i18n = new Smarty_Vslm_i18n();
+
+ $this->loader->add_action('plugins_loaded', $plugin_i18n, 'load_plugin_textdomain');
+ }
+
+ /**
+ * Register all of the hooks related to the admin area functionality
+ * of the plugin.
+ *
+ * @since 1.0.1
+ * @access private
+ */
+ private function define_admin_hooks() {
+ $plugin_admin = new Smarty_Vslm_Admin($this->get_plugin_name(), $this->get_version());
+
+ $plugin_activity_logging = new Smarty_Vslm_Activity_Logging();
+
+ $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
+ $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
+ $this->loader->add_action('admin_menu', $plugin_admin, 'fs_add_settings_page');
+ $this->loader->add_action('admin_init', $plugin_admin, 'fs_settings_init');
+ $this->loader->add_action('admin_notices', $plugin_admin, 'fs_success_notice');
+ $this->loader->add_action('admin_notices', $plugin_admin, 'fs_admin_notice');
+ $this->loader->add_action('init', $plugin_admin, 'register_submission_type');
+ $this->loader->add_action('init', $plugin_admin, 'register_subject_taxonomy', 0);
+ $this->loader->add_action('admin_menu', $plugin_admin, 'remove_add_new_submenu');
+ $this->loader->add_action('rest_api_init', $plugin_admin, 'register_submission_routes');
+ $this->loader->add_action('add_meta_boxes', $plugin_admin, 'add_submission_meta_boxes');
+ $this->loader->add_action('save_post', $plugin_admin, 'save_submission_meta_box');
+ $this->loader->add_action('admin_init', $plugin_admin, 'auto_publish_submission_on_edit');
+ $this->loader->add_filter('post_row_actions', $plugin_admin, 'remove_quick_edit', 10, 2);
+ $this->loader->add_filter('manage_submission_posts_columns', $plugin_admin, 'modify_submission_columns');
+ $this->loader->add_action('manage_submission_posts_custom_column', $plugin_admin, 'custom_submission_column', 10, 2);
+ $this->loader->add_filter('manage_edit-submission_sortable_columns', $plugin_admin, 'make_submission_columns_sortable');
+ $this->loader->add_action('pre_get_posts', $plugin_admin, 'exclude_submissions_from_feed');
+ $this->loader->add_action('wp_ajax_delete_comment', $plugin_admin, 'delete_comment_ajax');
+
+ // Register hooks for Activity & Logging
+ $this->loader->add_action('admin_init', $plugin_activity_logging, 'fs_al_settings_init');
+ $this->loader->add_action('wp_ajax_smarty_fs_clear_logs', $plugin_activity_logging, 'fs_handle_ajax_clear_logs');
+ }
+
+ /**
+ * Register all of the hooks related to the public-facing functionality
+ * of the plugin.
+ *
+ * @since 1.0.1
+ * @access private
+ */
+ private function define_public_hooks() {
+ $plugin_public = new Smarty_Vslm_Public($this->get_plugin_name(), $this->get_version());
+
+ $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_styles');
+ $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts');
+ }
+
+ /**
+ * Run the loader to execute all of the hooks with WordPress.
+ *
+ * @since 1.0.0
+ */
+ public function run() {
+ $this->loader->run();
+ }
+
+ /**
+ * The name of the plugin used to uniquely identify it within the context of
+ * WordPress and to define internationalization functionality.
+ *
+ * @since 1.0.1
+ * @return string The name of the plugin.
+ */
+ public function get_plugin_name() {
+ return $this->plugin_name;
+ }
+
+ /**
+ * The reference to the class that orchestrates the hooks with the plugin.
+ *
+ * @since 1.0.1
+ * @return Smarty_Vslm_Loader Orchestrates the hooks of the plugin.
+ */
+ public function get_loader() {
+ return $this->loader;
+ }
+
+ /**
+ * Retrieve the version number of the plugin.
+ *
+ * @since 1.0.1
+ * @return string The version number of the plugin.
+ */
+ public function get_version() {
+ return $this->version;
+ }
+}
\ No newline at end of file
diff --git a/public/class-smarty-vslm-public.php b/public/class-smarty-vslm-public.php
index a54203c..f2f080e 100644
--- a/public/class-smarty-vslm-public.php
+++ b/public/class-smarty-vslm-public.php
@@ -43,10 +43,10 @@ public function enqueue_styles() {
* This function enqueues custom CSS for the WooCommerce checkout page.
*
* An instance of this class should be passed to the run() function
- * defined in Smarty_Form_Submissions_Loader as all of the hooks are defined
+ * defined in Smarty_Vslm_Loader as all of the hooks are defined
* in that particular class.
*
- * The Smarty_Form_Submissions_Loader will then create the relationship
+ * The Smarty_Vslm_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* class.
*/
@@ -64,10 +64,10 @@ public function enqueue_scripts() {
* This function enqueues custom JavaScript for the WooCommerce checkout page.
*
* An instance of this class should be passed to the run() function
- * defined in Smarty_Form_Submissions_Loader as all of the hooks are defined
+ * defined in Smarty_Vslm_Loader as all of the hooks are defined
* in that particular class.
*
- * The Smarty_Form_Submissions_Loader will then create the relationship
+ * The Smarty_Vslm_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* class.
*/
diff --git a/smarty-very-simple-license-manager.php b/smarty-very-simple-license-manager.php
index d86f1f1..ed4d6be 100644
--- a/smarty-very-simple-license-manager.php
+++ b/smarty-very-simple-license-manager.php
@@ -1,14 +1,28 @@
admin_url('admin-ajax.php')
- ));
- }
-
- // Check if we're on any license-related pages (edit, add, or post screen)
- if ($hook === 'edit.php' || $hook === 'post.php' || $hook === 'post-new.php') {
- if ($post_type === 'vslm-licenses' || get_post_type() === 'vslm-licenses') {
- // Enqueue CSS and JS files for license post type
- wp_enqueue_style('vslm-admin-css', plugin_dir_url(__FILE__) . 'css/smarty-vslm-admin.css');
- wp_enqueue_script('vslm-admin-js', plugin_dir_url(__FILE__) . 'js/smarty-vslm-admin.js', array(), null, true);
- wp_enqueue_script('vslm-json-js', plugin_dir_url(__FILE__) . 'js/smarty-vslm-json.js', array(), null, true);
- }
- }
- }
- add_action('admin_enqueue_scripts', 'smarty_vslm_enqueue_admin_scripts');
-}
-
-/////////////////////////////////////////////////////////
-// Dashboard Widget
-/////////////////////////////////////////////////////////
-
-if (!function_exists('smarty_vslm_add_dashboard_widget')) {
- /**
- * Register the custom dashboard widget.
- */
- function smarty_vslm_add_dashboard_widget() {
- wp_add_dashboard_widget(
- 'smarty_vslm_dashboard_widget', // Widget ID
- 'License Manager Overview', // Widget Title
- 'smarty_vslm_dashboard_widget_render' // Callback function to display content
- );
- }
- add_action('wp_dashboard_setup', 'smarty_vslm_add_dashboard_widget');
-}
-
-if (!function_exists('smarty_vslm_dashboard_widget_render')) {
- /**
- * Render the content of the custom dashboard widget with a centered icon and link.
- */
- function smarty_vslm_dashboard_widget_render() {
- // Query for licenses and count statuses
- $total_count = wp_count_posts('vslm-licenses')->publish; // Get total published licenses
- $active_count = smarty_vslm_get_license_count_by_status('active');
- $inactive_count = smarty_vslm_get_license_count_by_status('inactive');
- $expired_count = smarty_vslm_get_license_count_by_status('expired');
-
- // Begin widget content
- echo '';
-
- // Centered icon and link for total licenses
- echo '
';
-
- // Table with detailed license counts
- echo '
';
- echo '';
- echo '';
- echo 'Status ';
- echo 'Count ';
- echo ' ';
- echo ' ';
- echo '';
- echo '';
- echo 'Active Licenses ';
- echo '' . $active_count . ' ';
- echo ' ';
- echo '';
- echo 'Inactive Licenses ';
- echo '' . $inactive_count . ' ';
- echo ' ';
- echo '';
- echo 'Expired Licenses ';
- echo '' . $expired_count . ' ';
- echo ' ';
- echo ' ';
- echo '
';
-
- echo '
';
- }
-}
-
-if (!function_exists('smarty_vslm_get_license_count_by_status')) {
- /**
- * Helper function to get the count of licenses by status.
- *
- * @param string $status The license status to count.
- * @return int The count of licenses with the given status.
- */
- function smarty_vslm_get_license_count_by_status($status) {
- $query = new WP_Query(array(
- 'post_type' => 'vslm-licenses',
- 'meta_key' => '_status',
- 'meta_value' => $status,
- 'posts_per_page' => -1,
- 'fields' => 'ids', // Only retrieve IDs for efficiency
- ));
- return $query->found_posts;
- }
-}
-
-/////////////////////////////////////////////////////////
-// License Custom Post Type and Taxonomy
-/////////////////////////////////////////////////////////
-
-if (!function_exists('smarty_vslm_register_license_post_type')) {
- /**
- * Register the custom post type for managing licenses.
- */
- function smarty_vslm_register_license_post_type() {
- register_post_type('vslm-licenses', array(
- 'labels' => array(
- 'name' => 'Licenses',
- 'singular_name' => 'License',
- 'add_new' => 'Add New License',
- 'add_new_item' => 'Add New License',
- 'edit_item' => 'Edit License',
- 'new_item' => 'New License',
- 'view_item' => 'View License',
- 'search_items' => 'Search Licenses',
- 'not_found' => 'No licenses found',
- 'not_found_in_trash' => 'No licenses found in Trash',
- ),
- 'public' => true,
- 'has_archive' => true,
- 'supports' => array('title'), // Only 'title' support, no editor
- 'menu_icon' => 'dashicons-admin-network',
- 'show_in_rest' => true,
- ));
- }
- add_action('init', 'smarty_vslm_register_license_post_type');
-}
-
-if (!function_exists('smarty_vslm_license_post_updated_messages')) {
- /**
- * Customize the update messages for the License custom post type.
- *
- * @param array $messages Default update messages.
- * @return array Modified update messages.
- */
- function smarty_vslm_license_post_updated_messages($messages) {
- global $post, $post_ID;
-
- $messages['vslm-licenses'] = array(
- 0 => '', // Unused. Messages start from index 1.
- 1 => 'License updated.', // Updated
- 2 => 'Custom field updated.',
- 3 => 'Custom field deleted.',
- 4 => 'License updated.',
- 5 => isset($_GET['revision']) ? sprintf('License restored to revision from %s', wp_post_revision_title((int) $_GET['revision'], false)) : false,
- 6 => 'License published.',
- 7 => 'License saved.',
- 8 => 'License submitted.',
- 9 => sprintf(
- 'License scheduled for: %1$s .',
- date_i18n('M j, Y @ G:i', strtotime($post->post_date))
- ),
- 10 => 'License draft updated.'
- );
-
- return $messages;
- }
- add_filter('post_updated_messages', 'smarty_vslm_license_post_updated_messages');
-}
-
-/////////////////////////////////////////////////////////
-// Custom Meta Boxes on Add/Edit Page
-/////////////////////////////////////////////////////////
-
-if (!function_exists('smarty_vslm_add_license_meta_boxes')) {
- /**
- * Add custom meta boxes for license details in the license edit screen, with status dot after the title.
- */
- function smarty_vslm_add_license_meta_boxes() {
- add_meta_box(
- 'license_details',
- smarty_vslm_license_meta_box_title(), // Set title with dynamic status dot
- 'smarty_vslm_license_details_callback',
- 'vslm-licenses',
- 'normal',
- 'default'
- );
- }
- add_action('add_meta_boxes', 'smarty_vslm_add_license_meta_boxes');
-}
-
-if (!function_exists('smarty_vslm_license_meta_box_title')) {
- /**
- * Generate the title for the license meta box with a colored status dot.
- *
- * @return string The meta box title with a status dot.
- */
- function smarty_vslm_license_meta_box_title() {
- global $post;
-
- // Get the license status
- $status = get_post_meta($post->ID, '_status', true) ?: 'new';
-
- // Determine the color for the dot based on status
- $dot_color = $status === 'active' ? '#28a745' : '#dc3545'; // Green if active, red if inactive
-
- // Set class based on status to handle the pulse effect only for 'active'
- $status_class = 'smarty-vslm-status-circle-container--' . $status;
-
- // Return the title with a container for the pulsing effect
- return 'LICENSE ' . '#' . $post->ID . ' ';
- }
-}
-
-if (!function_exists('smarty_vslm_add_json_response_meta_box')) {
- /**
- * Add a meta box for displaying the JSON response from the plugin status endpoint.
- */
- function smarty_vslm_add_json_response_meta_box() {
- add_meta_box(
- 'smarty_vslm_json_response',
- __('Product Status (JSON)', 'smarty-very-simple-license-manager'),
- 'smarty_vslm_json_response_meta_box_callback',
- 'vslm-licenses',
- 'normal',
- 'default'
- );
- }
- add_action('add_meta_boxes', 'smarty_vslm_add_json_response_meta_box');
-}
-
-if (!function_exists('smarty_vslm_json_response_meta_box_callback')) {
- /**
- * Callback for the Plugin Status JSON Response meta box.
- *
- * @param WP_Post $post The current post object.
- */
- function smarty_vslm_json_response_meta_box_callback($post) {
- // Retrieve meta data
- $multi_domain = get_post_meta($post->ID, '_multi_domain', true);
- $usage_url = get_post_meta($post->ID, '_usage_url', true);
- $usage_urls = get_post_meta($post->ID, '_usage_urls', true) ?: [];
- $plugin_name = get_post_meta($post->ID, '_plugin_name', true);
- $json_response_info = __('This is the product status JSON response from client site.', 'smarty-very-simple-license-manager');
-
- // Validate plugin name
- if (empty($plugin_name)) {
- echo '' . __('Plugin Name is missing.', 'smarty-very-simple-license-manager') . '
';
- return;
- }
-
- // Handle single-domain usage
- if ($multi_domain !== '1') {
- if (empty($usage_url)) {
- echo '' . __('Usage URL is missing for single-domain usage.', 'smarty-very-simple-license-manager') . '
';
- return;
- }
-
- $endpoint = trailingslashit(esc_url($usage_url)) . 'wp-json/' . sanitize_title($plugin_name) . '/v1/plugin-status';
- ?>
-
-
-
-
-
-
-
- ' . __('No usage URLs available for multi-domain usage.', 'smarty-very-simple-license-manager') . '';
- return;
- } ?>
-
-
-
-
-
-
-
- ' . __('Invalid or missing URL in multi-domain configuration.', 'smarty-very-simple-license-manager') . '';
- }
- }
- }
- }
-}
-
-if (!function_exists('smarty_vslm_license_details_callback')) {
- /**
- * Callback function to render the license details meta box.
- *
- * @param WP_Post $post The current post object.
- */
- function smarty_vslm_license_details_callback($post) {
- // Retrieve existing values from the post meta, if available
- $product_terms = get_the_terms($post->ID, 'product'); // Get assigned product terms
- $license_key = get_post_meta($post->ID, '_license_key', true);
- $client_name = get_post_meta($post->ID, '_client_name', true);
- $client_email = get_post_meta($post->ID, '_client_email', true);
- $purchase_date = get_post_meta($post->ID, '_purchase_date', true);
- $expiration_date = get_post_meta($post->ID, '_expiration_date', true);
- $status = get_post_meta($post->ID, '_status', true);
- $usage_url = get_post_meta($post->ID, '_usage_url', true); // Retrieve the usage URL
- $usage_urls = get_post_meta($post->ID, '_usage_urls', true) ?: array();
- $multi_domain = get_post_meta($post->ID, '_multi_domain', true);
- $wp_version = get_post_meta($post->ID, '_wp_version', true); // Retrieve the WordPress version
-
- // Retrieve plugin information
- $plugin_name = get_post_meta($post->ID, '_plugin_name', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
- $plugin_version = get_post_meta($post->ID, '_plugin_version', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
-
- // Retrieve additional server information
- $web_server = get_post_meta($post->ID, '_web_server', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
- $server_ip = get_post_meta($post->ID, '_server_ip', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
- $php_version = get_post_meta($post->ID, '_php_version', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
-
- // Retrieve additional user info
- $user_ip = get_post_meta($post->ID, '_user_ip', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
- $browser = get_post_meta($post->ID, '_browser', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
- $device_type = get_post_meta($post->ID, '_device_type', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
- $os = get_post_meta($post->ID, '_os', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager')); ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- post_type === 'vslm-licenses') {
- // Verify nonce for security
- if (!isset($_POST['smarty_vslm_license_nonce']) || !wp_verify_nonce($_POST['smarty_vslm_license_nonce'], 'smarty_vslm_save_license_meta')) {
- return $post_id;
- }
-
- // Save multi-domain setting
- $multi_domain = isset($_POST['multi_domain']) ? '1' : '0';
- update_post_meta($post_id, '_multi_domain', $multi_domain);
-
- if ($multi_domain !== '1') {
- // Single-domain usage
- if (isset($_POST['usage_url'])) {
- $usage_url = esc_url_raw($_POST['usage_url']);
- update_post_meta($post_id, '_usage_url', $usage_url);
- }
- // Delete the multi-domain usage URLs
- delete_post_meta($post_id, '_usage_urls');
- } else {
- // Multi-domain usage
- // Delete the single usage URL meta
- delete_post_meta($post_id, '_usage_url');
- // The _usage_urls meta will be managed via the REST API
- }
-
- // Auto-generate license key if none exists
- $license_key = sanitize_text_field($_POST['license_key']);
- if (empty($license_key)) {
- $license_key = strtoupper(wp_generate_password(16, false, false));
- }
- update_post_meta($post_id, '_license_key', $license_key);
-
- // Update other fields
- update_post_meta($post_id, '_client_name', sanitize_text_field($_POST['client_name']));
- update_post_meta($post_id, '_client_email', sanitize_email($_POST['client_email']));
- update_post_meta($post_id, '_purchase_date', sanitize_text_field($_POST['purchase_date']));
- update_post_meta($post_id, '_expiration_date', sanitize_text_field($_POST['expiration_date']));
- update_post_meta($post_id, '_status', sanitize_text_field($_POST['status']));
-
- if (isset($_POST['product'])) {
- wp_set_post_terms($post_id, array(intval($_POST['product'])), 'product');
- }
- }
- }
- add_action('save_post', 'smarty_vslm_save_license_meta', 10, 2);
-}
-
-if (!function_exists('smarty_vslm_set_numeric_slug')) {
- /**
- * Set a numeric slug for licenses instead of a title-based slug.
- *
- * @param array $data The array of sanitized post data.
- * @param array $postarr The array of unsanitized post data.
- * @return array Modified post data with a numeric slug.
- */
- function smarty_vslm_set_numeric_slug($data, $postarr) {
- if ($data['post_type'] === 'vslm-licenses' && $data['post_status'] === 'publish') {
- // Generate a unique numeric slug based on the post ID
- if (empty($postarr['ID'])) {
- // If it's a new post, use the current timestamp
- $numeric_slug = time();
- } else {
- // For existing posts, use the post ID
- $numeric_slug = $postarr['ID'];
- }
- $data['post_name'] = $numeric_slug; // Set the slug to be the numeric value
- }
- return $data;
- }
- add_filter('wp_insert_post_data', 'smarty_vslm_set_numeric_slug', 10, 2);
-}
-
-if (!function_exists('smarty_vslm_register_product_taxonomy')) {
- /**
- * Register the 'Products' taxonomy for licenses.
- */
- function smarty_vslm_register_product_taxonomy() {
- register_taxonomy('product', 'vslm-licenses', array(
- 'labels' => array(
- 'name' => esc_html(__('Products', 'smarty-very-simple-license-manager')),
- 'singular_name' => esc_html(__('Product', 'smarty-very-simple-license-manager')),
- 'search_items' => esc_html(__('Search Products', 'smarty-very-simple-license-manager')),
- 'all_items' => esc_html(__('All Products', 'smarty-very-simple-license-manager')),
- 'edit_item' => esc_html(__('Edit Product', 'smarty-very-simple-license-manager')),
- 'view_item' => esc_html(__('View Product', 'smarty-very-simple-license-manager')),
- 'add_new_item' => esc_html(__('Add New Product', 'smarty-very-simple-license-manager')),
- 'new_item_name' => esc_html(__('New Product Name', 'smarty-very-simple-license-manager')),
- 'menu_name' => esc_html(__('Products', 'smarty-very-simple-license-manager')),
- ),
- 'hierarchical' => true,
- 'show_ui' => true,
- 'show_in_rest' => true,
- 'query_var' => true,
- 'rewrite' => array('slug' => 'product'),
- ));
- }
- add_action('init', 'smarty_vslm_register_product_taxonomy');
-}
-
-/////////////////////////////////////////////////////////
-// Admin Bar Styling
-/////////////////////////////////////////////////////////
-
-if (!function_exists('smarty_vslm_remove_admin_bar_view_posts')) {
- /**
- * Remove the "View Posts" link from the admin bar for the License post type.
- *
- * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar instance.
- */
- function smarty_vslm_remove_admin_bar_view_posts($wp_admin_bar) {
- // Check if we're in the License custom post type or editing it
- global $post_type, $post;
-
- // Only proceed if we're in the admin area and dealing with the "vslm-licenses" post type
- if (is_admin() && ($post_type === 'vslm-licenses' || (isset($post) && $post->post_type === 'vslm-licenses'))) {
- // Remove any "View Posts" or similar links in the admin bar related to this post type
- $wp_admin_bar->remove_node('edit'); // Standard "Edit" node ID
- $wp_admin_bar->remove_node('view'); // Commonly used for "View" link in admin bar
- $wp_admin_bar->remove_node('archive'); // Possible ID for "Archive" links
- $wp_admin_bar->remove_menu('view'); // Extra attempt in case `remove_node` does not cover all cases
- }
- }
- add_action('admin_bar_menu', 'smarty_vslm_remove_admin_bar_view_posts', 999);
-}
-
-/////////////////////////////////////////////////////////
-// Custom Columns in Licenses List
-/////////////////////////////////////////////////////////
-
-if (!function_exists('smarty_vslm_remove_view_link')) {
- /**
- * Remove the "View" link from the row actions for licenses in the admin list.
- *
- * @param array $actions The current row actions.
- * @param WP_Post $post The current post object.
- * @return array Modified row actions without the "View" link.
- */
- function smarty_vslm_remove_view_link($actions, $post) {
- // Check if the current post type is "license"
- if ($post->post_type === 'vslm-licenses') {
- unset($actions['view']); // Remove the "View" action
- }
- return $actions;
- }
- add_filter('post_row_actions', 'smarty_vslm_remove_view_link', 10, 2);
+// Check if VSLM_VERSION is not already defined
+if (!defined('VSLM_VERSION')) {
+ /**
+ * Current plugin version.
+ * For the versioning of the plugin is used SemVer - https://semver.org
+ */
+ define('VSLM_VERSION', '1.0.1');
}
-if (!function_exists('smarty_vslm_remove_quick_edit')) {
- /**
- * Remove "Quick Edit" from the row actions in the licenses list.
- *
- * @param array $actions The current row actions.
- * @param WP_Post $post The current post object.
- * @return array Modified row actions without the "Quick Edit" option.
- */
- function smarty_vslm_remove_quick_edit($actions, $post) {
- if ($post->post_type === 'vslm-licenses') {
- unset($actions['inline hide-if-no-js']); // Remove the "Quick Edit" action
- }
- return $actions;
- }
- add_filter('post_row_actions', 'smarty_vslm_remove_quick_edit', 10, 2);
-}
-
-if (!function_exists('smarty_vslm_add_license_columns')) {
- /**
- * Add custom columns for License Key, Status, Expiration Date, and User Email in the licenses list table.
- *
- * @param array $columns The current list of columns.
- * @return array Modified list of columns.
- */
- function smarty_vslm_add_license_columns($columns) {
- unset($columns['title']);
- // Define the new columns order, placing "Product" first
- $new_columns = array(
- 'product' => esc_html(__('Product', 'smarty-very-simple-license-manager')),
- 'product_version' => esc_html(__('Version', 'smarty-very-simple-license-manager')),
- 'license_key' => esc_html(__('License Key', 'smarty-very-simple-license-manager')),
- 'purchase_date' => esc_html(__('Purchase Date', 'smarty-very-simple-license-manager')),
- 'expiration_date' => esc_html(__('Expiration Date', 'smarty-very-simple-license-manager')),
- 'client_name' => esc_html(__('Client Name', 'smarty-very-simple-license-manager')),
- 'client_email' => esc_html(__('Client Email', 'smarty-very-simple-license-manager')),
- 'usage_urls' => esc_html(__('Usage URL(s)', 'smarty-very-simple-license-manager')),
- 'license_status' => esc_html(__('Status', 'smarty-very-simple-license-manager')),
- );
-
- return $new_columns;
- }
- add_filter('manage_vslm-licenses_posts_columns', 'smarty_vslm_add_license_columns');
+// Check if VSLM_BASE_DIR is not already defined
+if (!defined('VSLM_BASE_DIR')) {
+ /**
+ * This constant is used as a base path for including other files or referencing directories within the plugin.
+ */
+ define('VSLM_BASE_DIR', dirname(__FILE__));
}
-if (!function_exists('smarty_vslm_fill_license_columns')) {
- /**
- * Populate the custom columns for License Key, Status, Expiration Date, and User Email.
- *
- * @param string $column The name of the column.
- * @param int $post_id The ID of the current post.
- */
- function smarty_vslm_fill_license_columns($column, $post_id) {
- if ($column === 'license_key') {
- $license_key = get_post_meta($post_id, '_license_key', true);
- $masked_key = substr($license_key, 0, 4) . '-XXXX-XXXX-XXXX';
-
- echo '';
-
- // Masked key
- echo '
' . esc_html($masked_key) . ' ';
- echo '
';
-
- // Show/Hide and Copy links
- echo '
';
- echo '
Show ';
- echo '
Hide ';
- echo '
| ';
- echo '
Copy ';
- echo '
';
-
- echo '
';
- } elseif ($column === 'license_status') {
- $status = get_post_meta($post_id, '_status', true);
- $status_text = ucfirst($status);
-
- if ($status === 'active') {
- echo '' . $status_text . ' ';
- } elseif ($status === 'inactive') {
- echo '' . $status_text . ' ';
- } elseif ($status === 'expired') {
- echo '' . $status_text . ' ';
- } else {
- echo '' . $status_text . ' ';
- }
- } elseif ($column === 'purchase_date') {
- $purchase_date = get_post_meta($post_id, '_purchase_date', true);
- $formatted_purchase_date = date('Y/m/d', strtotime($purchase_date)); // Format as YYYY/MM/DD
- echo esc_html($formatted_purchase_date);
- } elseif ($column === 'expiration_date') {
- $expiration_date = get_post_meta($post_id, '_expiration_date', true);
- $formatted_expiration_date = date('Y/m/d', strtotime($expiration_date));
- echo esc_html($formatted_expiration_date);
-
- // Calculate days left if the expiration date is valid
- $current_date = new DateTime();
- $expiration = new DateTime($expiration_date);
- $interval = $current_date->diff($expiration);
-
- if ($interval->invert === 0) { // Not expired yet
- echo '' . $interval->days . ' days left ';
- } else {
- echo '0 days left ';
- }
- } elseif ($column === 'client_name') {
- echo esc_html(get_post_meta($post_id, '_client_name', true));
- } elseif ($column === 'client_email') {
- echo esc_html(get_post_meta($post_id, '_client_email', true));
- } elseif ($column === 'usage_urls') {
- $multi_domain = get_post_meta($post_id, '_multi_domain', true);
- if ($multi_domain === '1') {
- $usage_urls = get_post_meta($post_id, '_usage_urls', true) ?: array();
- if (!empty($usage_urls)) {
- foreach ($usage_urls as $url_data) {
- if (is_array($url_data) && isset($url_data['site_url'])) {
- echo '' . esc_html($url_data['site_url']) . '
';
- }
- }
- } else {
- echo '—';
- }
- } else {
- $usage_url = get_post_meta($post_id, '_usage_url', true);
- echo $usage_url ? esc_url($usage_url) : '—';
- }
- } elseif ($column === 'product') {
- // Display the product name(s)
- $product_terms = get_the_terms($post_id, 'product');
- if (!empty($product_terms) && !is_wp_error($product_terms)) {
- $product_names = wp_list_pluck($product_terms, 'name');
- echo '' . esc_html(implode(', ', $product_names)) . ' ';
- } else {
- echo '—'; // Display a dash if no product is assigned
- }
- } elseif ($column === 'product_version') {
- // Retrieve the product version from the post meta
- $product_version = get_post_meta($post_id, '_plugin_version', true);
-
- // Display the product version or a placeholder if not available
- echo $product_version ? esc_html($product_version) : esc_html(__('Not recorded', 'smarty-very-simple-license-manager'));
- }
- }
- add_action('manage_vslm-licenses_posts_custom_column', 'smarty_vslm_fill_license_columns', 10, 2);
-}
-
-if (!function_exists('smarty_vslm_custom_admin_styles')) {
- function smarty_vslm_custom_admin_styles() {
- global $post_type;
-
- if ('vslm-licenses' === $post_type) {
- echo '';
- }
- }
- add_action('admin_head', 'smarty_vslm_custom_admin_styles');
-}
-
-/////////////////////////////////////////////////////////
-// License Status Sorting
-/////////////////////////////////////////////////////////
-
-if (!function_exists('smarty_vslm_sortable_license_columns')) {
- /**
- * Define sortable columns for License Key and Status.
- *
- * @param array $columns The current list of sortable columns.
- * @return array Modified list of sortable columns.
- */
- function smarty_vslm_sortable_license_columns($columns) {
- $columns['license_key'] = 'license_key';
- $columns['license_status'] = 'license_status';
- return $columns;
- }
- add_filter('manage_edit-vslm-licenses_sortable_columns', 'smarty_vslm_sortable_license_columns');
-}
-
-if (!function_exists('smarty_vslm_orderby_license_columns')) {
- /**
- * Modify the query to handle sorting by license key and status.
- *
- * @param WP_Query $query The current WP_Query instance.
- */
- function smarty_vslm_orderby_license_columns($query) {
- if (!is_admin()) return;
- if ($query->get('orderby') === 'license_key') {
- $query->set('meta_key', '_license_key');
- $query->set('orderby', 'meta_value');
- }
- if ($query->get('orderby') === 'license_status') {
- $query->set('meta_key', '_status');
- $query->set('orderby', 'meta_value');
- }
- }
- add_action('pre_get_posts', 'smarty_vslm_orderby_license_columns');
-}
-
-/////////////////////////////////////////////////////////
-// Cron Job for Expired License Check
-/////////////////////////////////////////////////////////
-
-if (!function_exists('smarty_vslm_schedule_cron_job')) {
- /**
- * Schedule a daily cron job to check for expired licenses.
- */
- function smarty_vslm_schedule_cron_job() {
- if (!wp_next_scheduled('smarty_vslm_license_check')) {
- wp_schedule_event(time(), 'daily', 'smarty_vslm_license_check');
- }
- }
- add_action('wp', 'smarty_vslm_schedule_cron_job');
-}
-
-if (!function_exists('smarty_vslm_check_expired_licenses')) {
- /**
- * Cron job function to mark expired licenses as expired.
- */
- function smarty_vslm_check_expired_licenses() {
- $licenses = get_posts(array('post_type' => 'vslm-licenses', 'posts_per_page' => -1));
- foreach ($licenses as $license) {
- $expiration_date = get_post_meta($license->ID, '_expiration_date', true);
- if (strtotime($expiration_date) < time()) {
- update_post_meta($license->ID, '_status', 'expired');
- }
- }
- }
- add_action('smarty_vslm_license_check', 'smarty_vslm_check_expired_licenses');
-}
-
-/////////////////////////////////////////////////////////
-// Settings Page for API Key Management
-/////////////////////////////////////////////////////////
-
-if (!function_exists('smarty_vslm_settings_page')) {
- /**
- * Create settings page for API key management.
- */
- function smarty_vslm_settings_page() {
- add_options_page(
- __('License Manager | Settings', 'smarty-very-simple-license-manager'),
- __('License Manager', 'smarty-very-simple-license-manager'),
- 'manage_options',
- 'smarty-vslm-settings',
- 'smarty_vslm_settings_page_html'
- );
- }
- add_action('admin_menu', 'smarty_vslm_settings_page');
-}
-
-if (!function_exists('smarty_vslm_settings_page_html')) {
- /**
- * Settings page HTML.
- */
- function smarty_vslm_settings_page_html() {
- // Check user capabilities
- if (!current_user_can('manage_options')) {
- return;
- }
-
- // HTML
- ?>
-
-
-
-
-
-
-
-
-
-
'GET',
- 'callback' => 'smarty_vslm_check_license_status',
- 'permission_callback' => 'smarty_vslm_basic_auth_permission_check',
- ));
- }
- add_action('rest_api_init', 'smarty_vslm_register_license_status_endpoint');
+/**
+ * The Consumer Secret for API authentication.
+ *
+ * Used in combination with the Consumer Key to secure API requests.
+ * This key should remain unchanged to ensure consistent and secure access to the API.
+ *
+ * @since 1.0.1
+ * @access public
+ */
+if (!defined('CS_KEY')) { // Do not change!
+ define('CS_KEY', base64_decode('Y3NfNWJlNDc4ZWVkMDEzNDIzZGJmN2RhYzBjNzBhODczNDZmZjhiM2UyZA=='));
}
-if (!function_exists('smarty_vslm_basic_auth_permission_check')) {
- /**
- * Permission callback for Basic Auth.
- *
- * @return bool True if authentication is successful, false otherwise.
- */
- function smarty_vslm_basic_auth_permission_check() {
- $headers = getallheaders();
- if (isset($headers['Authorization'])) {
- $auth_header = $headers['Authorization'];
- if (strpos($auth_header, 'Basic ') === 0) {
- $encoded_credentials = substr($auth_header, 6);
- $decoded_credentials = base64_decode($encoded_credentials);
- list($provided_ck_key, $provided_cs_key) = explode(':', $decoded_credentials, 2);
-
- // Retrieve the stored keys
- $stored_ck_key = get_option('smarty_vslm_ck_key');
- $stored_cs_key = get_option('smarty_vslm_cs_key');
-
- // Validate credentials
- if ($provided_ck_key === $stored_ck_key && $provided_cs_key === $stored_cs_key) {
- return true;
- }
- }
- }
- return false;
- }
+/**
+ * The code that runs during plugin activation.
+ * This action is documented in includes/classes/class-smarty-vslm-activator.php
+ *
+ * @since 1.0.1
+ */
+function activate_vslm() {
+ require_once plugin_dir_path(__FILE__) . 'includes/classes/class-smarty-vslm-activator.php';
+ Smarty_Vslm_Activator::activate();
}
-if (!function_exists('smarty_vslm_check_license_status')) {
- /**
- * Callback for the REST API endpoint to check license status.
- *
- * @param WP_REST_Request $request The REST request object.
- * @return WP_REST_Response The REST response with license status, expiration date, usage URL, and WordPress version.
- */
- function smarty_vslm_check_license_status(WP_REST_Request $request) {
- $license_key = $request->get_param('license_key');
- $site_url = $request->get_param('site_url');
- $wp_version = $request->get_param('wp_version');
- $web_server = $request->get_param('web_server');
- $server_ip = $request->get_param('server_ip');
- $php_version = $request->get_param('php_version');
- $plugin_name = $request->get_param('plugin_name');
- $plugin_version = $request->get_param('plugin_version');
- $user_ip = $request->get_param('user_ip');
- $browser = $request->get_param('browser');
- $device_type = $request->get_param('device_type');
- $os = $request->get_param('os');
-
- // Find the license by key
- $license_posts = get_posts(array(
- 'post_type' => 'vslm-licenses',
- 'meta_query' => array(
- array(
- 'key' => '_license_key',
- 'value' => $license_key,
- 'compare' => '='
- )
- )
- ));
-
- if (empty($license_posts)) {
- return new WP_REST_Response([
- 'status' => 'rest_no_route',
- 'message' => 'The requested route does not exist.',
- ], 404);
- }
-
- $license_id = $license_posts[0]->ID;
- $multi_domain = get_post_meta($license_id, '_multi_domain', true);
-
- if (!empty($site_url) && filter_var($site_url, FILTER_VALIDATE_URL)) {
- if ($multi_domain === '1') {
- // Multi-domain handling
- $usage_urls = get_post_meta($license_id, '_usage_urls', true) ?: [];
-
- // Check if the URL already exists
- $existing_key = array_search($site_url, array_column($usage_urls, 'site_url'));
-
- $url_data = [
- 'site_url' => $site_url,
- 'wp_version' => $wp_version,
- 'plugin_version' => $plugin_version,
- 'web_server' => $web_server,
- 'server_ip' => $server_ip,
- 'php_version' => $php_version,
- 'user_ip' => $user_ip,
- 'browser' => $browser,
- 'device_type' => $device_type,
- 'os' => $os,
- ];
-
- if ($existing_key !== false) {
- // Update existing entry
- $usage_urls[$existing_key] = $url_data;
- } else {
- // Add new entry
- $usage_urls[] = $url_data;
- }
-
- update_post_meta($license_id, '_usage_urls', $usage_urls);
- } else {
- // Single-domain usage
- $existing_usage_url = get_post_meta($license_id, '_usage_url', true);
-
- if (empty($existing_usage_url) || $existing_usage_url === $site_url) {
- update_post_meta($license_id, '_usage_url', esc_url_raw($site_url));
- } else {
- return new WP_REST_Response([
- 'status' => 'error',
- 'message' => 'License already activated on another domain.',
- ], 403);
- }
- }
- }
-
- if (!empty($wp_version)) {
- update_post_meta($license_id, '_wp_version', sanitize_text_field($wp_version));
- }
-
- if (!empty($plugin_name)) {
- update_post_meta($license_id, '_plugin_name', sanitize_text_field($plugin_name));
- }
-
- if (!empty($plugin_version)) {
- update_post_meta($license_id, '_plugin_version', sanitize_text_field($plugin_version));
- }
-
- if (!empty($web_server)) {
- update_post_meta($license_id, '_web_server', sanitize_text_field($web_server));
- }
-
- if (!empty($server_ip)) {
- update_post_meta($license_id, '_server_ip', sanitize_text_field($server_ip));
- }
-
- if (!empty($php_version)) {
- update_post_meta($license_id, '_php_version', sanitize_text_field($php_version));
- }
-
- if (!empty($user_ip)) {
- update_post_meta($license_id, '_user_ip', sanitize_text_field($user_ip));
- }
-
- if (!empty($browser)) {
- update_post_meta($license_id, '_browser', sanitize_text_field($browser));
- }
-
- if (!empty($device_type)) {
- update_post_meta($license_id, '_device_type', sanitize_text_field($device_type));
- }
-
- if (!empty($os)) {
- update_post_meta($license_id, '_os', sanitize_text_field($os));
- }
-
- // Retrieve license status, expiration date, usage URL, WP version, Web server and Server IP
- $license_status = get_post_meta($license_id, '_status', true);
- $expiration_date = get_post_meta($license_id, '_expiration_date', true);
- $stored_wp_version = get_post_meta($license_id, '_wp_version', true);
- $stored_web_server = get_post_meta($license_id, '_web_server', true);
- $stored_server_ip = get_post_meta($license_id, '_server_ip', true);
- $stored_php_version = get_post_meta($license_id, '_php_version', true);
- $stored_plugin_name = get_post_meta($license_id, '_plugin_name', true);
- $stored_plugin_version = get_post_meta($license_id, '_plugin_version', true);
- $stored_user_ip = get_post_meta($license_id, '_user_ip', true);
- $stored_browser = get_post_meta($license_id, '_browser', true);
- $stored_device_type = get_post_meta($license_id, '_device_type', true);
- $stored_os = get_post_meta($license_id, '_os', true);
-
- $response_data = array(
- 'status' => $license_status,
- 'expiration_date' => $expiration_date,
- 'multi_domain' => $multi_domain === '1',
- 'wp_version' => $stored_wp_version,
- 'web_server' => $stored_web_server,
- 'server_ip' => $stored_server_ip,
- 'php_version' => $stored_php_version,
- 'plugin_name' => $stored_plugin_name,
- 'plugin_version' => $stored_plugin_version,
- 'user_ip' => $stored_user_ip,
- 'browser' => $stored_browser,
- 'device_type' => $stored_device_type,
- 'os' => $stored_os,
- );
-
- if ($multi_domain === '1') {
- $response_data['usage_urls'] = get_post_meta($license_id, '_usage_urls', true) ?: array();
- } else {
- $response_data['usage_url'] = get_post_meta($license_id, '_usage_url', true);
- }
-
- return new WP_REST_Response([
- 'status' => $license_status ? $license_status : 'inactive',
- 'expiration_date' => $expiration_date,
- 'message' => 'License status retrieved successfully.',
- ], 200);
- }
+/**
+ * The code that runs during plugin deactivation.
+ * This action is documented in includes/classes/class-smarty-vslm-deactivator.php
+ *
+ * @since 1.0.1
+ */
+function deactivate_vslm() {
+ require_once plugin_dir_path(__FILE__) . 'includes/classes/class-smarty-vslm-deactivator.php';
+ Smarty_Vslm_Deactivator::deactivate();
}
-if (!function_exists('smarty_vslm_license_sortable_columns')) {
- /**
- * Make the Status column sortable in the admin.
- *
- * @param array $columns List of sortable columns.
- * @return array Updated sortable columns.
- */
- function smarty_vslm_license_sortable_columns($columns) {
- $columns['license_status'] = 'license_status';
- return $columns;
- }
- add_filter('manage_edit-license_sortable_columns', 'smarty_vslm_license_sortable_columns');
-}
+register_activation_hook(__FILE__, 'activate_vslm');
+register_deactivation_hook(__FILE__, 'deactivate_vslm');
-if (!function_exists('smarty_vslm_license_orderby_status')) {
- /**
- * Sort the licenses by status in the admin.
- *
- * @param WP_Query $query The current WP_Query object.
- */
- function smarty_vslm_license_orderby_status($query) {
- if (!is_admin()) {
- return;
- }
+/**
+ * The core plugin class that is used to define internationalization,
+ * admin-specific hooks, and public-facing site hooks.
+ */
+require plugin_dir_path(__FILE__) . 'includes/classes/class-smarty-vslm-locator.php';
- $orderby = $query->get('orderby');
- if ('license_status' === $orderby) {
- $query->set('meta_key', '_status');
- $query->set('orderby', 'meta_value');
- }
- }
- add_action('pre_get_posts', 'smarty_vslm_license_orderby_status');
-}
+/**
+ * The plugin functions file that is used to define general functions, shortcodes etc.
+ */
+require plugin_dir_path(__FILE__) . 'includes/functions.php';
-if (!function_exists('smarty_vslm_generate_ck_key')) {
- /**
- * AJAX handler to generate a CK key.
- */
- function smarty_vslm_generate_ck_key() {
- $ck_key = 'ck_' . bin2hex(random_bytes(20)); // Generate a CK key
- update_option('smarty_vslm_ck_key', $ck_key);
- wp_send_json_success($ck_key);
- }
- add_action('wp_ajax_generate_ck_key', 'smarty_vslm_generate_ck_key');
+/**
+ * Begins execution of the plugin.
+ *
+ * Since everything within the plugin is registered via hooks,
+ * then kicking off the plugin from this point in the file does
+ * not affect the page life cycle.
+ *
+ * @since 1.0.1
+ */
+function run_vslm() {
+ $plugin = new Smarty_Vslm_Locator();
+ $plugin->run();
}
-if (!function_exists('smarty_vslm_generate_cs_key')) {
- /**
- * AJAX handler to generate a CS key.
- */
- function smarty_vslm_generate_cs_key() {
- $cs_key = 'cs_' . bin2hex(random_bytes(20)); // Generate a CS key
- update_option('smarty_vslm_cs_key', $cs_key);
- wp_send_json_success($cs_key);
- }
- add_action('wp_ajax_generate_cs_key', 'smarty_vslm_generate_cs_key');
-}
+run_vslm();
\ No newline at end of file
From a075bc892917ca4587f95c2edadae7815a077c31 Mon Sep 17 00:00:00 2001
From: Martin Nestorov
Date: Sun, 24 Nov 2024 21:10:57 +0200
Subject: [PATCH 3/9] Code refactoring and adding of missing classes
---
admin/class-smarty-vslm-admin.php | 124 ++++--------
.../class-smarty-vslm-activity-logging.php | 188 ++++++++++++++++++
.../classes/class-smarty-vslm-locator.php | 44 ++--
3 files changed, 250 insertions(+), 106 deletions(-)
create mode 100644 admin/tabs/class-smarty-vslm-activity-logging.php
diff --git a/admin/class-smarty-vslm-admin.php b/admin/class-smarty-vslm-admin.php
index 9c5e865..d8bedcc 100644
--- a/admin/class-smarty-vslm-admin.php
+++ b/admin/class-smarty-vslm-admin.php
@@ -130,7 +130,6 @@ public function vslm_add_dashboard_widget() {
'smarty_vslm_dashboard_widget_render' // Callback function to display content
);
}
- add_action('wp_dashboard_setup', 'smarty_vslm_add_dashboard_widget');
/**
* Render the content of the custom dashboard widget with a centered icon and link.
@@ -200,7 +199,6 @@ public function vslm_register_license_post_type() {
'show_in_rest' => true,
));
}
- add_action('init', 'vslm_register_license_post_type');
/**
* Customize the update messages for the License custom post type.
@@ -231,7 +229,6 @@ public function vslm_license_post_updated_messages($messages) {
return $messages;
}
- add_filter('post_updated_messages', 'vslm_license_post_updated_messages');
/**
* Add custom meta boxes for license details in the license edit screen, with status dot after the title.
@@ -242,13 +239,12 @@ public function vslm_add_license_meta_boxes() {
add_meta_box(
'license_details',
vslm_license_meta_box_title(), // Set title with dynamic status dot
- 'smarty_vslm_license_details_callback',
+ array($this, 'vslm_license_details_cb'),
'vslm-licenses',
'normal',
'default'
);
}
- add_action('add_meta_boxes', 'vslm_add_license_meta_boxes');
/**
* Generate the title for the license meta box with a colored status dot.
@@ -281,13 +277,12 @@ function vslm_add_json_response_meta_box() {
add_meta_box(
'smarty_vslm_json_response',
__('Product Status (JSON)', 'smarty-very-simple-license-manager'),
- 'smarty_vslm_json_response_meta_box_callback',
+ array($this, 'vslm_json_response_meta_box_cb'),
'vslm-licenses',
'normal',
'default'
);
}
- add_action('add_meta_boxes', 'vslm_add_json_response_meta_box');
/**
* Callback for the Plugin Status JSON Response meta box.
@@ -295,7 +290,7 @@ function vslm_add_json_response_meta_box() {
* @since 1.0.1
* @param WP_Post $post The current post object.
*/
- public function smarty_vslm_json_response_meta_box_callback($post) {
+ public function vslm_json_response_meta_box_cb($post) {
// Retrieve meta data
$multi_domain = get_post_meta($post->ID, '_multi_domain', true);
$usage_url = get_post_meta($post->ID, '_usage_url', true);
@@ -362,7 +357,7 @@ public function smarty_vslm_json_response_meta_box_callback($post) {
* @since 1.0.1
* @param WP_Post $post The current post object.
*/
- public function smarty_vslm_license_details_callback($post) {
+ public function vslm_license_details_cb($post) {
// Retrieve existing values from the post meta, if available
$product_terms = get_the_terms($post->ID, 'product'); // Get assigned product terms
$license_key = get_post_meta($post->ID, '_license_key', true);
@@ -621,7 +616,7 @@ public function smarty_vslm_license_details_callback($post) {
* @param int $post_id The ID of the current post being saved.
* @param WP_Post $post The current post object.
*/
- public function smarty_vslm_save_license_meta($post_id, $post) {
+ public function vslm_save_license_meta($post_id, $post) {
if ($post->post_type === 'vslm-licenses') {
// Verify nonce for security
if (!isset($_POST['smarty_vslm_license_nonce']) || !wp_verify_nonce($_POST['smarty_vslm_license_nonce'], 'smarty_vslm_save_license_meta')) {
@@ -666,7 +661,6 @@ public function smarty_vslm_save_license_meta($post_id, $post) {
}
}
}
- add_action('save_post', 'smarty_vslm_save_license_meta', 10, 2);
/**
* Set a numeric slug for licenses instead of a title-based slug.
@@ -676,7 +670,7 @@ public function smarty_vslm_save_license_meta($post_id, $post) {
* @param array $postarr The array of unsanitized post data.
* @return array Modified post data with a numeric slug.
*/
- public function smarty_vslm_set_numeric_slug($data, $postarr) {
+ public function vslm_set_numeric_slug($data, $postarr) {
if ($data['post_type'] === 'vslm-licenses' && $data['post_status'] === 'publish') {
// Generate a unique numeric slug based on the post ID
if (empty($postarr['ID'])) {
@@ -690,14 +684,13 @@ public function smarty_vslm_set_numeric_slug($data, $postarr) {
}
return $data;
}
- add_filter('wp_insert_post_data', 'smarty_vslm_set_numeric_slug', 10, 2);
/**
* Register the 'Products' taxonomy for licenses.
*
* @since 1.0.1
*/
- public function smarty_vslm_register_product_taxonomy() {
+ public function vslm_register_product_taxonomy() {
register_taxonomy('product', 'vslm-licenses', array(
'labels' => array(
'name' => esc_html(__('Products', 'smarty-very-simple-license-manager')),
@@ -717,7 +710,6 @@ public function smarty_vslm_register_product_taxonomy() {
'rewrite' => array('slug' => 'product'),
));
}
- add_action('init', 'smarty_vslm_register_product_taxonomy');
/**
* Remove the "View Posts" link from the admin bar for the License post type.
@@ -725,7 +717,7 @@ public function smarty_vslm_register_product_taxonomy() {
* @since 1.0.1
* @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar instance.
*/
- public function smarty_vslm_remove_admin_bar_view_posts($wp_admin_bar) {
+ public function vslm_remove_admin_bar_view_posts($wp_admin_bar) {
// Check if we're in the License custom post type or editing it
global $post_type, $post;
@@ -738,7 +730,6 @@ public function smarty_vslm_remove_admin_bar_view_posts($wp_admin_bar) {
$wp_admin_bar->remove_menu('view'); // Extra attempt in case `remove_node` does not cover all cases
}
}
- add_action('admin_bar_menu', 'smarty_vslm_remove_admin_bar_view_posts', 999);
/**
* Remove the "View" link from the row actions for licenses in the admin list.
@@ -748,14 +739,13 @@ public function smarty_vslm_remove_admin_bar_view_posts($wp_admin_bar) {
* @param WP_Post $post The current post object.
* @return array Modified row actions without the "View" link.
*/
- function smarty_vslm_remove_view_link($actions, $post) {
+ function vslm_remove_view_link($actions, $post) {
// Check if the current post type is "license"
if ($post->post_type === 'vslm-licenses') {
unset($actions['view']); // Remove the "View" action
}
return $actions;
}
- add_filter('post_row_actions', 'smarty_vslm_remove_view_link', 10, 2);
/**
* Remove "Quick Edit" from the row actions in the licenses list.
@@ -765,13 +755,12 @@ function smarty_vslm_remove_view_link($actions, $post) {
* @param WP_Post $post The current post object.
* @return array Modified row actions without the "Quick Edit" option.
*/
- function smarty_vslm_remove_quick_edit($actions, $post) {
+ function vslm_remove_quick_edit($actions, $post) {
if ($post->post_type === 'vslm-licenses') {
unset($actions['inline hide-if-no-js']); // Remove the "Quick Edit" action
}
return $actions;
}
- add_filter('post_row_actions', 'smarty_vslm_remove_quick_edit', 10, 2);
/**
* Add custom columns for License Key, Status, Expiration Date, and User Email in the licenses list table.
@@ -780,7 +769,7 @@ function smarty_vslm_remove_quick_edit($actions, $post) {
* @param array $columns The current list of columns.
* @return array Modified list of columns.
*/
- public function smarty_vslm_add_license_columns($columns) {
+ public function vslm_add_license_columns($columns) {
unset($columns['title']);
// Define the new columns order, placing "Product" first
$new_columns = array(
@@ -797,7 +786,6 @@ public function smarty_vslm_add_license_columns($columns) {
return $new_columns;
}
- add_filter('manage_vslm-licenses_posts_columns', 'smarty_vslm_add_license_columns');
/**
* Populate the custom columns for License Key, Status, Expiration Date, and User Email.
@@ -806,7 +794,7 @@ public function smarty_vslm_add_license_columns($columns) {
* @param string $column The name of the column.
* @param int $post_id The ID of the current post.
*/
- public function smarty_vslm_fill_license_columns($column, $post_id) {
+ public function vslm_fill_license_columns($column, $post_id) {
if ($column === 'license_key') {
$license_key = get_post_meta($post_id, '_license_key', true);
$masked_key = substr($license_key, 0, 4) . '-XXXX-XXXX-XXXX';
@@ -896,7 +884,6 @@ public function smarty_vslm_fill_license_columns($column, $post_id) {
echo $product_version ? esc_html($product_version) : esc_html(__('Not recorded', 'smarty-very-simple-license-manager'));
}
}
- add_action('manage_vslm-licenses_posts_custom_column', 'smarty_vslm_fill_license_columns', 10, 2);
/**
* Define sortable columns for License Key and Status.
@@ -905,68 +892,38 @@ public function smarty_vslm_fill_license_columns($column, $post_id) {
* @param array $columns The current list of sortable columns.
* @return array Modified list of sortable columns.
*/
- public function smarty_vslm_sortable_license_columns($columns) {
+ public function vslm_sortable_license_columns($columns) {
$columns['license_key'] = 'license_key';
$columns['license_status'] = 'license_status';
return $columns;
}
- add_filter('manage_edit-vslm-licenses_sortable_columns', 'smarty_vslm_sortable_license_columns');
/**
- * Make the Status column sortable in the admin.
- *
- * @since 1.0.1
- * @param array $columns List of sortable columns.
- * @return array Updated sortable columns.
- */
- public function smarty_vslm_license_sortable_columns($columns) {
- $columns['license_status'] = 'license_status';
- return $columns;
- }
- add_filter('manage_edit-license_sortable_columns', 'smarty_vslm_license_sortable_columns');
-
- /**
- * Sort the licenses by status in the admin.
+ * Modify the query to handle sorting by license key and status.
*
* @since 1.0.1
- * @param WP_Query $query The current WP_Query object.
+ * @param WP_Query $query The current WP_Query instance.
*/
- public function smarty_vslm_license_orderby_status($query) {
+ public function vslm_orderby_license_columns($query) {
if (!is_admin()) {
return;
}
- $orderby = $query->get('orderby');
- if ('license_status' === $orderby) {
- $query->set('meta_key', '_status');
- $query->set('orderby', 'meta_value');
- }
- }
- add_action('pre_get_posts', 'smarty_vslm_license_orderby_status');
-
- /**
- * Modify the query to handle sorting by license key and status.
- *
- * @since 1.0.1
- * @param WP_Query $query The current WP_Query instance.
- */
- public function smarty_vslm_orderby_license_columns($query) {
- if (!is_admin()) return;
if ($query->get('orderby') === 'license_key') {
$query->set('meta_key', '_license_key');
$query->set('orderby', 'meta_value');
}
+
if ($query->get('orderby') === 'license_status') {
$query->set('meta_key', '_status');
$query->set('orderby', 'meta_value');
}
}
- add_action('pre_get_posts', 'smarty_vslm_orderby_license_columns');
/**
* @since 1.0.1
*/
- public function smarty_vslm_custom_admin_styles() {
+ public function vslm_custom_admin_styles() {
global $post_type;
if ('vslm-licenses' === $post_type) {
@@ -978,7 +935,6 @@ public function smarty_vslm_custom_admin_styles() {
';
}
}
- add_action('admin_head', 'smarty_vslm_custom_admin_styles');
/**
* Adds an options page for the plugin in the WordPress admin menu.
@@ -1029,7 +985,7 @@ public function vslm_display_settings_page() {
*
* @since 1.0.1
*/
- public function vslm_settings_init() {
+ public function smarty_vslm_settings_init() {
register_setting('smarty_vslm_settings', 'smarty_vslm_ck_key');
register_setting('smarty_vslm_settings', 'smarty_vslm_cs_key');
@@ -1037,14 +993,14 @@ public function vslm_settings_init() {
add_settings_section(
'smarty_vslm_section_general', // ID of the section
__('General', 'smarty-very-simple-license-manager'), // Title of the section
- 'smarty_vslm_section_general_callback', // Callback function that fills the section with the desired content
+ array($this, 'smarty_vslm_section_general_cb'), // Callback function that fills the section with the desired content
'smarty_vslm_settings' // Page on which to add the section
);
add_settings_field(
'smarty_vslm_ck_key',
__('Consumer Key', 'smarty-very-simple-license-manager'),
- 'smarty_vslm_ck_key_callback',
+ array($this, 'vslm_ck_key_cb'),
'smarty_vslm_settings',
'smarty_vslm_section_general'
);
@@ -1052,7 +1008,7 @@ public function vslm_settings_init() {
add_settings_field(
'smarty_vslm_cs_key',
__('Consumer Secret', 'smarty-very-simple-license-manager'),
- 'smarty_vslm_cs_key_callback',
+ array($this, 'vslm_cs_key_cb'),
'smarty_vslm_settings',
'smarty_vslm_section_general'
);
@@ -1063,7 +1019,7 @@ public function vslm_settings_init() {
*
* @since 1.0.1
*/
- public function smarty_vslm_section_general_callback() { ?>
+ public function smarty_vslm_section_general_cb() { ?>
*
* @since 1.0.1
*/
- public function smarty_vslm_ck_key_callback() {
+ public function vslm_ck_key_cb() {
$ck_key = get_option('smarty_vslm_ck_key'); ?>
@@ -1085,51 +1041,47 @@ public function smarty_vslm_ck_key_callback() {
*
* @since 1.0.1
*/
- public function smarty_vslm_cs_key_callback() {
+ public function vslm_cs_key_cb() {
$cs_key = get_option('smarty_vslm_cs_key'); ?>
'GET',
- 'callback' => 'smarty_vslm_check_license_status',
- 'permission_callback' => 'smarty_vslm_basic_auth_permission_check',
+ 'callback' => 'vslm_check_license_status',
+ 'permission_callback' => 'vslm_basic_auth_permission_check',
));
}
- add_action('rest_api_init', 'smarty_vslm_register_license_status_endpoint');
/**
* Permission callback for Basic Auth.
@@ -1137,7 +1089,7 @@ public function smarty_vslm_register_license_status_endpoint() {
* @since 1.0.1
* @return bool True if authentication is successful, false otherwise.
*/
- public function smarty_vslm_basic_auth_permission_check() {
+ public function vslm_basic_auth_permission_check() {
$headers = getallheaders();
if (isset($headers['Authorization'])) {
$auth_header = $headers['Authorization'];
@@ -1166,7 +1118,7 @@ public function smarty_vslm_basic_auth_permission_check() {
* @param WP_REST_Request $request The REST request object.
* @return WP_REST_Response The REST response with license status, expiration date, usage URL, and WordPress version.
*/
- public function smarty_vslm_check_license_status(WP_REST_Request $request) {
+ public function vslm_check_license_status(WP_REST_Request $request) {
$license_key = $request->get_param('license_key');
$site_url = $request->get_param('site_url');
$wp_version = $request->get_param('wp_version');
@@ -1335,19 +1287,18 @@ public function smarty_vslm_check_license_status(WP_REST_Request $request) {
*
* @since 1.0.1
*/
- public function smarty_vslm_schedule_cron_job() {
- if (!wp_next_scheduled('smarty_vslm_license_check')) {
- wp_schedule_event(time(), 'daily', 'smarty_vslm_license_check');
+ public function vslm_schedule_cron_job() {
+ if (!wp_next_scheduled('vslm_license_check')) {
+ wp_schedule_event(time(), 'daily', 'vslm_license_check');
}
}
- add_action('wp', 'smarty_vslm_schedule_cron_job');
-
+
/**
* Cron job function to mark expired licenses as expired.
*
* @since 1.0.1
*/
- public function smarty_vslm_check_expired_licenses() {
+ public function vslm_check_expired_licenses() {
$licenses = get_posts(array('post_type' => 'vslm-licenses', 'posts_per_page' => -1));
foreach ($licenses as $license) {
$expiration_date = get_post_meta($license->ID, '_expiration_date', true);
@@ -1356,5 +1307,4 @@ public function smarty_vslm_check_expired_licenses() {
}
}
}
- add_action('smarty_vslm_license_check', 'smarty_vslm_check_expired_licenses');
}
\ No newline at end of file
diff --git a/admin/tabs/class-smarty-vslm-activity-logging.php b/admin/tabs/class-smarty-vslm-activity-logging.php
new file mode 100644
index 0000000..7490438
--- /dev/null
+++ b/admin/tabs/class-smarty-vslm-activity-logging.php
@@ -0,0 +1,188 @@
+' . __('View and manage the activity logs for the plugin.', 'smarty-very-simple-license-manager') . '';
+ }
+
+ /**
+ * Callback function for the Activity & Logging section field.
+ *
+ * @since 1.0.1
+ */
+ public static function vslm_activity_log_cb() {
+ $instance = new self('Smarty_Vslm_Admin', '1.0.1');
+ $instance->vslm_display_activity_log();
+ }
+
+ /**
+ * Callback function to display the system info.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_system_info_cb() {
+ $system_info = $this->get_system_info();
+ echo '';
+ foreach ($system_info as $key => $value) {
+ echo '' . esc_html($key) . ': ' . wp_kses($value, array('span' => array('style' => array()))) . ' ';
+ }
+ echo ' ';
+ }
+
+ /**
+ * Get system information.
+ *
+ * @since 1.0.1
+ * @return string System information.
+ */
+ private function get_system_info() {
+ $system_info = array(
+ 'User Agent' => esc_html($_SERVER['HTTP_USER_AGENT']),
+ 'Web Server' => esc_html($_SERVER['SERVER_SOFTWARE']),
+ 'PHP Version' => esc_html(PHP_VERSION),
+ 'PHP Max POST Size' => esc_html(ini_get('post_max_size')),
+ 'PHP Max Upload Size' => esc_html(ini_get('upload_max_filesize')),
+ 'PHP Memory Limit' => esc_html(ini_get('memory_limit')),
+ 'PHP DateTime Class' => class_exists('DateTime') ? 'Available ' : 'Not Available ',
+ 'PHP Curl' => function_exists('curl_version') ? 'Available ' : 'Not Available ',
+ );
+
+ return $system_info;
+ }
+
+ /**
+ * Display the activity log.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_display_activity_log() {
+ // Retrieve log entries from the database or file
+ $logs = get_option('smarty_vslm_activity_log', array());
+
+ if (empty($logs)) {
+ echo '' . esc_html__('Log empty', 'smarty-very-simple-license-manager') . ' ';
+ echo '' . esc_html__('Delete Logs', 'smarty-very-simple-license-manager') . ' ';
+ } else {
+ echo '';
+ foreach ($logs as $log) {
+ echo '' . esc_html($log) . ' ';
+ }
+ echo ' ';
+ echo '' . esc_html__('Delete Logs', 'smarty-very-simple-license-manager') . ' ';
+ }
+ }
+
+ /**
+ * Add an entry to the activity log.
+ *
+ * @since 1.0.1
+ * @param string $message The log message.
+ */
+ public static function vslm_add_activity_log($message) {
+ $logs = get_option('smarty_vslm_activity_log', array());
+
+ // Get the current time in the specified format
+ $time_format = 'Y-m-d H:i:s'; // PHP date format
+ $current_time = current_time('mysql'); // Get current time in MySQL format
+
+ // Get the timezone
+ $timezone_string = get_option('timezone_string');
+ if (!$timezone_string) {
+ // If no timezone string is available, fall back to GMT offset
+ $gmt_offset = get_option('gmt_offset');
+ if ($gmt_offset) {
+ $timezone_string = timezone_name_from_abbr('', $gmt_offset * 3600, 0);
+ } else {
+ $timezone_string = 'UTC';
+ }
+ }
+
+ $timezone = new DateTimeZone($timezone_string);
+
+ // Create DateTime object with current time and timezone
+ $datetime = new DateTime($current_time, $timezone);
+ $formatted_time = $datetime->format('Y-m-d H:i:s'); // Reformat time according to timezone
+ $timezone_name = $datetime->format('T'); // Gets the timezone abbreviation, e.g., GMT
+
+ // Combine time, timezone, and message
+ $log_entry = sprintf("[%s %s] - %s", $formatted_time, $timezone_name, $message);
+ $logs[] = $log_entry;
+
+ // Save the updated logs back to the database
+ update_option('smarty_vslm_activity_log', $logs);
+ }
+
+ /**
+ * Clear the activity log.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_clear_activity_log() {
+ update_option('smarty_vslm_activity_log', array());
+ }
+
+ /**
+ * Handle the AJAX request to clear the logs.
+ *
+ * @since 1.0.1
+ */
+ public function vslm_handle_ajax_clear_logs() {
+ check_ajax_referer('smarty_vslm_license_nonce', 'nonce');
+
+ if (!current_user_can('manage_options')) {
+ wp_send_json_error('You do not have sufficient permissions to access this page.');
+ }
+
+ $this->vslm_clear_activity_log();
+ wp_send_json_success(__('Logs cleared.', 'smarty-very-simple-license-manager'));
+ }
+}
\ No newline at end of file
diff --git a/includes/classes/class-smarty-vslm-locator.php b/includes/classes/class-smarty-vslm-locator.php
index ad40cfa..4eaf125 100644
--- a/includes/classes/class-smarty-vslm-locator.php
+++ b/includes/classes/class-smarty-vslm-locator.php
@@ -145,27 +145,33 @@ private function define_admin_hooks() {
$this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
$this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
- $this->loader->add_action('admin_menu', $plugin_admin, 'fs_add_settings_page');
- $this->loader->add_action('admin_init', $plugin_admin, 'fs_settings_init');
- $this->loader->add_action('admin_notices', $plugin_admin, 'fs_success_notice');
- $this->loader->add_action('admin_notices', $plugin_admin, 'fs_admin_notice');
- $this->loader->add_action('init', $plugin_admin, 'register_submission_type');
- $this->loader->add_action('init', $plugin_admin, 'register_subject_taxonomy', 0);
- $this->loader->add_action('admin_menu', $plugin_admin, 'remove_add_new_submenu');
- $this->loader->add_action('rest_api_init', $plugin_admin, 'register_submission_routes');
- $this->loader->add_action('add_meta_boxes', $plugin_admin, 'add_submission_meta_boxes');
- $this->loader->add_action('save_post', $plugin_admin, 'save_submission_meta_box');
- $this->loader->add_action('admin_init', $plugin_admin, 'auto_publish_submission_on_edit');
- $this->loader->add_filter('post_row_actions', $plugin_admin, 'remove_quick_edit', 10, 2);
- $this->loader->add_filter('manage_submission_posts_columns', $plugin_admin, 'modify_submission_columns');
- $this->loader->add_action('manage_submission_posts_custom_column', $plugin_admin, 'custom_submission_column', 10, 2);
- $this->loader->add_filter('manage_edit-submission_sortable_columns', $plugin_admin, 'make_submission_columns_sortable');
- $this->loader->add_action('pre_get_posts', $plugin_admin, 'exclude_submissions_from_feed');
- $this->loader->add_action('wp_ajax_delete_comment', $plugin_admin, 'delete_comment_ajax');
+ $this->loader->add_action('wp_dashboard_setup', $plugin_admin, 'vslm_add_dashboard_widget');
+ $this->loader->add_action('init', $plugin_admin, 'vslm_register_license_post_type');
+ $this->loader->add_filter('post_updated_messages', $plugin_admin, 'vslm_license_post_updated_messages');
+ $this->loader->add_action('add_meta_boxes', $plugin_admin, 'vslm_add_license_meta_boxes');
+ $this->loader->add_action('add_meta_boxes', $plugin_admin, 'vslm_add_json_response_meta_box');
+ $this->loader->add_action('save_post', $plugin_admin, 'vslm_save_license_meta', 10, 2);
+ $this->loader->add_filter('wp_insert_post_data', $plugin_admin, 'vslm_set_numeric_slug', 10, 2);
+ $this->loader->add_action('init', $plugin_admin, 'vslm_register_product_taxonomy');
+ $this->loader->add_action('admin_bar_menu', $plugin_admin, 'vslm_remove_admin_bar_view_posts', 999);
+ $this->loader->add_filter('post_row_actions', $plugin_admin, 'vslm_remove_view_link', 10, 2);
+ $this->loader->add_filter('post_row_actions', $plugin_admin, 'vslm_remove_quick_edit', 10, 2);
+ $this->loader->add_filter('manage_vslm-licenses_posts_columns', $plugin_admin, 'vslm_add_license_columns');
+ $this->loader->add_action('manage_vslm-licenses_posts_custom_column', $plugin_admin, 'vslm_fill_license_columns', 10, 2);
+ $this->loader->add_filter('manage_edit-vslm-licenses_sortable_columns', $plugin_admin, 'vslm_sortable_license_columns');
+ $this->loader->add_action('pre_get_posts', $plugin_admin, 'vslm_orderby_license_columns');
+ $this->loader->add_action('admin_head', $plugin_admin, 'vslm_custom_admin_styles');
+ $this->loader->add_action('admin_menu', $plugin_admin, 'vslm_add_settings_page');
+ $this->loader->add_action('admin_init', $plugin_admin, 'vslm_settings_init');
+ $this->loader->add_action('wp_ajax_generate_ck_key', $plugin_admin, 'vslm_generate_ck_key');
+ $this->loader->add_action('wp_ajax_generate_cs_key', $plugin_admin, 'vslm_generate_cs_key');
+ $this->loader->add_action('rest_api_init', $plugin_admin, 'vslm_register_license_status_endpoint');
+ $this->loader->add_action('wp', $plugin_admin, 'vslm_schedule_cron_job');
+ $this->loader->add_action('smarty_vslm_license_check', $plugin_admin, 'vslm_check_expired_licenses');
// Register hooks for Activity & Logging
- $this->loader->add_action('admin_init', $plugin_activity_logging, 'fs_al_settings_init');
- $this->loader->add_action('wp_ajax_smarty_fs_clear_logs', $plugin_activity_logging, 'fs_handle_ajax_clear_logs');
+ $this->loader->add_action('admin_init', $plugin_activity_logging, 'vslm_al_settings_init');
+ $this->loader->add_action('wp_ajax_smarty_vslm_clear_logs', $plugin_activity_logging, 'vslm_handle_ajax_clear_logs');
}
/**
From 24ebe8a3e22d2641d4ab4dbeaa545c89ad98d015 Mon Sep 17 00:00:00 2001
From: Martin Nestorov
Date: Mon, 25 Nov 2024 00:21:39 +0200
Subject: [PATCH 4/9] Bug fixes
---
admin/class-smarty-vslm-admin.php | 168 ++++++++++--------
admin/css/smarty-vslm-admin.css | 17 +-
admin/js/smarty-vslm-admin.js | 53 ++++--
admin/js/smarty-vslm-ajax.js | 33 +++-
admin/partials/smarty-vslm-admin-display.php | 28 ++-
includes/classes/class-smarty-vslm-loader.php | 2 +-
.../classes/class-smarty-vslm-locator.php | 8 +-
7 files changed, 206 insertions(+), 103 deletions(-)
diff --git a/admin/class-smarty-vslm-admin.php b/admin/class-smarty-vslm-admin.php
index d8bedcc..a8ab88e 100644
--- a/admin/class-smarty-vslm-admin.php
+++ b/admin/class-smarty-vslm-admin.php
@@ -82,7 +82,7 @@ public function enqueue_styles() {
*
* @since 1.0.1
*/
- public function enqueue_scripts() {
+ public function enqueue_scripts($hook) {
/**
* This function enqueues custom JavaScript for the plugin settings in WordPress admin.
*
@@ -100,20 +100,26 @@ public function enqueue_scripts() {
// Check if we're on the License Manager settings page
if ($hook === 'settings_page_smarty-vslm-settings') {
// Enqueue AJAX script for the settings page
- wp_enqueue_script('vslm-ajax', plugin_dir_url(__FILE__) . 'js/smarty-vslm-ajax.js', array('jquery'), $this->version, true);
+ wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/smarty-vslm-ajax.js', array('jquery'), $this->version, false);
// Localize AJAX URL for the JavaScript
- wp_localize_script('vslm-ajax', 'smarty_vslm_ajax', array(
- 'ajax_url' => admin_url('admin-ajax.php')
- ));
+ wp_localize_script(
+ $this->plugin_name,
+ 'smartyVerySimpleLicenseManager',
+ array(
+ 'ajaxUrl' => admin_url('admin-ajax.php'),
+ 'siteUrl' => site_url(),
+ 'nonce' => wp_create_nonce('smarty_vslm_license_nonce'),
+ )
+ );
}
// Check if we're on any license-related pages (edit, add, or post screen)
if ($hook === 'edit.php' || $hook === 'post.php' || $hook === 'post-new.php') {
if ($post_type === 'vslm-licenses' || get_post_type() === 'vslm-licenses') {
// Enqueue CSS and JS files for license post type
- wp_enqueue_script('vslm-admin-js', plugin_dir_url(__FILE__) . 'js/smarty-vslm-admin.js', array(), $this->version, true);
- wp_enqueue_script('vslm-json-js', plugin_dir_url(__FILE__) . 'js/smarty-vslm-json.js', array(), $this->version, true);
+ wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/smarty-vslm-admin.js', array(), $this->version, false);
+ wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/smarty-vslm-json.js', array(), $this->version, false);
}
}
}
@@ -125,9 +131,9 @@ public function enqueue_scripts() {
*/
public function vslm_add_dashboard_widget() {
wp_add_dashboard_widget(
- 'smarty_vslm_dashboard_widget', // Widget ID
- 'License Manager Overview', // Widget Title
- 'smarty_vslm_dashboard_widget_render' // Callback function to display content
+ 'smarty_vslm_dashboard_widget', // Widget ID
+ __('License Manager Overview', 'smarty-very-simple-license-manager'), // Widget Title
+ array($this, 'vslm_dashboard_widget_render_cb') // Callback function to display content
);
}
@@ -136,7 +142,7 @@ public function vslm_add_dashboard_widget() {
*
* @since 1.0.1
*/
- public function vslm_dashboard_widget_render() {
+ public function vslm_dashboard_widget_render_cb() {
// Query for licenses and count statuses
$total_count = wp_count_posts('vslm-licenses')->publish; // Get total published licenses
$active_count = smarty_vslm_get_license_count_by_status('active');
@@ -151,21 +157,21 @@ public function vslm_dashboard_widget_render() {
- Status
- Count
+
+
- Active Licenses
+
- Inactive Licenses
+
- Expired Licenses
+
@@ -238,7 +244,7 @@ public function vslm_license_post_updated_messages($messages) {
public function vslm_add_license_meta_boxes() {
add_meta_box(
'license_details',
- vslm_license_meta_box_title(), // Set title with dynamic status dot
+ array($this, 'vslm_license_meta_box_title'), // Set title with dynamic status dot
array($this, 'vslm_license_details_cb'),
'vslm-licenses',
'normal',
@@ -369,7 +375,7 @@ public function vslm_license_details_cb($post) {
$usage_url = get_post_meta($post->ID, '_usage_url', true); // Retrieve the usage URL
$usage_urls = get_post_meta($post->ID, '_usage_urls', true) ?: array();
$multi_domain = get_post_meta($post->ID, '_multi_domain', true);
- $wp_version = get_post_meta($post->ID, '_wp_version', true); // Retrieve the WordPress version
+ $wp_version = get_post_meta($post->ID, '_wp_version', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
// Retrieve plugin information
$plugin_name = get_post_meta($post->ID, '_plugin_name', true) ?: esc_html(__('Not recorded yet', 'smarty-very-simple-license-manager'));
@@ -403,7 +409,7 @@ public function vslm_license_details_cb($post) {
-
+ ID}"); ?>">
@@ -479,49 +485,49 @@ public function vslm_license_details_cb($post) {
@@ -545,7 +551,7 @@ public function vslm_license_details_cb($post) {
@@ -649,6 +655,8 @@ public function vslm_save_license_meta($post_id, $post) {
}
update_post_meta($post_id, '_license_key', $license_key);
+ Smarty_Vslm_Activity_Logging::vslm_add_activity_log("License key updated for License #$post_id: $license_key.");
+
// Update other fields
update_post_meta($post_id, '_client_name', sanitize_text_field($_POST['client_name']));
update_post_meta($post_id, '_client_email', sanitize_email($_POST['client_email']));
@@ -797,23 +805,22 @@ public function vslm_add_license_columns($columns) {
public function vslm_fill_license_columns($column, $post_id) {
if ($column === 'license_key') {
$license_key = get_post_meta($post_id, '_license_key', true);
- $masked_key = substr($license_key, 0, 4) . '-XXXX-XXXX-XXXX';
+ $masked_key = substr($license_key, 0, 4) . '-XXXX-XXXX-XXXX'; ?>
- echo '';
+
- // Masked key
- echo '
' . esc_html($masked_key) . ' ';
- echo '
';
-
- // Show/Hide and Copy links
- echo '
';
- echo '
Show ';
- echo '
Hide ';
- echo '
| ';
- echo '
Copy ';
- echo '
';
+
+
+
- echo '
';
+
+
+
__('General', 'smarty-very-simple-license-manager'),
+ 'activity-logging' => __('Activity & Logging', 'smarty-very-simple-license-manager'),
);
+
+ return $tabs;
}
/**
@@ -970,6 +981,9 @@ public function vslm_display_settings_page() {
return;
}
+ $current_tab = isset($_GET['tab']) ? $_GET['tab'] : 'general';
+ $tabs = $this->vslm_get_settings_tabs();
+
// Define the path to the external file
$partial_file = plugin_dir_path(__FILE__) . 'partials/smarty-vslm-admin-display.php';
@@ -985,23 +999,28 @@ public function vslm_display_settings_page() {
*
* @since 1.0.1
*/
- public function smarty_vslm_settings_init() {
- register_setting('smarty_vslm_settings', 'smarty_vslm_ck_key');
- register_setting('smarty_vslm_settings', 'smarty_vslm_cs_key');
+ public function vslm_settings_init() {
+ // Check if the settings were saved and set a transient
+ if (isset($_GET['settings-updated']) && $_GET['settings-updated']) {
+ set_transient('smarty_vslm_settings_updated', 'yes', 5);
+ }
+
+ register_setting('smarty_vslm_options_general', 'smarty_vslm_ck_key');
+ register_setting('smarty_vslm_options_general', 'smarty_vslm_cs_key');
// Add General section
add_settings_section(
'smarty_vslm_section_general', // ID of the section
__('General', 'smarty-very-simple-license-manager'), // Title of the section
- array($this, 'smarty_vslm_section_general_cb'), // Callback function that fills the section with the desired content
- 'smarty_vslm_settings' // Page on which to add the section
+ array($this, 'vslm_section_general_cb'), // Callback function that fills the section with the desired content
+ 'smarty_vslm_options_general' // Page on which to add the section
);
add_settings_field(
'smarty_vslm_ck_key',
__('Consumer Key', 'smarty-very-simple-license-manager'),
array($this, 'vslm_ck_key_cb'),
- 'smarty_vslm_settings',
+ 'smarty_vslm_options_general',
'smarty_vslm_section_general'
);
@@ -1009,7 +1028,7 @@ public function smarty_vslm_settings_init() {
'smarty_vslm_cs_key',
__('Consumer Secret', 'smarty-very-simple-license-manager'),
array($this, 'vslm_cs_key_cb'),
- 'smarty_vslm_settings',
+ 'smarty_vslm_options_general',
'smarty_vslm_section_general'
);
}
@@ -1019,7 +1038,7 @@ public function smarty_vslm_settings_init() {
*
* @since 1.0.1
*/
- public function smarty_vslm_section_general_cb() { ?>
+ public function vslm_section_general_cb() { ?>
ID;
+ Smarty_Vslm_Activity_Logging::vslm_add_activity_log("License #$license_id successfully activated on site: $site_url.");
+
$multi_domain = get_post_meta($license_id, '_multi_domain', true);
if (!empty($site_url) && filter_var($site_url, FILTER_VALIDATE_URL)) {
@@ -1304,6 +1331,7 @@ public function vslm_check_expired_licenses() {
$expiration_date = get_post_meta($license->ID, '_expiration_date', true);
if (strtotime($expiration_date) < time()) {
update_post_meta($license->ID, '_status', 'expired');
+ Smarty_Vslm_Activity_Logging::vslm_add_activity_log("License #{$license->ID} marked as expired.");
}
}
}
diff --git a/admin/css/smarty-vslm-admin.css b/admin/css/smarty-vslm-admin.css
index 4691271..6535e81 100644
--- a/admin/css/smarty-vslm-admin.css
+++ b/admin/css/smarty-vslm-admin.css
@@ -2,7 +2,7 @@
* All of the CSS for plugin admin functionality should be included in this file.
*/
-.smarty-vslm-status-circle {
+ .smarty-vslm-status-circle {
width: 15px;
height: 15px;
border-radius: 50%;
@@ -339,6 +339,17 @@
color: #005177;
}
+/* Styling for the waarning message in settings "General" tab */
+.smarty-vslm-warning-msg {
+ color: #726a51;
+ background-color: #fff3cd;
+ border: 1px solid #e5d4a2;
+ border-left: 4px solid #e5d4a2;
+ border-radius: 3px;
+ padding: 10px;
+ margin-top: 20px;
+}
+
/* Helpers */
.active {
color: #28a745;
@@ -350,6 +361,10 @@
font-weight: bold;
}
+.warning {
+ color: #726a51;
+}
+
.smarty-json-response,
.smarty-json-container pre {
background: #333333;
diff --git a/admin/js/smarty-vslm-admin.js b/admin/js/smarty-vslm-admin.js
index 5fddb36..067c4a0 100644
--- a/admin/js/smarty-vslm-admin.js
+++ b/admin/js/smarty-vslm-admin.js
@@ -27,32 +27,51 @@
* single DOM-ready or window-load handler for a particular page.
*/
- function generateLicenseKey() {
- const key = [...Array(4)].map(() =>
- Math.random().toString(36).substring(2, 6).toUpperCase()
- ).join("-");
- document.getElementById("smarty_vslm_license_key").value = key;
- }
+ $(document).ready(function($) {
+ // Generate License Key function using jQuery
+ function generateLicenseKey($inputElement) {
+ const key = [...Array(4)].map(() =>
+ Math.random().toString(36).substring(2, 6).toUpperCase()
+ ).join("-");
+ $inputElement.val(key); // Use jQuery to set the value
+ }
- function copyLicenseKey(element, licenseKey) {
- navigator.clipboard.writeText(licenseKey).then(function() {
- alert('License key copied to clipboard');
- }, function(err) {
- console.error('Could not copy text: ', err);
+ // e listener for Generate Key button
+ $('.smarty-vslm-generate-key-button').on('click', function () {
+ const $inputElement = $('#smarty_vslm_license_key'); // Target the input field
+ generateLicenseKey($inputElement); // Pass the input element to the function
});
- }
- $(document).ready(function($) {
- $('.smarty-vslm-show-key-link').on('click', function(event) {
- event.preventDefault();
+ $('.smarty-vslm-copy-key-link').on('click', function (e) {
+ e.preventDefault();
+ const licenseKey = $(this).data('license-key');
+
+ if (!navigator.clipboard || !navigator.clipboard.writeText) {
+ console.error('Clipboard API is not supported in this environment.');
+ alert('Copying to clipboard is not supported in your browser.');
+ return;
+ }
+
+ navigator.clipboard.writeText(licenseKey)
+ .then(function () {
+ alert('License key copied to clipboard');
+ })
+ .catch(function (err) {
+ console.error('Could not copy text: ', err);
+ alert('Failed to copy license key.');
+ });
+ });
+
+ $('.smarty-vslm-show-key-link').on('click', function (e) {
+ e.preventDefault();
var $wrapper = $(this).closest('.smarty-vslm-license-key-wrapper');
$wrapper.find('.smarty-vslm-masked-key').text($wrapper.find('.smarty-vslm-full-key').val());
$(this).hide();
$wrapper.find('.smarty-vslm-hide-key-link').show();
});
- $('.smarty-vslm-hide-key-link').on('click', function(event) {
- event.preventDefault();
+ $('.smarty-vslm-hide-key-link').on('click', function (e) {
+ e.preventDefault();
var $wrapper = $(this).closest('.smarty-vslm-license-key-wrapper');
var maskedKey = $wrapper.find('.smarty-vslm-full-key').val().substring(0, 4) + '-XXXX-XXXX-XXXX';
$wrapper.find('.smarty-vslm-masked-key').text(maskedKey);
diff --git a/admin/js/smarty-vslm-ajax.js b/admin/js/smarty-vslm-ajax.js
index 4d7c242..9e1fe68 100644
--- a/admin/js/smarty-vslm-ajax.js
+++ b/admin/js/smarty-vslm-ajax.js
@@ -33,10 +33,11 @@
e.preventDefault(); // Prevent the default form action
$.ajax({
- url: smarty_vslm_ajax.ajax_url,
+ url: smartyVerySimpleLicenseManager.ajaxUrl,
method: 'POST',
data: {
- action: 'smarty_vslm_generate_ck_key'
+ action: 'vslm_generate_ck_key',
+ nonce: smartyVerySimpleLicenseManager.nonce,
},
success: function (response) {
if (response.success) {
@@ -51,10 +52,11 @@
e.preventDefault(); // Prevent the default form action
$.ajax({
- url: smarty_vslm_ajax.ajax_url,
+ url: smartyVerySimpleLicenseManager.ajaxUrl,
method: 'POST',
data: {
- action: 'smarty_vslm_generate_cs_key'
+ action: 'vslm_generate_cs_key',
+ nonce: smartyVerySimpleLicenseManager.nonce,
},
success: function (response) {
if (response.success) {
@@ -63,5 +65,28 @@
}
});
});
+
+ // Delete admin logs
+ $('#smarty-vslm-delete-logs-button').on('click', function(e) {
+ e.preventDefault();
+
+ if (confirm('Are you sure you want to delete all logs?')) {
+ $.post(
+ smartyVerySimpleLicenseManager.ajaxUrl,
+ {
+ action: 'vslm_clear_logs',
+ nonce: smartyVerySimpleLicenseManager.nonce,
+ },
+ function(response) {
+ if (response.success) {
+ alert('Logs cleared.');
+ location.reload();
+ } else {
+ alert('Failed to clear logs.');
+ }
+ }
+ );
+ }
+ });
});
})(jQuery);
\ No newline at end of file
diff --git a/admin/partials/smarty-vslm-admin-display.php b/admin/partials/smarty-vslm-admin-display.php
index 6d14b16..5f1709d 100644
--- a/admin/partials/smarty-vslm-admin-display.php
+++ b/admin/partials/smarty-vslm-admin-display.php
@@ -14,14 +14,28 @@
?>
-
+
+
+ $tab_caption) : ?>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/includes/classes/class-smarty-vslm-loader.php b/includes/classes/class-smarty-vslm-loader.php
index b8e1adb..ffb5149 100644
--- a/includes/classes/class-smarty-vslm-loader.php
+++ b/includes/classes/class-smarty-vslm-loader.php
@@ -14,7 +14,7 @@
* @subpackage Smarty_Very_Simple_License_Manager/includes/classes
* @author Smarty Studio | Martin Nestorov
*/
-class Smarty_Form_Submissions_Loader {
+class Smarty_Vslm_Loader {
/**
* The array of actions registered with WordPress.
diff --git a/includes/classes/class-smarty-vslm-locator.php b/includes/classes/class-smarty-vslm-locator.php
index 4eaf125..9140ef8 100644
--- a/includes/classes/class-smarty-vslm-locator.php
+++ b/includes/classes/class-smarty-vslm-locator.php
@@ -163,15 +163,17 @@ private function define_admin_hooks() {
$this->loader->add_action('admin_head', $plugin_admin, 'vslm_custom_admin_styles');
$this->loader->add_action('admin_menu', $plugin_admin, 'vslm_add_settings_page');
$this->loader->add_action('admin_init', $plugin_admin, 'vslm_settings_init');
- $this->loader->add_action('wp_ajax_generate_ck_key', $plugin_admin, 'vslm_generate_ck_key');
- $this->loader->add_action('wp_ajax_generate_cs_key', $plugin_admin, 'vslm_generate_cs_key');
+ $this->loader->add_action('wp_ajax_vslm_generate_ck_key', $plugin_admin, 'vslm_generate_ck_key');
+ $this->loader->add_action('wp_ajax_nopriv_vslm_generate_ck_key', $plugin_admin, 'vslm_generate_ck_key');
+ $this->loader->add_action('wp_ajax_vslm_generate_cs_key', $plugin_admin, 'vslm_generate_cs_key');
+ $this->loader->add_action('wp_ajax_nopriv_vslm_generate_cs_key', $plugin_admin, 'vslm_generate_cs_key');
$this->loader->add_action('rest_api_init', $plugin_admin, 'vslm_register_license_status_endpoint');
$this->loader->add_action('wp', $plugin_admin, 'vslm_schedule_cron_job');
$this->loader->add_action('smarty_vslm_license_check', $plugin_admin, 'vslm_check_expired_licenses');
// Register hooks for Activity & Logging
$this->loader->add_action('admin_init', $plugin_activity_logging, 'vslm_al_settings_init');
- $this->loader->add_action('wp_ajax_smarty_vslm_clear_logs', $plugin_activity_logging, 'vslm_handle_ajax_clear_logs');
+ $this->loader->add_action('wp_ajax_vslm_clear_logs', $plugin_activity_logging, 'vslm_handle_ajax_clear_logs');
}
/**
From a26603bd7b0817751e383b59ff222596134e992c Mon Sep 17 00:00:00 2001
From: Martin Nestorov
Date: Mon, 25 Nov 2024 00:29:53 +0200
Subject: [PATCH 5/9] Bug fixes
---
css/smarty-vslm-admin.css | 369 --------------------------------------
js/smarty-vslm-admin.js | 33 ----
js/smarty-vslm-ajax.js | 37 ----
js/smarty-vslm-json.js | 36 ----
4 files changed, 475 deletions(-)
delete mode 100644 css/smarty-vslm-admin.css
delete mode 100644 js/smarty-vslm-admin.js
delete mode 100644 js/smarty-vslm-ajax.js
delete mode 100644 js/smarty-vslm-json.js
diff --git a/css/smarty-vslm-admin.css b/css/smarty-vslm-admin.css
deleted file mode 100644
index 66ff79e..0000000
--- a/css/smarty-vslm-admin.css
+++ /dev/null
@@ -1,369 +0,0 @@
-.smarty-vslm-status-circle {
- width: 15px;
- height: 15px;
- border-radius: 50%;
- margin-left: 8px;
-}
-
-/* Checkbox Styling */
-.smarty-vslm-checkbox {
- display: inline-block;
- position: relative;
- width: 24px;
- height: 24px;
-}
-
-.smarty-vslm-checkbox input[type="checkbox"] {
- opacity: 0;
- width: 24px;
- height: 24px;
- position: absolute;
- cursor: pointer;
-}
-
-.smarty-vslm-checkbox .checkmark {
- position: absolute;
- top: 0;
- left: 0;
- width: 20px;
- height: 20px;
- background-color: #e6e6e6;
- border-radius: 4px;
- transition: background-color 0.3s ease;
-}
-
-.smarty-vslm-checkbox input[type="checkbox"]:checked ~ .checkmark {
- background-color: #28a745; /* Change color when checked */
-}
-
-.smarty-vslm-checkbox .checkmark::after {
- content: "";
- position: absolute;
- display: none;
-}
-
-.smarty-vslm-checkbox input[type="checkbox"]:checked ~ .checkmark::after {
- display: block;
-}
-
-.smarty-vslm-checkbox .checkmark::after {
- left: 7px;
- top: 3px;
- width: 4px;
- height: 10px;
- border: solid white;
- border-top-width: medium;
- border-right-width: medium;
- border-bottom-width: medium;
- border-left-width: medium;
- border-width: 0 2px 2px 0;
- transform: rotate(45deg);
-}
-
-/* Two-column Layout */
-.smarty-vslm-two-col {
- display: flex;
- gap: 10px;
-}
-
-.smarty-vslm-left-col, .smarty-vslm-right-col {
- flex: 1;
- border-left: 1px solid #ddd;
-}
-
-.smarty-vslm-left-col {
- border-left: none;
-}
-
-/* Table styling */
-.smarty-vslm-license-table {
- width: 100%;
- max-width: 100%;
- border-collapse: collapse;
-}
-
-.smarty-vslm-license-table td {
- padding: 10px 15px;
- vertical-align: middle;
-}
-
-.smarty-vslm-license-table label {
- font-weight: bold;
- display: inline-block;
- text-align: right;
- vertical-align: middle;
- vertical-align: -moz-middle-with-baseline;
- width: 100%;
-}
-
-.smarty-vslm-license-table .smarty-vslm-field-wrapper {
- display: flex;
- align-items: center;
-}
-
-.smarty-vslm-license-table input,
-.smarty-vslm-license-table select {
- width: 100%;
-}
-
-.smarty-vslm-license-table input[type="checkbox"] {
- width: auto;
-}
-
-.smarty-vslm-license-table .usage-urls br:first-of-type {
- margin-bottom: 10px;
- }
-
-.smarty-vslm-license-table .usage-urls br:last-of-type {
- display: none;
-}
-
-/* Inner (nested) table styling */
-.smarty-vslm-nested-table {
- border-collapse: collapse;
- width: 100%;
- margin: 10px 0;
- text-align: left;
- border: 1px solid #ccc;
-}
-
-.smarty-vslm-nested-table td {
- padding: 8px 10px;
- border: 1px solid #ccc;
-}
-
-.smarty-vslm-nested-table tr:nth-child(even) {
- background-color: #f9f9f9;
-}
-
-.smarty-vslm-nested-table tr:nth-child(odd) {
- background-color: #fff;
-}
-
-.smarty-vslm-generate-key-button {
- margin-left: 10px;
- white-space: nowrap;
-}
-
-@media (max-width: 600px) {
- .smarty-vslm-license-table td {
- display: block;
- width: 100%;
- }
- .smarty-vslm-generate-key-button {
- margin-top: 5px;
- margin-left: 0;
- }
-}
-
-.smarty-vslm-license-key-wrapper {
- display: flex;
- flex-direction: column;
- align-items: flex-start;
-}
-
-.smarty-vslm-masked-key {
- border: 1px solid #ededf0;
- border-radius: 3px;
- padding: 2px 4px;
- background-color: #fefefe;
- width: 160px;
-}
-
-.smarty-vslm-key-toggle-links a {
- color: #2271b1;
- cursor: pointer;
- text-decoration: none;
- margin-right: 5px;
-}
-
-.smarty-vslm-key-toggle-links a:hover {
- color: #135e96;
- text-decoration: none;
-}
-
-/* License Status Styling */
-.smarty-vslm-status-badge.active {
- background-color: #d9f2d9; /* Light green background */
- color: #28a745; /* Darker green text */
- font-weight: bold;
- padding: 4px 8px;
- border-radius: 4px;
-}
-
-.smarty-vslm-status-badge.inactive {
- background-color: #f8d7da; /* Light red background */
- color: #dc3545; /* Darker red text */
- font-weight: bold;
- padding: 4px 8px;
- border-radius: 4px;
-}
-
-.smarty-vslm-status-badge.expired {
- background-color: #b3cbdd;
- color: #2e5877;
- font-weight: bold;
- padding: 4px 8px;
- border-radius: 4px;
-}
-
-/* Outer container to position the circles */
-.smarty-vslm-status-circle-container {
- position: relative;
- display: inline-block;
- width: 14px;
- height: 14px;
- vertical-align: middle;
-}
-
-/* Main status circle */
-.smarty-vslm-status-circle {
- position: relative;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- z-index: 2;
-}
-
-/* Active status with pulsing effect */
-.smarty-vslm-status-circle-container--active .smarty-vslm-status-circle {
- background-color: #28a745; /* Active color */
-}
-.smarty-vslm-status-circle-container--active::before {
- content: '';
- position: absolute;
- top: 0;
- left: 10px;
- width: 80%;
- height: 80%;
- border-radius: 50%;
- background-color: rgba(40, 167, 69, 0.9); /* Slightly lighter green for pulse */
- z-index: 1;
- animation: pulse-active 1.9s infinite ease-out;
-}
-
-/* Inactive status with pulsing effect */
-.smarty-vslm-status-circle-container--inactive .smarty-vslm-status-circle {
- background-color: #dc3545; /* Inactive color */
-}
-
-.smarty-vslm-status-circle-container--inactive::before {
- content: '';
- position: absolute;
- top: 0;
- left: 10px;
- width: 80%;
- height: 80%;
- border-radius: 50%;
- background-color: rgba(220, 53, 69, 0.9); /* Slightly lighter red for pulse */
- z-index: 1;
- animation: pulse-inactive 1.9s infinite ease-out;
-}
-
-/* Expired status with pulsing effect */
-.smarty-vslm-status-circle-container--expired .smarty-vslm-status-circle {
- background-color: #427eab; /* Expired color */
-}
-
-.smarty-vslm-status-circle-container--expired::before {
- content: '';
- position: absolute;
- top: 0;
- left: 10px;
- width: 80%;
- height: 80%;
- border-radius: 50%;
- background-color: rgba(66, 126, 171, 0.9); /* Slightly lighter blue for pulse */
- z-index: 1;
- animation: pulse-expired 1.9s infinite ease-out;
-}
-
-/* Keyframes for pulsing effects */
-@keyframes pulse-active {
- 0% {
- transform: scale(1);
- opacity: 0.8;
- }
- 50% {
- transform: scale(1.8);
- opacity: 0.4;
- }
- 100% {
- transform: scale(2.2);
- opacity: 0;
- }
-}
-
-@keyframes pulse-inactive {
- 0% {
- transform: scale(1);
- opacity: 0.7;
- }
- 50% {
- transform: scale(1.5);
- opacity: 0.3;
- }
- 100% {
- transform: scale(2);
- opacity: 0;
- }
-}
-
-@keyframes pulse-expired {
- 0% {
- transform: scale(1);
- opacity: 0.6;
- }
- 50% {
- transform: scale(1.6);
- opacity: 0.3;
- }
- 100% {
- transform: scale(2.1);
- opacity: 0;
- }
-}
-
-/* Styling for the Copy link */
-.smarty-vslm-copy-key-link {
- margin-left: 5px;
- cursor: pointer;
- color: #0073aa;
-}
-
-.smarty-vslm-copy-key-link:hover {
- color: #005177;
-}
-
-/* Helpers */
-.active {
- color: #28a745;
- font-weight: bold;
-}
-
-.inactive {
- color: #dc3545;
- font-weight: bold;
-}
-
-.smarty-json-response,
-.smarty-json-container pre {
- background: #333333;
- max-height: 150px;
- border-radius: 5px;
- padding: 5px;
- overflow: auto;
-}
-
-.smarty-json-container pre {
- color: #d9f2d9;
- font-family: 'Courier New', Courier, monospace;
-}
-
-.smarty-json-container .success {
- color: #d9f2d9;
-}
-
-.smarty-json-container .error {
- color: #f8d7da;
-}
\ No newline at end of file
diff --git a/js/smarty-vslm-admin.js b/js/smarty-vslm-admin.js
deleted file mode 100644
index 03c2a1f..0000000
--- a/js/smarty-vslm-admin.js
+++ /dev/null
@@ -1,33 +0,0 @@
-function generateLicenseKey() {
- const key = [...Array(4)].map(() =>
- Math.random().toString(36).substring(2, 6).toUpperCase()
- ).join("-");
- document.getElementById("smarty_vslm_license_key").value = key;
-}
-
-function copyLicenseKey(element, licenseKey) {
- navigator.clipboard.writeText(licenseKey).then(function() {
- alert('License key copied to clipboard');
- }, function(err) {
- console.error('Could not copy text: ', err);
- });
-}
-
-jQuery(document).ready(function($) {
- $('.smarty-vslm-show-key-link').on('click', function(event) {
- event.preventDefault();
- var $wrapper = $(this).closest('.smarty-vslm-license-key-wrapper');
- $wrapper.find('.smarty-vslm-masked-key').text($wrapper.find('.smarty-vslm-full-key').val());
- $(this).hide();
- $wrapper.find('.smarty-vslm-hide-key-link').show();
- });
-
- $('.smarty-vslm-hide-key-link').on('click', function(event) {
- event.preventDefault();
- var $wrapper = $(this).closest('.smarty-vslm-license-key-wrapper');
- var maskedKey = $wrapper.find('.smarty-vslm-full-key').val().substring(0, 4) + '-XXXX-XXXX-XXXX';
- $wrapper.find('.smarty-vslm-masked-key').text(maskedKey);
- $(this).hide();
- $wrapper.find('.smarty-vslm-show-key-link').show();
- });
-});
\ No newline at end of file
diff --git a/js/smarty-vslm-ajax.js b/js/smarty-vslm-ajax.js
deleted file mode 100644
index 8f340d3..0000000
--- a/js/smarty-vslm-ajax.js
+++ /dev/null
@@ -1,37 +0,0 @@
-jQuery(document).ready(function ($) {
- // Handle CK Key generation
- $('#smarty_vslm_generate_ck_key').on('click', function (e) {
- e.preventDefault(); // Prevent the default form action
-
- $.ajax({
- url: smarty_vslm_ajax.ajax_url,
- method: 'POST',
- data: {
- action: 'smarty_vslm_generate_ck_key'
- },
- success: function (response) {
- if (response.success) {
- $('#smarty_vslm_ck_key').val(response.data); // Update the CK Key field with the new value
- }
- }
- });
- });
-
- // Handle CS Key generation
- $('#smarty_vslm_generate_cs_key').on('click', function (e) {
- e.preventDefault(); // Prevent the default form action
-
- $.ajax({
- url: smarty_vslm_ajax.ajax_url,
- method: 'POST',
- data: {
- action: 'smarty_vslm_generate_cs_key'
- },
- success: function (response) {
- if (response.success) {
- $('#smarty_vslm_cs_key').val(response.data); // Update the CS Key field with the new value
- }
- }
- });
- });
-});
diff --git a/js/smarty-vslm-json.js b/js/smarty-vslm-json.js
deleted file mode 100644
index 9e1cc2c..0000000
--- a/js/smarty-vslm-json.js
+++ /dev/null
@@ -1,36 +0,0 @@
-document.addEventListener('DOMContentLoaded', function () {
- console.log('DOMContentLoaded triggered');
- const jsonContainers = document.querySelectorAll('[data-json-endpoint]');
-
- console.log('Found containers:', jsonContainers);
-
- jsonContainers.forEach(container => {
- const endpoint = container.dataset.jsonEndpoint;
- console.log('Fetching from endpoint:', endpoint);
-
- fetch(endpoint)
- .then(response => {
- if (!response.ok) {
- if (response.status === 404) {
- return { status: 'rest_no_route', message: 'REST route not found.' };
- }
- throw new Error(`HTTP Error: ${response.status}`);
- }
- return response.json();
- })
- .then(data => {
- console.log('Data received:', data);
- const formattedJson = JSON.stringify(data, null, 2);
- container.innerHTML = `${formattedJson} `;
- })
- .catch(error => {
- console.error('Error fetching JSON:', error);
- const errorJson = {
- status: 'error',
- message: error.message || 'Unknown error occurred.',
- };
- const formattedErrorJson = JSON.stringify(errorJson, null, 2);
- container.innerHTML = `${formattedErrorJson} `;
- });
- });
-});
From ffe339a83d25cdc8c7428bc64e65c4f88cdf0edf Mon Sep 17 00:00:00 2001
From: Martin Nestorov
Date: Mon, 25 Nov 2024 01:09:40 +0200
Subject: [PATCH 6/9] Bug fixes
---
admin/class-smarty-vslm-admin.php | 27 ++--
admin/css/smarty-vslm-admin.css | 160 ++++++++++++++++++-
admin/partials/smarty-vslm-admin-display.php | 2 +-
3 files changed, 167 insertions(+), 22 deletions(-)
diff --git a/admin/class-smarty-vslm-admin.php b/admin/class-smarty-vslm-admin.php
index a8ab88e..733a3b5 100644
--- a/admin/class-smarty-vslm-admin.php
+++ b/admin/class-smarty-vslm-admin.php
@@ -100,11 +100,11 @@ public function enqueue_scripts($hook) {
// Check if we're on the License Manager settings page
if ($hook === 'settings_page_smarty-vslm-settings') {
// Enqueue AJAX script for the settings page
- wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/smarty-vslm-ajax.js', array('jquery'), $this->version, false);
+ wp_enqueue_script('smarty-vslm-ajax', plugin_dir_url(__FILE__) . 'js/smarty-vslm-ajax.js', array('jquery'), time(), true);
// Localize AJAX URL for the JavaScript
wp_localize_script(
- $this->plugin_name,
+ 'smarty-vslm-ajax',
'smartyVerySimpleLicenseManager',
array(
'ajaxUrl' => admin_url('admin-ajax.php'),
@@ -114,13 +114,10 @@ public function enqueue_scripts($hook) {
);
}
- // Check if we're on any license-related pages (edit, add, or post screen)
- if ($hook === 'edit.php' || $hook === 'post.php' || $hook === 'post-new.php') {
- if ($post_type === 'vslm-licenses' || get_post_type() === 'vslm-licenses') {
- // Enqueue CSS and JS files for license post type
- wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/smarty-vslm-admin.js', array(), $this->version, false);
- wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/smarty-vslm-json.js', array(), $this->version, false);
- }
+ if ($post_type === 'vslm-licenses' || get_post_type() === 'vslm-licenses') {
+ // Enqueue JS files for license post type
+ wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/smarty-vslm-admin.js', array(), $this->version, false);
+ wp_enqueue_script('smarty-vslm-json', plugin_dir_url(__FILE__) . 'js/smarty-vslm-json.js', array(), time(), true);
}
}
@@ -325,7 +322,7 @@ public function vslm_json_response_meta_box_cb($post) {
-
+
-
+
'GET',
- 'callback' => 'vslm_check_license_status',
- 'permission_callback' => 'vslm_basic_auth_permission_check',
+ 'callback' => array($this, 'vslm_check_license_status_cb'),
+ 'permission_callback' => array($this, 'vslm_basic_auth_permission_check_cb'),
));
}
@@ -1114,7 +1111,7 @@ public function vslm_register_license_status_endpoint() {
* @since 1.0.1
* @return bool True if authentication is successful, false otherwise.
*/
- public function vslm_basic_auth_permission_check() {
+ public function vslm_basic_auth_permission_check_cb() {
$headers = getallheaders();
if (isset($headers['Authorization'])) {
$auth_header = $headers['Authorization'];
@@ -1143,7 +1140,7 @@ public function vslm_basic_auth_permission_check() {
* @param WP_REST_Request $request The REST request object.
* @return WP_REST_Response The REST response with license status, expiration date, usage URL, and WordPress version.
*/
- public function vslm_check_license_status(WP_REST_Request $request) {
+ public function vslm_check_license_status_cb(WP_REST_Request $request) {
$license_key = $request->get_param('license_key');
$site_url = $request->get_param('site_url');
$wp_version = $request->get_param('wp_version');
diff --git a/admin/css/smarty-vslm-admin.css b/admin/css/smarty-vslm-admin.css
index 6535e81..5932cf0 100644
--- a/admin/css/smarty-vslm-admin.css
+++ b/admin/css/smarty-vslm-admin.css
@@ -2,7 +2,12 @@
* All of the CSS for plugin admin functionality should be included in this file.
*/
- .smarty-vslm-status-circle {
+ .form-table {
+ border-bottom: 2px solid #ccc;
+ margin-bottom: 30px;
+}
+
+.smarty-vslm-status-circle {
width: 15px;
height: 15px;
border-radius: 50%;
@@ -10,6 +15,7 @@
}
/* Checkbox Styling */
+
.smarty-vslm-checkbox {
display: inline-block;
position: relative;
@@ -65,6 +71,7 @@
}
/* Two-column Layout */
+
.smarty-vslm-two-col {
display: flex;
gap: 10px;
@@ -80,6 +87,7 @@
}
/* Table styling */
+
.smarty-vslm-license-table {
width: 100%;
max-width: 100%;
@@ -123,6 +131,7 @@
}
/* Inner (nested) table styling */
+
.smarty-vslm-nested-table {
border-collapse: collapse;
width: 100%;
@@ -187,6 +196,7 @@
}
/* License Status Styling */
+
.smarty-vslm-status-badge.active {
background-color: #d9f2d9; /* Light green background */
color: #28a745; /* Darker green text */
@@ -212,6 +222,7 @@
}
/* Outer container to position the circles */
+
.smarty-vslm-status-circle-container {
position: relative;
display: inline-block;
@@ -221,6 +232,7 @@
}
/* Main status circle */
+
.smarty-vslm-status-circle {
position: relative;
width: 12px;
@@ -230,6 +242,7 @@
}
/* Active status with pulsing effect */
+
.smarty-vslm-status-circle-container--active .smarty-vslm-status-circle {
background-color: #28a745; /* Active color */
}
@@ -247,6 +260,7 @@
}
/* Inactive status with pulsing effect */
+
.smarty-vslm-status-circle-container--inactive .smarty-vslm-status-circle {
background-color: #dc3545; /* Inactive color */
}
@@ -265,6 +279,7 @@
}
/* Expired status with pulsing effect */
+
.smarty-vslm-status-circle-container--expired .smarty-vslm-status-circle {
background-color: #427eab; /* Expired color */
}
@@ -283,6 +298,7 @@
}
/* Keyframes for pulsing effects */
+
@keyframes pulse-active {
0% {
transform: scale(1);
@@ -329,6 +345,7 @@
}
/* Styling for the Copy link */
+
.smarty-vslm-copy-key-link {
margin-left: 5px;
cursor: pointer;
@@ -340,6 +357,7 @@
}
/* Styling for the waarning message in settings "General" tab */
+
.smarty-vslm-warning-msg {
color: #726a51;
background-color: #fff3cd;
@@ -350,7 +368,82 @@
margin-top: 20px;
}
+/* The switch - the box around the slider */
+
+.smarty-toggle-switch {
+ position: relative;
+ display: inline-block;
+ width: 60px;
+ height: 34px;
+}
+
+/* Hide default HTML checkbox */
+
+.smarty-toggle-switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+/* The slider */
+
+.smarty-slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ transition: .4s;
+ border-radius: 34px;
+}
+
+.smarty-slider:before {
+ position: absolute;
+ content: "";
+ height: 26px;
+ width: 26px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ transition: .4s;
+ border-radius: 50%;
+}
+
+input:checked + .smarty-slider {
+ background-color: #2196F3;
+}
+
+input:checked + .smarty-slider:before {
+ transform: translateX(26px);
+}
+
+/* Rounded sliders */
+
+.smarty-slider.round {
+ border-radius: 34px;
+}
+
+.smarty-slider.round:before {
+ border-radius: 50%;
+}
+
/* Helpers */
+
+.smarty-error {
+ background: #fff0f4 !important;
+ color: #c51244 !important;
+}
+
+.smarty-text-success {
+ color: #28a745;
+}
+
+.smarty-text-danger {
+ color: #c51244;
+}
+
.active {
color: #28a745;
font-weight: bold;
@@ -363,10 +456,65 @@
.warning {
color: #726a51;
+ font-weight: bold;
}
-.smarty-json-response,
-.smarty-json-container pre {
+ /* Buttons */
+
+ .btn {
+ display: inline-block;
+ font-weight: 400;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ border: 1px solid transparent;
+ padding: .375rem .75rem;
+ font-size: .85rem;
+ line-height: 1.5;
+ border-radius: .25rem;
+ transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
+ cursor: pointer;
+}
+
+.btn-success {
+ display: inline-block;
+ margin: 20px 5px;
+ background: #28a745;
+ border-color: #28a745;
+ color: #fff;
+}
+
+.btn-success:hover {
+ color: #fff;
+ background-color: #218838;
+ border-color: #1e7e34;
+}
+
+.btn-danger {
+ color: #fff;
+ background-color: #dc3545;
+ border-color: #dc3545;
+}
+
+.btn-danger:hover {
+ color: #fff;
+ background-color: #c82333;
+ border-color: #bd2130;
+}
+
+.btn.disabled, .btn:disabled {
+ opacity: .65;
+ cursor: not-allowed;
+}
+
+/* JSON container */
+
+.smarty-vslm-json-response,
+.smarty-vslm-json-container pre {
background: #333333;
max-height: 150px;
border-radius: 5px;
@@ -374,15 +522,15 @@
overflow: auto;
}
-.smarty-json-container pre {
+.smarty-vslm-json-container pre {
color: #d9f2d9;
font-family: 'Courier New', Courier, monospace;
}
-.smarty-json-container .success {
+.smarty-vslm-json-container .success {
color: #d9f2d9;
}
-.smarty-json-container .error {
+.smarty-vslm-json-container .error {
color: #f8d7da;
}
\ No newline at end of file
diff --git a/admin/partials/smarty-vslm-admin-display.php b/admin/partials/smarty-vslm-admin-display.php
index 5f1709d..5d6944b 100644
--- a/admin/partials/smarty-vslm-admin-display.php
+++ b/admin/partials/smarty-vslm-admin-display.php
@@ -29,7 +29,7 @@
-
+
These keys should be generated once and not changed thereafter.
Altering them could disrupt existing API integrations that rely on these keys for secure access.', 'smarty-very-simple-license-manager')); ?>
From 46b400e74e050e086eb71991d0f0a2ecfa57274e Mon Sep 17 00:00:00 2001
From: Martin Nestorov
Date: Mon, 25 Nov 2024 01:14:40 +0200
Subject: [PATCH 7/9] Added more debug messages
---
admin/js/smarty-vslm-json.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/admin/js/smarty-vslm-json.js b/admin/js/smarty-vslm-json.js
index 9e1cc2c..3642294 100644
--- a/admin/js/smarty-vslm-json.js
+++ b/admin/js/smarty-vslm-json.js
@@ -12,8 +12,12 @@ document.addEventListener('DOMContentLoaded', function () {
.then(response => {
if (!response.ok) {
if (response.status === 404) {
- return { status: 'rest_no_route', message: 'REST route not found.' };
+ return {
+ status: 'rest_no_route',
+ message: 'REST route not found.'
+ };
}
+ console.error(`Error: HTTP ${response.status}`, response);
throw new Error(`HTTP Error: ${response.status}`);
}
return response.json();
From 5b7ba22338c40245fee1cd14997d946d7a075cc6 Mon Sep 17 00:00:00 2001
From: Martin Nestorov
Date: Mon, 25 Nov 2024 01:19:47 +0200
Subject: [PATCH 8/9] Update class-smarty-vslm-admin.php
---
admin/class-smarty-vslm-admin.php | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/admin/class-smarty-vslm-admin.php b/admin/class-smarty-vslm-admin.php
index 733a3b5..b818996 100644
--- a/admin/class-smarty-vslm-admin.php
+++ b/admin/class-smarty-vslm-admin.php
@@ -1036,8 +1036,7 @@ public function vslm_settings_init() {
* @since 1.0.1
*/
public function vslm_section_general_cb() { ?>
-
-
Date: Tue, 26 Nov 2024 12:36:03 +0200
Subject: [PATCH 9/9] Bug fixes
---
admin/class-smarty-vslm-admin.php | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/admin/class-smarty-vslm-admin.php b/admin/class-smarty-vslm-admin.php
index b818996..69a26a3 100644
--- a/admin/class-smarty-vslm-admin.php
+++ b/admin/class-smarty-vslm-admin.php
@@ -652,7 +652,7 @@ public function vslm_save_license_meta($post_id, $post) {
}
update_post_meta($post_id, '_license_key', $license_key);
- Smarty_Vslm_Activity_Logging::vslm_add_activity_log("License key updated for License #$post_id: $license_key.");
+ $this->activity_loggingvslm_add_activity_log('License key updated for License #' . $post_id . ': ' . $license_key);
// Update other fields
update_post_meta($post_id, '_client_name', sanitize_text_field($_POST['client_name']));
@@ -1071,9 +1071,7 @@ public function vslm_cs_key_cb() {
public function vslm_generate_ck_key() {
$ck_key = 'ck_' . bin2hex(random_bytes(20)); // Generate a CK key
update_option('smarty_vslm_ck_key', $ck_key);
-
- Smarty_Vslm_Activity_Logging::vslm_add_activity_log("New CK key generated: $ck_key.");
-
+ $this->activity_logging->vslm_add_activity_log('New CK key generated: ' . $ck_key);
wp_send_json_success($ck_key);
}
@@ -1085,9 +1083,7 @@ public function vslm_generate_ck_key() {
public function vslm_generate_cs_key() {
$cs_key = 'cs_' . bin2hex(random_bytes(20)); // Generate a CS key
update_option('smarty_vslm_cs_key', $cs_key);
-
- Smarty_Vslm_Activity_Logging::vslm_add_activity_log("New CS key generated: $cs_key.");
-
+ $this->activity_logging->vslm_add_activity_log('New CS key generated: ' . $cs_key);
wp_send_json_success($cs_key);
}
@@ -1173,8 +1169,7 @@ public function vslm_check_license_status_cb(WP_REST_Request $request) {
}
$license_id = $license_posts[0]->ID;
- Smarty_Vslm_Activity_Logging::vslm_add_activity_log("License #$license_id successfully activated on site: $site_url.");
-
+ $this->activity_logging->vslm_add_activity_log('License #' . $license_id . ' successfully activated on site: ' . $site_url);
$multi_domain = get_post_meta($license_id, '_multi_domain', true);
if (!empty($site_url) && filter_var($site_url, FILTER_VALIDATE_URL)) {
@@ -1327,7 +1322,7 @@ public function vslm_check_expired_licenses() {
$expiration_date = get_post_meta($license->ID, '_expiration_date', true);
if (strtotime($expiration_date) < time()) {
update_post_meta($license->ID, '_status', 'expired');
- Smarty_Vslm_Activity_Logging::vslm_add_activity_log("License #{$license->ID} marked as expired.");
+ $this->activity_logging->vslm_add_activity_log('License #' . $license->ID . ' marked as expired.');
}
}
}