376 lines
12 KiB
PHP
376 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* AJAX Handler class - Handles all AJAX requests.
|
|
*
|
|
* @package MapleIcons
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Class MI_Ajax_Handler
|
|
*
|
|
* Handles all AJAX requests for the plugin.
|
|
*/
|
|
class MI_Ajax_Handler {
|
|
|
|
/**
|
|
* Constructor - Register AJAX handlers.
|
|
*/
|
|
public function __construct() {
|
|
// Admin AJAX handlers.
|
|
add_action( 'wp_ajax_mi_download_set', array( $this, 'handle_download_set' ) );
|
|
add_action( 'wp_ajax_mi_delete_set', array( $this, 'handle_delete_set' ) );
|
|
add_action( 'wp_ajax_mi_set_active', array( $this, 'handle_set_active' ) );
|
|
add_action( 'wp_ajax_mi_get_progress', array( $this, 'handle_get_progress' ) );
|
|
|
|
// Block editor AJAX handlers.
|
|
add_action( 'wp_ajax_mi_search_icons', array( $this, 'handle_search_icons' ) );
|
|
add_action( 'wp_ajax_mi_get_icon_svg', array( $this, 'handle_get_icon_svg' ) );
|
|
|
|
// No nopriv handlers - all functionality requires login.
|
|
}
|
|
|
|
/**
|
|
* Handle download set request.
|
|
*/
|
|
public function handle_download_set() {
|
|
// 1. Nonce verification.
|
|
if ( ! check_ajax_referer( 'mi_admin_nonce', 'nonce', false ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Security check failed.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 2. Capability check.
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'You do not have permission to do this.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 3. Input validation.
|
|
$slug = isset( $_POST['slug'] ) ? sanitize_key( $_POST['slug'] ) : '';
|
|
|
|
if ( empty( $slug ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Icon set slug is required.', 'maple-icons' ) )
|
|
);
|
|
}
|
|
|
|
if ( ! MI_Icon_Sets::is_valid_slug( $slug ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Invalid icon set.', 'maple-icons' ) )
|
|
);
|
|
}
|
|
|
|
// Check if already downloaded.
|
|
$registry = MI_Icon_Registry::get_instance();
|
|
if ( $registry->is_downloaded( $slug ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'This icon set is already downloaded.', 'maple-icons' ) )
|
|
);
|
|
}
|
|
|
|
// 4. Process download.
|
|
// Increase time limit for large downloads.
|
|
set_time_limit( 600 ); // 10 minutes.
|
|
|
|
$downloader = new MI_Downloader();
|
|
$result = $downloader->download_set( $slug );
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => $result->get_error_message() )
|
|
);
|
|
}
|
|
|
|
if ( ! $result['success'] ) {
|
|
wp_send_json_error(
|
|
array(
|
|
'message' => sprintf(
|
|
/* translators: %1$d: downloaded count, %2$d: failed count */
|
|
__( 'Download completed with errors. %1$d downloaded, %2$d failed.', 'maple-icons' ),
|
|
$result['downloaded'],
|
|
$result['failed']
|
|
),
|
|
'errors' => array_slice( $result['errors'], 0, 10 ), // Limit errors shown.
|
|
'downloaded' => $result['downloaded'],
|
|
'failed' => $result['failed'],
|
|
)
|
|
);
|
|
}
|
|
|
|
// Mark as downloaded.
|
|
$registry->mark_downloaded( $slug, $result['downloaded'] );
|
|
|
|
// If no active set, make this one active.
|
|
if ( ! $registry->get_active_set() ) {
|
|
$registry->set_active( $slug );
|
|
}
|
|
|
|
$registry->refresh();
|
|
|
|
wp_send_json_success(
|
|
array(
|
|
'message' => sprintf(
|
|
/* translators: %d: number of icons */
|
|
__( 'Successfully downloaded %d icons.', 'maple-icons' ),
|
|
$result['downloaded']
|
|
),
|
|
'icon_count' => $result['downloaded'],
|
|
'is_active' => $registry->get_active_set() === $slug,
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Handle delete set request.
|
|
*/
|
|
public function handle_delete_set() {
|
|
// 1. Nonce verification.
|
|
if ( ! check_ajax_referer( 'mi_admin_nonce', 'nonce', false ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Security check failed.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 2. Capability check.
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'You do not have permission to do this.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 3. Input validation.
|
|
$slug = isset( $_POST['slug'] ) ? sanitize_key( $_POST['slug'] ) : '';
|
|
|
|
if ( empty( $slug ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Icon set slug is required.', 'maple-icons' ) )
|
|
);
|
|
}
|
|
|
|
if ( ! MI_Icon_Sets::is_valid_slug( $slug ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Invalid icon set.', 'maple-icons' ) )
|
|
);
|
|
}
|
|
|
|
// 4. Delete the set.
|
|
$registry = MI_Icon_Registry::get_instance();
|
|
$result = $registry->delete_set( $slug );
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => $result->get_error_message() )
|
|
);
|
|
}
|
|
|
|
wp_send_json_success(
|
|
array(
|
|
'message' => __( 'Icon set deleted successfully.', 'maple-icons' ),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Handle set active request.
|
|
*/
|
|
public function handle_set_active() {
|
|
// 1. Nonce verification.
|
|
if ( ! check_ajax_referer( 'mi_admin_nonce', 'nonce', false ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Security check failed.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 2. Capability check.
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'You do not have permission to do this.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 3. Input validation.
|
|
$slug = isset( $_POST['slug'] ) ? sanitize_key( $_POST['slug'] ) : '';
|
|
|
|
// Empty slug is allowed (to deactivate).
|
|
if ( ! empty( $slug ) && ! MI_Icon_Sets::is_valid_slug( $slug ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Invalid icon set.', 'maple-icons' ) )
|
|
);
|
|
}
|
|
|
|
// 4. Set active.
|
|
$registry = MI_Icon_Registry::get_instance();
|
|
$result = $registry->set_active( $slug );
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => $result->get_error_message() )
|
|
);
|
|
}
|
|
|
|
wp_send_json_success(
|
|
array(
|
|
'message' => empty( $slug )
|
|
? __( 'No icon set is now active.', 'maple-icons' )
|
|
: __( 'Icon set activated.', 'maple-icons' ),
|
|
'active_set' => $slug,
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Handle get progress request.
|
|
*/
|
|
public function handle_get_progress() {
|
|
// 1. Nonce verification.
|
|
if ( ! check_ajax_referer( 'mi_admin_nonce', 'nonce', false ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Security check failed.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 2. Capability check.
|
|
if ( ! current_user_can( 'manage_options' ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'You do not have permission to do this.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 3. Input validation.
|
|
$slug = isset( $_POST['slug'] ) ? sanitize_key( $_POST['slug'] ) : '';
|
|
|
|
if ( empty( $slug ) || ! MI_Icon_Sets::is_valid_slug( $slug ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Invalid icon set.', 'maple-icons' ) )
|
|
);
|
|
}
|
|
|
|
// 4. Get progress.
|
|
$downloader = new MI_Downloader();
|
|
$progress = $downloader->get_progress( $slug );
|
|
|
|
if ( false === $progress ) {
|
|
wp_send_json_success(
|
|
array(
|
|
'downloading' => false,
|
|
'completed' => 0,
|
|
'total' => 0,
|
|
)
|
|
);
|
|
}
|
|
|
|
wp_send_json_success(
|
|
array(
|
|
'downloading' => true,
|
|
'completed' => $progress['completed'],
|
|
'total' => $progress['total'],
|
|
'percentage' => $progress['total'] > 0
|
|
? round( ( $progress['completed'] / $progress['total'] ) * 100 )
|
|
: 0,
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Handle search icons request (for block editor).
|
|
*/
|
|
public function handle_search_icons() {
|
|
// 1. Nonce verification.
|
|
if ( ! check_ajax_referer( 'mi_block_nonce', 'nonce', false ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Security check failed.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 2. Capability check (edit_posts for block usage).
|
|
if ( ! current_user_can( 'edit_posts' ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'You do not have permission to do this.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 3. Input validation.
|
|
$query = isset( $_POST['query'] ) ? sanitize_text_field( $_POST['query'] ) : '';
|
|
$style = isset( $_POST['style'] ) ? sanitize_key( $_POST['style'] ) : '';
|
|
$limit = isset( $_POST['limit'] ) ? absint( $_POST['limit'] ) : MI_SEARCH_LIMIT;
|
|
$offset = isset( $_POST['offset'] ) ? absint( $_POST['offset'] ) : 0;
|
|
|
|
// Limit the limit.
|
|
if ( $limit > 100 ) {
|
|
$limit = 100;
|
|
}
|
|
|
|
// 4. Search.
|
|
$registry = MI_Icon_Registry::get_instance();
|
|
$results = $registry->search_icons( $query, $style, $limit, $offset );
|
|
|
|
wp_send_json_success( $results );
|
|
}
|
|
|
|
/**
|
|
* Handle get icon SVG request (for block editor).
|
|
*/
|
|
public function handle_get_icon_svg() {
|
|
// 1. Nonce verification.
|
|
if ( ! check_ajax_referer( 'mi_block_nonce', 'nonce', false ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Security check failed.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 2. Capability check.
|
|
if ( ! current_user_can( 'edit_posts' ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'You do not have permission to do this.', 'maple-icons' ) ),
|
|
403
|
|
);
|
|
}
|
|
|
|
// 3. Input validation.
|
|
$slug = isset( $_POST['set'] ) ? sanitize_key( $_POST['set'] ) : '';
|
|
$style = isset( $_POST['style'] ) ? sanitize_key( $_POST['style'] ) : '';
|
|
$name = isset( $_POST['name'] ) ? sanitize_file_name( $_POST['name'] ) : '';
|
|
|
|
if ( empty( $slug ) || empty( $style ) || empty( $name ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => __( 'Missing required parameters.', 'maple-icons' ) )
|
|
);
|
|
}
|
|
|
|
// 4. Get SVG.
|
|
$registry = MI_Icon_Registry::get_instance();
|
|
$svg = $registry->get_icon_svg( $slug, $style, $name );
|
|
|
|
if ( is_wp_error( $svg ) ) {
|
|
wp_send_json_error(
|
|
array( 'message' => $svg->get_error_message() )
|
|
);
|
|
}
|
|
|
|
wp_send_json_success(
|
|
array(
|
|
'svg' => $svg,
|
|
'set' => $slug,
|
|
'style' => $style,
|
|
'name' => $name,
|
|
)
|
|
);
|
|
}
|
|
}
|