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'); ?> + +
+

+ Licenses +

+ + + + + + + + + + + + + + + + + + + + + + +
StatusCount
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')); ?> + +
+
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+ +
+ +
+ 'product', + 'name' => 'product', + 'show_option_none' => esc_html(__('-- Select a Product --', 'smarty-very-simple-license-manager')), + 'selected' => $product_terms ? $product_terms[0]->term_id : '', + 'required' => true, + 'hide_empty' => false, + )); + ?> +
+
+
+ +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +

+ + +
+
+ + 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 '
'; + } 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 @@ + + +
+

+
+ + + +
+

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')); ?>

+
+ +
+
\ 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 '

'; - echo '' . $total_count . ' Licenses'; - echo '

'; - - // Table with detailed license counts - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '
StatusCount
Active Licenses' . $active_count . '
Inactive Licenses' . $inactive_count . '
Expired Licenses' . $expired_count . '
'; - - 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')); ?> - - -
- -
- - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
-
- -
- -
- 'product', - 'name' => 'product', - 'show_option_none' => esc_html(__('-- Select a Product --', 'smarty-very-simple-license-manager')), - 'selected' => $product_terms ? $product_terms[0]->term_id : '', - 'required' => true, - 'hide_empty' => false, - )); - ?> -
-
-
- - -
- - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -

- - -
- -
- - 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 '
'; - } 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 - ?> -
-

-
- - - -
-

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')); ?>

-
- - -
-
- -

-
- - -

- - -

'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 ''; + } + + /** + * 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 ''; + echo ''; + } else { + echo ''; + echo ''; + } + } + + /** + * 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() { - - + + - + - + - + @@ -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) { @@ -479,49 +485,49 @@ public function vslm_license_details_cb($post) {
StatusCount
Active Licenses
Inactive Licenses
Expired Licenses
- +
- + - + - + - + - + - + - + - + - + - + - +
@@ -545,7 +551,7 @@ public function vslm_license_details_cb($post) { - + @@ -555,39 +561,39 @@ 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 '
'; + + +
__('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 @@ ?>
-

+

+
- - - -
-

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')); ?>

-
+ + + + +
+

+

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')); ?>

+
+ + + +
\ 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.'); } } }