416 lines
15 KiB
PHP
416 lines
15 KiB
PHP
<?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
|
|
}
|
|
}
|