init_hooks();
$this->includes();
}
private function init_hooks() {
add_action('admin_menu', [$this, 'add_admin_menu'], 55);
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
add_action('wp_ajax_jltma_popup_save', [$this, 'save_popup']);
add_action('wp_ajax_jltma_popup_delete', [$this, 'delete_popup']);
add_action('wp_ajax_jltma_popup_duplicate', [$this, 'duplicate_popup']);
add_action('wp_ajax_jltma_popup_toggle_status', [$this, 'toggle_popup_status']);
}
private function includes() {
// Classes are now autoloaded via the plugin autoloader
}
public function add_admin_menu() {
add_submenu_page(
'master-addons-settings',
__('Popup Builder', 'master-addons'),
__('Popup Builder', 'master-addons'),
'manage_options',
'jltma-popups',
[$this, 'render_popup_page']
);
}
public function render_popup_page() {
$action = isset($_GET['action']) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : 'list'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only display routing, no state change
switch ($action) {
case 'new':
$this->render_new_popup_page();
break;
case 'edit':
$this->render_edit_popup_page();
break;
case 'templates':
$this->render_templates_page();
break;
default:
$this->render_list_page();
break;
}
}
private function render_list_page() {
$list_table = new Popup_List_Table();
$list_table->prepare_items();
?>
get_popup($popup_id);
if (!$popup) {
wp_die( esc_html__('Popup not found', 'master-addons') );
}
?>
render();
}
public function enqueue_admin_assets($hook) {
if (strpos($hook, 'jltma-popups') === false) {
return;
}
\MasterAddons\Inc\Classes\Assets_Manager::enqueue('popup-builder-admin');
wp_localize_script('jltma-popup-builder-admin', 'jltma_popup_builder', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('jltma_popup_builder'),
'strings' => [
'confirm_delete' => __('Are you sure you want to delete this popup?', 'master-addons'),
'saving' => __('Saving...', 'master-addons'),
'saved' => __('Saved!', 'master-addons'),
'error' => __('An error occurred. Please try again.', 'master-addons'),
]
]);
}
public function save_popup() {
if (!check_ajax_referer('jltma_popup_save', 'jltma_popup_nonce', false)) {
wp_die( esc_html__('Security check failed', 'master-addons') );
}
if (!current_user_can('edit_posts')) {
wp_send_json_error(['message' => esc_html__('Invalid access', 'master-addons')]);
}
$popup_id = isset( $_POST['popup_id'] ) ? absint( $_POST['popup_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
$popup_data = [
'name' => isset( $_POST['popup_name'] ) ? sanitize_text_field( wp_unslash( $_POST['popup_name'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'type' => isset( $_POST['popup_type'] ) ? sanitize_text_field( wp_unslash( $_POST['popup_type'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'content' => isset( $_POST['popup_content'] ) ? wp_kses_post( wp_unslash( $_POST['popup_content'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'trigger_type' => isset( $_POST['trigger_type'] ) ? sanitize_text_field( wp_unslash( $_POST['trigger_type'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'trigger_delay' => isset( $_POST['trigger_delay'] ) ? absint( $_POST['trigger_delay'] ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'display_on' => isset( $_POST['display_on'] ) ? sanitize_text_field( wp_unslash( $_POST['display_on'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'show_frequency' => isset( $_POST['show_frequency'] ) ? sanitize_text_field( wp_unslash( $_POST['show_frequency'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'popup_position' => isset( $_POST['popup_position'] ) ? sanitize_text_field( wp_unslash( $_POST['popup_position'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'popup_width' => isset( $_POST['popup_width'] ) ? sanitize_text_field( wp_unslash( $_POST['popup_width'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'popup_animation' => isset( $_POST['popup_animation'] ) ? sanitize_text_field( wp_unslash( $_POST['popup_animation'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'status' => isset($_POST['popup_status']) ? 'active' : 'inactive',
'settings' => [
'show_overlay' => isset($_POST['show_overlay']),
'close_on_overlay' => isset($_POST['close_on_overlay']),
'show_close_button' => isset($_POST['show_close_button']),
'close_on_esc' => isset($_POST['close_on_esc']),
'show_logged_in' => isset($_POST['show_logged_in']),
'show_logged_out' => isset($_POST['show_logged_out']),
'show_first_time' => isset($_POST['show_first_time']),
'popup_priority' => isset( $_POST['popup_priority'] ) ? absint( $_POST['popup_priority'] ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'popup_class' => isset( $_POST['popup_class'] ) ? sanitize_text_field( wp_unslash( $_POST['popup_class'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
'popup_custom_css' => isset( $_POST['popup_custom_css'] ) ? sanitize_textarea_field( wp_unslash( $_POST['popup_custom_css'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
]
];
global $wpdb;
$table_name = $wpdb->prefix . 'jltma_popups';
if ($popup_id) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct update required for custom popup table, no WP core API equivalent
$result = $wpdb->update(
$table_name,
[
'name' => $popup_data['name'],
'type' => $popup_data['type'],
'content' => $popup_data['content'],
'settings' => json_encode($popup_data['settings']),
'status' => $popup_data['status'],
'updated_at' => current_time('mysql')
],
['id' => $popup_id]
);
} else {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- direct insert required for custom popup table, no WP core API equivalent
$result = $wpdb->insert(
$table_name,
[
'name' => $popup_data['name'],
'type' => $popup_data['type'],
'content' => $popup_data['content'],
'settings' => json_encode($popup_data['settings']),
'status' => $popup_data['status'],
'created_at' => current_time('mysql'),
'updated_at' => current_time('mysql')
]
);
$popup_id = $wpdb->insert_id;
}
if ($result !== false) {
wp_send_json_success([
'message' => __('Popup saved successfully', 'master-addons'),
'popup_id' => $popup_id
]);
} else {
wp_send_json_error(['message' => __('Failed to save popup', 'master-addons')]);
}
}
public function delete_popup() {
if (!check_ajax_referer('jltma_popup_builder', 'nonce', false)) {
wp_die( esc_html__('Security check failed', 'master-addons') );
}
if (!current_user_can('edit_posts')) {
wp_send_json_error(['message' => esc_html__('Invalid access', 'master-addons')]);
}
$popup_id = isset( $_POST['popup_id'] ) ? absint( $_POST['popup_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
global $wpdb;
$table_name = $wpdb->prefix . 'jltma_popups';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct delete required for custom popup table, no WP core API equivalent
$result = $wpdb->delete($table_name, ['id' => $popup_id]);
if ($result) {
wp_send_json_success(['message' => __('Popup deleted successfully', 'master-addons')]);
} else {
wp_send_json_error(['message' => __('Failed to delete popup', 'master-addons')]);
}
}
public function duplicate_popup() {
if (!check_ajax_referer('jltma_popup_builder', 'nonce', false)) {
wp_die( esc_html__('Security check failed', 'master-addons') );
}
if (!current_user_can('edit_posts')) {
wp_send_json_error(['message' => esc_html__('Invalid access', 'master-addons')]);
}
$popup_id = isset( $_POST['popup_id'] ) ? absint( $_POST['popup_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
global $wpdb;
$table_name = $wpdb->prefix . 'jltma_popups';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- $table_name is a safe prefixed table name, value is prepared with %d
$popup = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE id = %d", $popup_id));
if ($popup) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- direct insert required for custom popup table, no WP core API equivalent
$result = $wpdb->insert(
$table_name,
[
'name' => $popup->name . ' - Copy',
'type' => $popup->type,
'content' => $popup->content,
'settings' => $popup->settings,
'status' => 'inactive',
'created_at' => current_time('mysql'),
'updated_at' => current_time('mysql')
]
);
if ($result) {
wp_send_json_success(['message' => __('Popup duplicated successfully', 'master-addons')]);
}
}
wp_send_json_error(['message' => __('Failed to duplicate popup', 'master-addons')]);
}
public function toggle_popup_status() {
if (!check_ajax_referer('jltma_popup_builder', 'nonce', false)) {
wp_die( esc_html__('Security check failed', 'master-addons') );
}
if (!current_user_can('edit_posts')) {
wp_send_json_error(['message' => esc_html__('Invalid access', 'master-addons')]);
}
$popup_id = isset( $_POST['popup_id'] ) ? absint( $_POST['popup_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified above
global $wpdb;
$table_name = $wpdb->prefix . 'jltma_popups';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- $table_name is a safe prefixed table name, value is prepared with %d
$popup = $wpdb->get_row($wpdb->prepare("SELECT status FROM $table_name WHERE id = %d", $popup_id));
if ($popup) {
$new_status = $popup->status === 'active' ? 'inactive' : 'active';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct update required for custom popup table, no WP core API equivalent
$result = $wpdb->update(
$table_name,
['status' => $new_status],
['id' => $popup_id]
);
if ($result !== false) {
wp_send_json_success([
'message' => __('Status updated successfully', 'master-addons'),
'new_status' => $new_status
]);
}
}
wp_send_json_error(['message' => __('Failed to update status', 'master-addons')]);
}
private function get_popup($id) {
global $wpdb;
$table_name = $wpdb->prefix . 'jltma_popups';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- $table_name is a safe prefixed table name, value is prepared with %d
$popup = $wpdb->get_row($wpdb->prepare("SELECT * FROM $table_name WHERE id = %d", $id));
if ($popup && !empty($popup->settings)) {
$popup->settings = json_decode($popup->settings, true);
}
return $popup;
}
public static function create_database_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'jltma_popups';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
type varchar(50) NOT NULL,
content longtext NOT NULL,
settings longtext,
status varchar(20) DEFAULT 'active',
views int DEFAULT 0,
conversions int DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
}