first commit
This commit is contained in:
373
wp-content/plugins/lordicon/includes/class-ajax-handler.php
Normal file
373
wp-content/plugins/lordicon/includes/class-ajax-handler.php
Normal file
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
namespace Lordicon;
|
||||
|
||||
class AjaxHandler {
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function run() {
|
||||
add_action('wp_ajax_lordicon_request', array($this, 'handle_request'));
|
||||
}
|
||||
|
||||
public function handle_request() {
|
||||
check_ajax_referer('lordicon_action', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_die('Unauthorized');
|
||||
}
|
||||
|
||||
// Check if valid POST request
|
||||
if ( ! isset( $_POST['endpoint'] ) ) {
|
||||
wp_send_json_error('Invalid request.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize endpoint
|
||||
$endpoint = sanitize_text_field( wp_unslash( $_POST['endpoint'] ) );
|
||||
|
||||
switch ($endpoint) {
|
||||
case 'auth_start':
|
||||
$this->auth_start();
|
||||
break;
|
||||
case 'auth_check':
|
||||
$this->auth_check();
|
||||
break;
|
||||
case 'logout':
|
||||
$this->logout();
|
||||
break;
|
||||
case 'status':
|
||||
$this->status();
|
||||
break;
|
||||
case 'variants':
|
||||
$this->variants();
|
||||
break;
|
||||
case 'icons':
|
||||
$this->icons();
|
||||
break;
|
||||
case 'track':
|
||||
$this->track();
|
||||
break;
|
||||
case 'upload':
|
||||
$this->upload();
|
||||
break;
|
||||
default:
|
||||
wp_send_json_error('Unknown action');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function icons() {
|
||||
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
|
||||
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'lordicon_action' ) ) {
|
||||
wp_send_json_error('Security check failed.');
|
||||
return;
|
||||
}
|
||||
|
||||
$family = sanitize_text_field( wp_unslash( $_POST['family'] ?? '' ) );
|
||||
$style = sanitize_text_field( wp_unslash( $_POST['style'] ?? '' ) );
|
||||
$search = sanitize_text_field( wp_unslash( $_POST['search'] ?? '' ) );
|
||||
$index = sanitize_text_field( wp_unslash( $_POST['index'] ?? '' ) );
|
||||
$page = isset( $_POST['page'] ) ? intval( wp_unslash( $_POST['page'] ) ) : 1;
|
||||
$per_page = isset( $_POST['per_page'] ) ? intval( wp_unslash( $_POST['per_page'] ) ) : 100;
|
||||
|
||||
$result = API::get_instance()->icons([
|
||||
'family' => $family,
|
||||
'style' => $style,
|
||||
'search' => $search,
|
||||
'index' => $index,
|
||||
'page' => $page,
|
||||
'per_page' => $per_page,
|
||||
]);
|
||||
|
||||
if ( isset( $result['error'] ) ) {
|
||||
wp_send_json_error( $result['error'] );
|
||||
}
|
||||
|
||||
wp_send_json_success([
|
||||
'icons' => $result['data'] ?? [],
|
||||
'params' => [
|
||||
'link' => $result['headers']['link'] ?? '',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
private function track() {
|
||||
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
|
||||
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'lordicon_action' ) ) {
|
||||
wp_send_json_error('Security check failed.');
|
||||
return;
|
||||
}
|
||||
|
||||
$family = sanitize_text_field( wp_unslash( $_POST['family'] ?? '' ) );
|
||||
$style = sanitize_text_field( wp_unslash( $_POST['style'] ?? '' ) );
|
||||
$index = isset( $_POST['index'] ) ? intval( wp_unslash( $_POST['index'] ) ) : 0;
|
||||
|
||||
$params = [
|
||||
'family' => $family,
|
||||
'style' => $style,
|
||||
'index' => $index,
|
||||
];
|
||||
|
||||
$result = API::get_instance()->track( $params );
|
||||
|
||||
if ( isset( $result['error'] ) ) {
|
||||
wp_send_json_error( $result['error'] );
|
||||
}
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
private function status() {
|
||||
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
|
||||
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'lordicon_action' ) ) {
|
||||
wp_send_json_error('Security check failed.');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = API::get_instance()->status();
|
||||
|
||||
if (isset($result['error'])) {
|
||||
wp_send_json_error($result['error']);
|
||||
} else {
|
||||
wp_send_json_success($result['data']);
|
||||
}
|
||||
}
|
||||
|
||||
private function variants() {
|
||||
$cache_key = 'lordicon_variants';
|
||||
$cached_result = get_transient($cache_key);
|
||||
|
||||
if ($cached_result !== false) {
|
||||
wp_send_json_success($cached_result);
|
||||
return;
|
||||
}
|
||||
|
||||
$result = API::get_instance()->variants();
|
||||
|
||||
if (isset($result['error'])) {
|
||||
wp_send_json_error($result['error']);
|
||||
} else {
|
||||
set_transient($cache_key, $result['data'], HOUR_IN_SECONDS);
|
||||
wp_send_json_success($result['data']);
|
||||
}
|
||||
}
|
||||
|
||||
private function auth_start() {
|
||||
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
|
||||
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'lordicon_action' ) ) {
|
||||
wp_send_json_error('Security check failed.');
|
||||
return;
|
||||
}
|
||||
|
||||
$email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) );
|
||||
|
||||
if ( empty( $email ) ) {
|
||||
wp_send_json_error( 'Email is required' );
|
||||
return;
|
||||
}
|
||||
|
||||
$result = API::get_instance()->auth_start( $email );
|
||||
|
||||
if ( isset( $result['error'] ) ) {
|
||||
wp_send_json_error( $result['error'] );
|
||||
}
|
||||
|
||||
wp_send_json_success( $result['data'] ?? [] );
|
||||
}
|
||||
|
||||
private function auth_check() {
|
||||
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
|
||||
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'lordicon_action' ) ) {
|
||||
wp_send_json_error('Security check failed.');
|
||||
return;
|
||||
}
|
||||
|
||||
$email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) );
|
||||
$code = sanitize_text_field( wp_unslash( $_POST['code'] ?? '' ) );
|
||||
|
||||
if ( empty( $email ) || empty( $code ) ) {
|
||||
wp_send_json_error( 'Email and code are required' );
|
||||
return;
|
||||
}
|
||||
|
||||
$result = API::get_instance()->auth_check( $email, $code );
|
||||
|
||||
if ( isset( $result['error'] ) ) {
|
||||
wp_send_json_error( $result['error'] );
|
||||
}
|
||||
|
||||
$data = $result['data'] ?? [];
|
||||
|
||||
if ( isset( $data['token'] ) ) {
|
||||
$settings_json = get_option( 'lordicon_settings', '{}' );
|
||||
$settings = json_decode( $settings_json );
|
||||
|
||||
if ( ! is_object( $settings ) ) {
|
||||
$settings = new \stdClass();
|
||||
}
|
||||
|
||||
$settings->token = $data['token'];
|
||||
update_option( 'lordicon_settings', wp_json_encode( $settings ) );
|
||||
}
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
private function logout() {
|
||||
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
|
||||
if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'lordicon_action' ) ) {
|
||||
wp_send_json_error('Security check failed.');
|
||||
return;
|
||||
}
|
||||
|
||||
delete_option('lordicon_settings');
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
private function upload() {
|
||||
$nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
|
||||
if (empty($nonce) || ! wp_verify_nonce($nonce, 'lordicon_action')) {
|
||||
wp_send_json_error('Security check failed.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the current user has permission to upload files
|
||||
if (!current_user_can('upload_files')) {
|
||||
wp_send_json_error('Insufficient permissions');
|
||||
}
|
||||
|
||||
// Sanitize input fields from POST to prevent malicious input
|
||||
$post_id = isset($_POST['post_id']) ? intval(wp_unslash($_POST['post_id'])) : 0;
|
||||
$family = sanitize_text_field(wp_unslash($_POST['family'] ?? ''));
|
||||
$style = sanitize_text_field(wp_unslash($_POST['style'] ?? ''));
|
||||
$index = sanitize_text_field(wp_unslash($_POST['index'] ?? ''));
|
||||
$name = sanitize_text_field(wp_unslash($_POST['name'] ?? ''));
|
||||
$hash = sanitize_text_field(wp_unslash($_POST['hash'] ?? ''));
|
||||
|
||||
// Ensure required fields are provided before proceeding
|
||||
if (empty($family) || empty($style) || empty($index) || empty($name)) {
|
||||
wp_send_json_error('Family, style, index, and name are required');
|
||||
}
|
||||
|
||||
// Include WordPress media functions
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/media.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
|
||||
$result = [
|
||||
'svgAttachmentId' => 0,
|
||||
'jsonAttachmentId' => 0,
|
||||
];
|
||||
|
||||
// Check existing attachments
|
||||
$existing_svg = $this->find_existing_attachment('svg', $family, $style, $index, $name, $post_id, $hash);
|
||||
$existing_json = $this->find_existing_attachment('json', $family, $style, $index, $name, $post_id);
|
||||
|
||||
if ($existing_svg) $result['svgAttachmentId'] = $existing_svg->ID;
|
||||
if ($existing_json) $result['jsonAttachmentId'] = $existing_json->ID;
|
||||
|
||||
// Handle SVG and JSON file uploads in a loop for cleaner code
|
||||
foreach ([
|
||||
'svg_file' => ['type' => 'svg', 'mime' => 'image/svg+xml'],
|
||||
'json_file' => ['type' => 'json', 'mime' => 'application/json']
|
||||
] as $input_name => $props) {
|
||||
// Proceed only if a file is uploaded and there is no existing attachment
|
||||
if (isset($_FILES[$input_name], $_FILES[$input_name]['tmp_name']) && $result[$props['type'].'AttachmentId'] <= 0) {
|
||||
// Sanitize file name
|
||||
$filename = isset($_FILES[$input_name]['name']) ? sanitize_file_name(wp_unslash($_FILES[$input_name]['name'])) : '';
|
||||
$_FILES[$input_name]['name'] = $filename;
|
||||
|
||||
$tmp_name = isset($_FILES[$input_name]['tmp_name']) ? wp_normalize_path(sanitize_text_field($_FILES[$input_name]['tmp_name'])) : '';
|
||||
|
||||
if (
|
||||
$tmp_name &&
|
||||
isset($_FILES[$input_name]['error']) &&
|
||||
$_FILES[$input_name]['error'] === UPLOAD_ERR_OK &&
|
||||
is_uploaded_file($tmp_name)
|
||||
) {
|
||||
// Verify file type and extension to match expected type
|
||||
$filetype = wp_check_filetype_and_ext($tmp_name, $filename);
|
||||
|
||||
if ($filetype['ext'] !== $props['type'] || $filetype['type'] !== $props['mime']) {
|
||||
wp_send_json_error('Invalid ' . strtoupper($props['type']) . ' file type.');
|
||||
}
|
||||
|
||||
// Use WordPress media handling to store the uploaded file properly
|
||||
$attachment_id = media_handle_upload($input_name, $post_id);
|
||||
if (is_wp_error($attachment_id)) {
|
||||
wp_send_json_error($attachment_id->get_error_message());
|
||||
}
|
||||
|
||||
// Update post title for easier identification in Media Library
|
||||
$title = sprintf('%s-%s-%s-%s', $family, $style, $index, $name);
|
||||
wp_update_post(['ID' => $attachment_id, 'post_title' => $title]);
|
||||
|
||||
// Store custom meta for later identification of uploaded icons
|
||||
foreach ([
|
||||
'_lordicon_type' => $props['type'],
|
||||
'_lordicon_family' => $family,
|
||||
'_lordicon_style' => $style,
|
||||
'_lordicon_index' => $index,
|
||||
'_lordicon_name' => $name,
|
||||
'_lordicon_hash' => $hash,
|
||||
] as $meta_key => $meta_value) {
|
||||
update_post_meta($attachment_id, $meta_key, $meta_value);
|
||||
}
|
||||
|
||||
// Store attachment ID in result for response
|
||||
$result[$props['type'].'AttachmentId'] = $attachment_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json_success($result);
|
||||
}
|
||||
|
||||
private function find_existing_attachment($type, $family, $style, $index, $name, $post_id = 0, $hash = null) {
|
||||
$meta_query = array(
|
||||
array(
|
||||
'key' => '_lordicon_type',
|
||||
'value' => $type
|
||||
),
|
||||
array(
|
||||
'key' => '_lordicon_family',
|
||||
'value' => $family
|
||||
),
|
||||
array(
|
||||
'key' => '_lordicon_style',
|
||||
'value' => $style
|
||||
),
|
||||
array(
|
||||
'key' => '_lordicon_index',
|
||||
'value' => $index
|
||||
),
|
||||
array(
|
||||
'key' => '_lordicon_name',
|
||||
'value' => $name
|
||||
)
|
||||
);
|
||||
|
||||
if (!empty($hash)) {
|
||||
$meta_query[] = array(
|
||||
'key' => '_lordicon_hash',
|
||||
'value' => $hash
|
||||
);
|
||||
}
|
||||
|
||||
// We use a meta query here to find attachments that match specific metadata fields.
|
||||
// Each Lordicon file (SVG or JSON) is stored as a WordPress attachment with custom meta
|
||||
// describing its type, family, style, index, name, and optionally hash. By querying
|
||||
// these meta fields, we can reliably locate the exact attachment corresponding to
|
||||
// the uploaded icon without relying solely on file names or post titles.
|
||||
$args = array(
|
||||
'post_type' => 'attachment',
|
||||
'post_status' => 'inherit',
|
||||
'post_parent' => $post_id,
|
||||
'meta_query' => $meta_query
|
||||
);
|
||||
|
||||
$attachments = get_posts($args);
|
||||
return !empty($attachments) ? $attachments[0] : null;
|
||||
}
|
||||
}
|
||||
222
wp-content/plugins/lordicon/includes/class-api.php
Normal file
222
wp-content/plugins/lordicon/includes/class-api.php
Normal file
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
namespace Lordicon;
|
||||
|
||||
class API {
|
||||
private static $instance = null;
|
||||
|
||||
private $api_base_url = 'https://api.lordicon.com/v1/';
|
||||
private $settings;
|
||||
|
||||
public function __construct() {
|
||||
$this->settings = json_decode(get_option('lordicon_settings', '{}'));
|
||||
}
|
||||
|
||||
public static function get_instance() {
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function autologin() {
|
||||
// jeśli mamy token w ustawieniach, zwracamy go
|
||||
if (!empty($this->settings->token)) {
|
||||
return array('token' => $this->settings->token);
|
||||
}
|
||||
|
||||
// jeśli brak tokena - próbujemy zalogować jako guest
|
||||
$response = $this->auth_guest();
|
||||
|
||||
if (!empty($response['data']['token'])) {
|
||||
// zapisz nowy token w ustawieniach WP
|
||||
$this->settings->token = $response['data']['token'];
|
||||
update_option('lordicon_settings', json_encode($this->settings));
|
||||
return array('token' => $this->settings->token);
|
||||
}
|
||||
|
||||
// jeśli nie udało się pobrać tokena
|
||||
return array('error' => $response['error'] ?? 'Autologin failed');
|
||||
}
|
||||
|
||||
public function auth_guest() {
|
||||
$url = $this->api_base_url . 'auth/' . Constants::app_name();
|
||||
|
||||
$args = array(
|
||||
'headers' => array('Content-Type' => 'application/json'),
|
||||
'body' => null,
|
||||
'method' => 'POST',
|
||||
'timeout' => 15,
|
||||
);
|
||||
|
||||
$response = wp_remote_request($url, $args);
|
||||
|
||||
return $this->handle_response($response);
|
||||
}
|
||||
|
||||
public function auth_start($email) {
|
||||
$url = $this->api_base_url . 'auth/' . Constants::app_name();
|
||||
|
||||
$args = array(
|
||||
'headers' => array('Content-Type' => 'application/json'),
|
||||
'body' => json_encode(array('email' => $email)),
|
||||
'method' => 'POST',
|
||||
'timeout' => 15,
|
||||
);
|
||||
|
||||
$response = wp_remote_request($url, $args);
|
||||
|
||||
return $this->handle_response($response);
|
||||
}
|
||||
|
||||
public function auth_check($email, $code) {
|
||||
$url = $this->api_base_url . 'auth/' . Constants::app_name();
|
||||
|
||||
$args = array(
|
||||
'headers' => array('Content-Type' => 'application/json'),
|
||||
'body' => json_encode(array('email' => $email, 'code' => $code)),
|
||||
'method' => 'PATCH',
|
||||
'timeout' => 15,
|
||||
);
|
||||
|
||||
$response = wp_remote_request($url, $args);
|
||||
|
||||
return $this->handle_response($response);
|
||||
}
|
||||
|
||||
public function status() {
|
||||
$this->autologin();
|
||||
|
||||
$url = $this->api_base_url . 'status';
|
||||
$token = $this->token;
|
||||
|
||||
if (!$token) {
|
||||
return array('error' => 'Unauthorized');
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . ($token),
|
||||
),
|
||||
'method' => 'GET',
|
||||
'timeout' => 5,
|
||||
);
|
||||
|
||||
$response = wp_remote_request($url, $args);
|
||||
|
||||
return $this->handle_response($response);
|
||||
}
|
||||
|
||||
public function variants() {
|
||||
$this->autologin();
|
||||
|
||||
$url = $this->api_base_url . 'variants';
|
||||
$token = $this->token;
|
||||
|
||||
if (!$token) {
|
||||
return array('error' => 'Unauthorized');
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . ($token),
|
||||
),
|
||||
'method' => 'GET',
|
||||
'timeout' => 5,
|
||||
);
|
||||
|
||||
$response = wp_remote_request($url, $args);
|
||||
|
||||
return $this->handle_response($response);
|
||||
}
|
||||
|
||||
public function icons($params) {
|
||||
$this->autologin();
|
||||
|
||||
$url = $this->api_base_url . 'icons';
|
||||
if (!empty($params)) {
|
||||
$query_string = http_build_query($params);
|
||||
$url .= '?' . $query_string;
|
||||
}
|
||||
|
||||
$token = $this->token;
|
||||
|
||||
if (!$token) {
|
||||
return array('error' => 'Unauthorized');
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . ($token),
|
||||
),
|
||||
'method' => 'GET',
|
||||
'timeout' => 5,
|
||||
);
|
||||
|
||||
$response = wp_remote_request($url, $args);
|
||||
|
||||
return $this->handle_response($response);
|
||||
}
|
||||
|
||||
public function track($params) {
|
||||
$this->autologin();
|
||||
|
||||
$url = $this->api_base_url . 'download/track';
|
||||
|
||||
$token = $this->token;
|
||||
|
||||
if (!$token) {
|
||||
return array('error' => 'Unauthorized');
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . ($token),
|
||||
),
|
||||
'body' => json_encode($params),
|
||||
'method' => 'POST',
|
||||
'timeout' => 15,
|
||||
);
|
||||
|
||||
$response = wp_remote_request($url, $args);
|
||||
|
||||
return $this->handle_response($response);
|
||||
}
|
||||
|
||||
private function handle_response($response) {
|
||||
if (is_wp_error($response)) {
|
||||
return array('error' => $response->get_error_message());
|
||||
}
|
||||
|
||||
$body_raw = wp_remote_retrieve_body($response);
|
||||
$headers = wp_remote_retrieve_headers($response)->getAll();
|
||||
$status_code = wp_remote_retrieve_response_code($response);
|
||||
$body = json_decode($body_raw, true);
|
||||
|
||||
if (isset($body['error']) || isset($body['message'])) {
|
||||
return array('error' => $body['message'] ?? $body['error']);
|
||||
}
|
||||
|
||||
return array(
|
||||
'data' => $body,
|
||||
'headers' => $headers,
|
||||
'status_code' => $status_code,
|
||||
);
|
||||
}
|
||||
|
||||
private function __clone() {}
|
||||
|
||||
public function __wakeup() {
|
||||
throw new \Exception("Cannot unserialize singleton");
|
||||
}
|
||||
|
||||
public function __get($property) {
|
||||
if ($property === 'token') {
|
||||
return $this->settings->token ?? null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
29
wp-content/plugins/lordicon/includes/class-constants.php
Normal file
29
wp-content/plugins/lordicon/includes/class-constants.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
namespace Lordicon;
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Constants {
|
||||
const PLUGIN_VERSION = '1.0.0';
|
||||
const PLUGIN_NAME = 'lordicon';
|
||||
const PLUGIN_BASENAME = 'lordicon/lordicon.php';
|
||||
const APP_NAME = 'wp';
|
||||
|
||||
public static function plugin_version() {
|
||||
return self::PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
public static function plugin_name() {
|
||||
return self::PLUGIN_NAME;
|
||||
}
|
||||
|
||||
public static function plugin_basename() {
|
||||
return self::PLUGIN_BASENAME;
|
||||
}
|
||||
|
||||
public static function app_name() {
|
||||
return self::APP_NAME;
|
||||
}
|
||||
}
|
||||
60
wp-content/plugins/lordicon/includes/class-loader.php
Normal file
60
wp-content/plugins/lordicon/includes/class-loader.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Lordicon;
|
||||
|
||||
if (!defined('ABSPATH') ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Loader {
|
||||
protected $actions;
|
||||
protected $filters;
|
||||
protected $shortcodes;
|
||||
|
||||
public function __construct() {
|
||||
$this->actions = array();
|
||||
$this->filters = array();
|
||||
$this->shortcodes = array();
|
||||
}
|
||||
|
||||
public function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
|
||||
$this->actions[] = array(
|
||||
'hook' => $hook,
|
||||
'component' => $component,
|
||||
'callback' => $callback,
|
||||
'priority' => $priority,
|
||||
'accepted_args' => $accepted_args
|
||||
);
|
||||
}
|
||||
|
||||
public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
|
||||
$this->filters[] = array(
|
||||
'hook' => $hook,
|
||||
'component' => $component,
|
||||
'callback' => $callback,
|
||||
'priority' => $priority,
|
||||
'accepted_args' => $accepted_args
|
||||
);
|
||||
}
|
||||
|
||||
public function add_shortcode( $tag, $component, $callback ) {
|
||||
$this->shortcodes[] = array(
|
||||
'tag' => $tag,
|
||||
'component' => $component,
|
||||
'callback' => $callback,
|
||||
);
|
||||
}
|
||||
|
||||
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'] );
|
||||
}
|
||||
|
||||
foreach ($this->shortcodes as $shortcode) {
|
||||
add_shortcode( $shortcode['tag'], array( $shortcode['component'], $shortcode['callback'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
416
wp-content/plugins/lordicon/includes/class-plugin.php
Normal file
416
wp-content/plugins/lordicon/includes/class-plugin.php
Normal file
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
namespace Lordicon;
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
function is_settings() {
|
||||
$screen = get_current_screen();
|
||||
if (!$screen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this screen is a settings page of our plugin
|
||||
// Matches either top-level or submenu pages
|
||||
$menu_slug = 'lordicon-settings';
|
||||
return str_ends_with($screen->id, $menu_slug);
|
||||
}
|
||||
|
||||
class Plugin {
|
||||
private $loader;
|
||||
private $handler;
|
||||
|
||||
public function __construct() {
|
||||
$this->load_dependencies();
|
||||
$this->init();
|
||||
}
|
||||
|
||||
public function run() {
|
||||
$this->loader->run();
|
||||
$this->handler->run();
|
||||
}
|
||||
|
||||
private function load_dependencies() {
|
||||
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-constants.php';
|
||||
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-loader.php';
|
||||
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-api.php';
|
||||
require_once plugin_dir_path(dirname(__FILE__)).'includes/class-ajax-handler.php';
|
||||
}
|
||||
|
||||
private function init() {
|
||||
$this->loader = new Loader();
|
||||
$this->loader->add_filter('upload_mimes', $this, 'allow_lordicon_mimes');
|
||||
$this->loader->add_filter('wp_check_filetype_and_ext', $this, 'check_lordicon_filetype', 10, 4);
|
||||
$this->loader->add_filter('post_mime_types', $this, 'add_json_mime_types');
|
||||
$this->loader->add_filter('wp_prepare_attachment_for_js', $this, 'prepare_json_attachment_for_js', 10, 3);
|
||||
|
||||
if (is_admin()) {
|
||||
$this->loader->add_action('admin_enqueue_scripts', $this, 'enqueue_admin_assets');
|
||||
$this->loader->add_action('enqueue_block_editor_assets', $this, 'enqueue_block_editor_assets');
|
||||
$this->loader->add_action('admin_menu', $this, 'settings_init_menu');
|
||||
$this->loader->add_action('admin_init', $this, 'settings_handle_form_submission');
|
||||
|
||||
$this->loader->add_filter('plugin_row_meta', $this, 'plugin_links', 10, 3);
|
||||
} else {
|
||||
$define_element = apply_filters('lordicon_define_element', true);
|
||||
|
||||
if ($define_element) {
|
||||
$this->loader->add_action('wp_enqueue_scripts', $this, 'enqueue_frontend_assets');
|
||||
}
|
||||
}
|
||||
|
||||
// Block registration (both admin and frontend)
|
||||
$this->loader->add_action('init', $this, 'register_block_type');
|
||||
|
||||
$this->handler = new AjaxHandler();
|
||||
}
|
||||
|
||||
public function enqueue_admin_assets() {
|
||||
if (is_settings()) {
|
||||
wp_enqueue_script(
|
||||
'lordicon-settings-script',
|
||||
plugins_url('/dist/settings.js', dirname(__FILE__)),
|
||||
array(),
|
||||
Constants::plugin_version(),
|
||||
false,
|
||||
);
|
||||
|
||||
wp_enqueue_style(
|
||||
'lordicon-settings-css',
|
||||
plugins_url('/dist/settings.css', dirname(__FILE__)),
|
||||
array(),
|
||||
Constants::plugin_version()
|
||||
);
|
||||
|
||||
$this->patch_module('lordicon-settings-script', 'settings');
|
||||
}
|
||||
}
|
||||
|
||||
public function enqueue_block_editor_assets() {
|
||||
wp_enqueue_script(
|
||||
'lordicon-block-js',
|
||||
plugins_url('/dist/block.js', dirname(__FILE__)),
|
||||
array('wp-blocks', 'wp-element', 'wp-components', 'wp-block-editor', 'wp-i18n'),
|
||||
Constants::plugin_version(),
|
||||
false,
|
||||
);
|
||||
|
||||
wp_enqueue_style(
|
||||
'lordicon-block-css',
|
||||
plugins_url('/dist/block.css', dirname(__FILE__)),
|
||||
array('wp-edit-blocks'),
|
||||
Constants::plugin_version()
|
||||
);
|
||||
|
||||
$this->patch_module('lordicon-block-js', 'editor');
|
||||
}
|
||||
|
||||
public function enqueue_frontend_assets() {
|
||||
wp_enqueue_style(
|
||||
'lordicon-element-style',
|
||||
plugins_url('/dist/element.css', dirname(__FILE__)),
|
||||
array(),
|
||||
Constants::plugin_version()
|
||||
);
|
||||
|
||||
wp_enqueue_script_module(
|
||||
'lordicon-element-script',
|
||||
plugins_url('/dist/element.js', dirname(__FILE__)),
|
||||
array(),
|
||||
Constants::plugin_version(),
|
||||
);
|
||||
}
|
||||
|
||||
private function patch_module(string $scriptHandle, string $context) {
|
||||
$url = admin_url('admin-ajax.php');
|
||||
$nonce = wp_create_nonce('lordicon_action');
|
||||
$status = API::get_instance()->status()['data'];
|
||||
$variants = $status ? API::get_instance()->variants()['data'] : [];
|
||||
|
||||
// Safely get post ID without using $_GET
|
||||
$post_id = 0;
|
||||
if ($context === 'editor') {
|
||||
$post = get_post();
|
||||
if ($post && $post->ID) {
|
||||
$post_id = $post->ID;
|
||||
}
|
||||
}
|
||||
|
||||
$config = [
|
||||
'url' => $url,
|
||||
'nonce' => $nonce,
|
||||
'status' => $status,
|
||||
'variants' => $variants,
|
||||
'postId' => $post_id,
|
||||
'context' => $context,
|
||||
];
|
||||
|
||||
wp_add_inline_script(
|
||||
$scriptHandle,
|
||||
'window.__LORDICON__ = ' . wp_json_encode($config) . ';',
|
||||
'after'
|
||||
);
|
||||
|
||||
// Patch the script tag to use type="module"
|
||||
add_filter('script_loader_tag', function ($tag, $handle, $src) use ($scriptHandle) {
|
||||
if ($scriptHandle !== $handle) return $tag;
|
||||
|
||||
$search = sprintf('id="%s-js"', $scriptHandle);
|
||||
$replace = $search . ' type="module"';
|
||||
return str_replace($search, $replace, $tag);
|
||||
}, 10, 3);
|
||||
}
|
||||
|
||||
public function register_block_type() {
|
||||
register_block_type(dirname(__DIR__) . '/dist/block.json', array(
|
||||
'render_callback' => array($this, 'render_block'),
|
||||
));
|
||||
}
|
||||
|
||||
public function settings_init_menu() {
|
||||
add_options_page(
|
||||
'Lordicon Settings',
|
||||
'Lordicon',
|
||||
'manage_options',
|
||||
'lordicon-settings',
|
||||
array($this, 'render_settings'),
|
||||
);
|
||||
}
|
||||
|
||||
public function settings_handle_form_submission() {
|
||||
// Check if form is submitted
|
||||
if ( ! isset( $_POST['lordicon_settings'], $_POST['lordicon_nonce'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize nonce
|
||||
$nonce = sanitize_text_field( wp_unslash( $_POST['lordicon_nonce'] ) );
|
||||
if ( ! wp_verify_nonce( $nonce, 'lordicon_settings_action' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize settings
|
||||
$settings = array_map( 'sanitize_text_field', (array) wp_unslash( $_POST['lordicon_settings'] ) );
|
||||
|
||||
// Save settings
|
||||
update_option( 'lordicon_settings', $settings );
|
||||
|
||||
// Message
|
||||
add_settings_error(
|
||||
'lordicon_settings',
|
||||
'settings_updated',
|
||||
'Settings saved.',
|
||||
'updated'
|
||||
);
|
||||
}
|
||||
|
||||
public function plugin_links($plugin_links, $plugin_file, $plugin_data) {
|
||||
$links = array();
|
||||
if (isset($plugin_data['AuthorName']) && $plugin_data['AuthorName'] == 'Lordicon') {
|
||||
$links = array(
|
||||
'<a href="' . admin_url('options-general.php?page=lordicon-settings') . '">Settings</a>',
|
||||
);
|
||||
}
|
||||
return array_merge($plugin_links, $links);
|
||||
}
|
||||
|
||||
public function allow_lordicon_mimes($mimes) {
|
||||
if (!isset($mimes['json'])) {
|
||||
$mimes['json'] = 'application/json';
|
||||
}
|
||||
if (!isset($mimes['svg'])) {
|
||||
$mimes['svg'] = 'image/svg+xml';
|
||||
}
|
||||
return $mimes;
|
||||
}
|
||||
|
||||
public function add_json_mime_types($mime_types) {
|
||||
$mime_types['application/json'] = array(
|
||||
__('Lordicon Files', 'lordicon'),
|
||||
__('Manage Lordicon Files', 'lordicon'),
|
||||
// translators: %s is the number of Lordicon files
|
||||
_n_noop('Lordicon File <span class="count">(%s)</span>', 'Lordicon Files <span class="count">(%s)</span>', 'lordicon'),
|
||||
);
|
||||
|
||||
return $mime_types;
|
||||
}
|
||||
|
||||
public function prepare_json_attachment_for_js($response, $attachment, $meta) {
|
||||
if ($response['mime'] === 'application/json') {
|
||||
$response['icon'] = plugins_url('assets/lordicon-icon.png', dirname(__FILE__));
|
||||
|
||||
if (get_post_meta($attachment->ID, '_lordicon_type', true) === 'json') {
|
||||
$response['subtype'] = 'lordicon-json';
|
||||
$response['title'] = $response['title'];
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function check_lordicon_filetype($data, $file, $filename, $mimes) {
|
||||
if (substr($filename, -5) === '.json') {
|
||||
$data['ext'] = 'json';
|
||||
$data['type'] = 'application/json';
|
||||
}
|
||||
if (substr($filename, -4) === '.svg') {
|
||||
$data['ext'] = 'svg';
|
||||
$data['type'] = 'image/svg+xml';
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function render_block( $attributes, $content ) {
|
||||
$icon = $attributes['icon'] ?? null;
|
||||
$json_attachment_id = isset( $attributes['jsonAttachmentId'] ) ? intval( $attributes['jsonAttachmentId'] ) : 0;
|
||||
$svg_attachment_id = isset( $attributes['svgAttachmentId'] ) ? intval( $attributes['svgAttachmentId'] ) : 0;
|
||||
$anchor = $attributes['anchor'] ?? '';
|
||||
$class_name = $attributes['className'] ?? '';
|
||||
$display = $attributes['properties']['display'] ?? 'block';
|
||||
$format = $attributes['properties']['format'] ?? 'json';
|
||||
|
||||
if ( ! $icon ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$json_src = $json_attachment_id ? wp_get_attachment_url( $json_attachment_id ) : '';
|
||||
$svg_src = $svg_attachment_id ? wp_get_attachment_url( $svg_attachment_id ) : '';
|
||||
|
||||
// Classes
|
||||
$css_classes = [ 'lordicon-wrapper' ];
|
||||
if ( 'block' !== $display ) {
|
||||
$css_classes[] = 'lordicon-wrapper-' . sanitize_html_class( $display );
|
||||
}
|
||||
if ( ! empty( $class_name ) ) {
|
||||
$css_classes[] = sanitize_html_class( $class_name );
|
||||
}
|
||||
$class_attr = esc_attr( implode( ' ', $css_classes ) );
|
||||
|
||||
// ID (anchor)
|
||||
$id_attr = '';
|
||||
if ( ! empty( $anchor ) ) {
|
||||
$id_attr = ' id="' . esc_attr( $anchor ) . '"';
|
||||
}
|
||||
|
||||
// Prepare <lord-icon> attributes as key => value (value true means boolean attr)
|
||||
$lord_icon_attrs = [];
|
||||
|
||||
if ( $json_src ) {
|
||||
$lord_icon_attrs['src'] = esc_url( $json_src );
|
||||
|
||||
// trigger
|
||||
$allowed_triggers = [ 'in', 'hover', 'click', 'loop', 'morph' ];
|
||||
$trigger = 'hover';
|
||||
if ( ! empty( $attributes['properties']['state'] ) ) {
|
||||
$state_parts = explode( '-', $attributes['properties']['state'] );
|
||||
$potential_trigger = $state_parts[0] ?? '';
|
||||
if ( in_array( $potential_trigger, $allowed_triggers, true ) ) {
|
||||
$trigger = $potential_trigger;
|
||||
}
|
||||
}
|
||||
$lord_icon_attrs['trigger'] = $trigger;
|
||||
|
||||
// size -> style attribute
|
||||
if ( ! empty( $attributes['properties']['size'] ) && intval( $attributes['properties']['size'] ) > 0 ) {
|
||||
$size_val = intval( $attributes['properties']['size'] );
|
||||
$lord_icon_attrs['style'] = "width:{$size_val}px;height:{$size_val}px;";
|
||||
}
|
||||
|
||||
// stroke
|
||||
if ( isset( $attributes['properties']['stroke'] ) && $attributes['properties']['stroke'] !== 2 ) {
|
||||
$lord_icon_attrs['stroke'] = (string) $attributes['properties']['stroke'];
|
||||
}
|
||||
|
||||
// colors (name:value,name:value)
|
||||
if ( ! empty( $attributes['properties']['colors'] ) && is_array( $attributes['properties']['colors'] ) ) {
|
||||
$color_pairs = [];
|
||||
foreach ( $attributes['properties']['colors'] as $name => $value ) {
|
||||
$color_pairs[] = sanitize_key( (string) $name ) . ':' . sanitize_text_field( (string) $value );
|
||||
}
|
||||
$lord_icon_attrs['colors'] = implode( ',', $color_pairs );
|
||||
}
|
||||
|
||||
// state
|
||||
if ( ! empty( $attributes['properties']['state'] ) ) {
|
||||
$lord_icon_attrs['state'] = sanitize_text_field( $attributes['properties']['state'] );
|
||||
}
|
||||
|
||||
// speed (float with dot)
|
||||
if ( isset( $attributes['properties']['speed'] ) ) {
|
||||
$lord_icon_attrs['speed'] = number_format( floatval( $attributes['properties']['speed'] ), 2, '.', '' );
|
||||
}
|
||||
|
||||
// target
|
||||
if ( ! empty( $attributes['properties']['target'] ) ) {
|
||||
$lord_icon_attrs['target'] = sanitize_text_field( $attributes['properties']['target'] );
|
||||
}
|
||||
|
||||
// sequence (forces trigger=sequence)
|
||||
if ( ! empty( $attributes['properties']['sequence'] ) ) {
|
||||
$lord_icon_attrs['sequence'] = sanitize_text_field( $attributes['properties']['sequence'] );
|
||||
$lord_icon_attrs['trigger'] = 'sequence';
|
||||
}
|
||||
|
||||
// intro (boolean attribute)
|
||||
$has_intro = ! empty( $attributes['properties']['intro'] ) && true === $attributes['properties']['intro'];
|
||||
|
||||
// loading policy
|
||||
$lord_icon_attrs['loading'] = ( ! empty( $svg_src ) && ! $has_intro ) ? 'interaction' : 'lazy';
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="<?php echo esc_attr( implode( ' ', $css_classes ) ); ?>"<?php echo ! empty( $anchor ) ? ' id="' . esc_attr( $anchor ) . '"' : ''; ?>>
|
||||
<?php if ( $json_src ) : ?>
|
||||
<lord-icon
|
||||
<?php foreach ( $lord_icon_attrs as $attr => $value ) : ?>
|
||||
<?php
|
||||
if ( is_bool( $value ) && $value ) {
|
||||
echo ' ' . esc_attr( $attr );
|
||||
} else {
|
||||
echo ' ' . esc_attr( $attr ) . '="' . esc_attr( (string) $value ) . '"';
|
||||
}
|
||||
?>
|
||||
<?php endforeach; ?>
|
||||
<?php if ( $has_intro ) : ?>
|
||||
<?php echo ' ' . esc_attr( 'intro' ); ?>
|
||||
<?php endif; ?>
|
||||
>
|
||||
<?php if ( $svg_src && ! $has_intro ) : ?>
|
||||
<img src="<?php echo esc_url( $svg_src ); ?>" alt="" loading="lazy" />
|
||||
<?php endif; ?>
|
||||
</lord-icon>
|
||||
<?php elseif ( 'svg' === $format && $svg_src ) : ?>
|
||||
<img src="<?php echo esc_url( $svg_src ); ?>"
|
||||
<?php if ( ! empty( $attributes['properties']['size'] ) && intval( $attributes['properties']['size'] ) > 0 ) : ?>
|
||||
style="width:<?php echo intval( $attributes['properties']['size'] ); ?>px;height:<?php echo intval( $attributes['properties']['size'] ); ?>px;"
|
||||
<?php endif; ?>
|
||||
/>
|
||||
<?php else : ?>
|
||||
<div class="lordicon-info">
|
||||
<p>
|
||||
<?php
|
||||
$label = sprintf(
|
||||
'%s-%s-%s-%s',
|
||||
$icon['family'] ?? '',
|
||||
$icon['style'] ?? '',
|
||||
$icon['index'] ?? '',
|
||||
$icon['name'] ?? ''
|
||||
);
|
||||
echo esc_html( sprintf( 'Icon unavailable: %s. Edit this block and choose a new icon.', $label ) );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public function render_settings() {
|
||||
?>
|
||||
<div id="lordicon"></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user