Hotel Raxa - Advanced Booking System Implementation
🏨 Hotel Booking Enhancements: - Implemented Eagle Booking Advanced Pricing add-on - Added Booking.com-style rate management system - Created professional calendar interface for pricing - Integrated deals and discounts functionality 💰 Advanced Pricing Features: - Dynamic pricing models (per room, per person, per adult) - Base rates, adult rates, and child rates management - Length of stay discounts and early bird deals - Mobile rates and secret deals implementation - Seasonal promotions and flash sales 📅 Availability Management: - Real-time availability tracking - Stop sell and restriction controls - Closed to arrival/departure functionality - Minimum/maximum stay requirements - Automatic sold-out management 💳 Payment Integration: - Maintained Redsys payment gateway integration - Seamless integration with existing Eagle Booking - No modifications to core Eagle Booking plugin 🛠️ Technical Implementation: - Custom database tables for advanced pricing - WordPress hooks and filters integration - AJAX-powered admin interface - Data migration from existing Eagle Booking - Professional calendar view for revenue management 📊 Admin Interface: - Booking.com-style management dashboard - Visual rate and availability calendar - Bulk operations for date ranges - Statistics and analytics dashboard - Modal dialogs for quick editing 🔧 Code Quality: - WordPress coding standards compliance - Secure database operations with prepared statements - Proper input validation and sanitization - Error handling and logging - Responsive admin interface 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,909 @@
|
||||
<?php
|
||||
/**
|
||||
* Redux Custom Font Extension Class
|
||||
*
|
||||
* @package Redux
|
||||
* @author Kevin Provance <kevin.provance@gmail.com> & Dovy Paukstys <dovy@reduxframework.com>
|
||||
* @class Redux_Extension_Custom_Fonts
|
||||
* @version 4.4.2
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
if ( ! class_exists( 'Redux_Extension_Custom_Fonts' ) ) {
|
||||
|
||||
/**
|
||||
* Class Redux_Extension_Custom_Fonts
|
||||
*/
|
||||
class Redux_Extension_Custom_Fonts extends Redux_Extension_Abstract {
|
||||
|
||||
/**
|
||||
* Extension version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $version = '4.4.2';
|
||||
|
||||
/**
|
||||
* Extension friendly name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $ext_name = 'Custom Fonts';
|
||||
|
||||
/**
|
||||
* Custom fonts array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $custom_fonts = array();
|
||||
|
||||
/**
|
||||
* WordPress upload directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $upload_dir = '';
|
||||
|
||||
/**
|
||||
* WordPress upload URI.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $upload_url = '';
|
||||
|
||||
/**
|
||||
* Extension instance.
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
public static $instance = null;
|
||||
|
||||
/**
|
||||
* Is font conversation service available?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $can_convert;
|
||||
|
||||
/**
|
||||
* Class Constructor. Defines the args for the extensions class
|
||||
*
|
||||
* @param object $redux ReduxFramework pointer.
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function __construct( $redux ) {
|
||||
parent::__construct( $redux, __FILE__ );
|
||||
|
||||
self::$instance = parent::get_instance();
|
||||
|
||||
$this->add_field( 'custom_fonts' );
|
||||
|
||||
$this->upload_dir = Redux_Core::$upload_dir . 'custom-fonts/';
|
||||
$this->upload_url = Redux_Core::$upload_url . 'custom-fonts/';
|
||||
|
||||
if ( ! is_dir( $this->upload_dir ) ) {
|
||||
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir );
|
||||
}
|
||||
|
||||
if ( ! is_dir( $this->upload_dir . '/custom' ) ) {
|
||||
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir . '/custom' );
|
||||
}
|
||||
|
||||
$this->get_fonts();
|
||||
|
||||
if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
|
||||
if ( filemtime( $this->upload_dir . 'custom' ) > ( filemtime( $this->upload_dir . 'fonts.css' ) + 10 ) ) {
|
||||
$this->generate_css();
|
||||
}
|
||||
} else {
|
||||
$this->generate_css();
|
||||
}
|
||||
|
||||
add_action( 'wp_ajax_redux_custom_fonts', array( $this, 'ajax' ) );
|
||||
add_action( 'wp_ajax_redux_custom_font_timer', array( $this, 'timer' ) );
|
||||
|
||||
add_filter( "redux/{$this->parent->args['opt_name']}/field/typography/custom_fonts", array( $this, 'add_custom_fonts' ) );
|
||||
|
||||
// phpcs:disable
|
||||
// $this->is_field = Redux_Helpers::is_field_in_use( $parent, 'custom_fonts' );
|
||||
|
||||
// if ( ! $this->is_field ) {
|
||||
// $this->add_section();
|
||||
// }
|
||||
|
||||
add_filter( "redux/options/{$this->parent->args['opt_name']}/section/redux_dynamic_font_control", array( $this, 'remove_dynamic_section' ) ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
|
||||
add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
|
||||
add_action( 'wp_head', array( $this, 'enqueue_output' ), 150 );
|
||||
add_filter( 'tiny_mce_before_init', array( $this, 'extend_tinymce_dropdown' ) );
|
||||
|
||||
$this->can_convert = true; // has_filter( 'redux/' . $this->parent->args['opt_name'] . '/extensions/custom_fonts/api_url' );
|
||||
// phpcs:enable
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer.
|
||||
*/
|
||||
public function timer() {
|
||||
$name = get_option( 'redux_custom_font_current' );
|
||||
|
||||
if ( ! empty( $name ) ) {
|
||||
echo esc_html( $name );
|
||||
}
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the dynamically added section if the field was used elsewhere
|
||||
*
|
||||
* @param array $section Section array.
|
||||
*
|
||||
* @return array
|
||||
* @since Redux_Framework 3.1.1
|
||||
*/
|
||||
public function remove_dynamic_section( array $section ): array {
|
||||
if ( isset( $this->parent->field_types['custom_fonts'] ) ) {
|
||||
$section = array();
|
||||
}
|
||||
|
||||
return $section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds FontMeister fonts to the TinyMCE drop-down.
|
||||
* Typekit's fonts don't render properly in the drop-down and in the editor,
|
||||
* because Typekit needs JS and TinyMCE doesn't support that.
|
||||
*
|
||||
* @param array $opt Option array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function extend_tinymce_dropdown( array $opt ): array {
|
||||
if ( ! is_admin() ) {
|
||||
return $opt;
|
||||
}
|
||||
|
||||
if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
|
||||
$theme_advanced_fonts = $opt['font_formats'] ?? 'Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats';
|
||||
$custom_fonts = '';
|
||||
|
||||
$stylesheet = $this->upload_url . 'fonts.css';
|
||||
|
||||
if ( empty( $opt['content_css'] ) ) {
|
||||
$opt['content_css'] = $stylesheet;
|
||||
} else {
|
||||
$opt['content_css'] = $opt['content_css'] . ',' . $stylesheet;
|
||||
}
|
||||
|
||||
foreach ( $this->custom_fonts as $arr ) {
|
||||
foreach ( $arr as $font => $pieces ) {
|
||||
$custom_fonts .= ';' . $font . '=' . $font;
|
||||
}
|
||||
}
|
||||
|
||||
$opt['font_formats'] = $theme_advanced_fonts . $custom_fonts;
|
||||
}
|
||||
|
||||
return $opt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to enqueue the custom fonts css
|
||||
*/
|
||||
public function enqueue_output() {
|
||||
if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
|
||||
wp_enqueue_style(
|
||||
'redux-custom-fonts',
|
||||
$this->upload_url . 'fonts.css',
|
||||
array(),
|
||||
time()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the appropriate mime types to WordPress
|
||||
*
|
||||
* @param array $existing_mimes Mine array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function custom_upload_mimes( array $existing_mimes = array() ): array {
|
||||
$existing_mimes['ttf'] = 'font/ttf';
|
||||
$existing_mimes['otf'] = 'font/otf';
|
||||
$existing_mimes['eot'] = 'application/vnd.ms-fontobject';
|
||||
$existing_mimes['woff'] = 'application/font-woff';
|
||||
$existing_mimes['woff2'] = 'application/font-woff2';
|
||||
$existing_mimes['svg'] = 'image/svg+xml';
|
||||
$existing_mimes['zip'] = 'application/zip';
|
||||
|
||||
return $existing_mimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the fonts in the custom_fonts directory
|
||||
*/
|
||||
public function get_fonts() {
|
||||
if ( empty( $this->custom_fonts ) ) {
|
||||
$params = array(
|
||||
'include_hidden' => false,
|
||||
'recursive' => true,
|
||||
);
|
||||
|
||||
$fonts = $this->parent->filesystem->execute( 'dirlist', $this->upload_dir, $params );
|
||||
|
||||
if ( ! empty( $fonts ) ) {
|
||||
foreach ( $fonts as $section ) {
|
||||
if ( 'd' === $section['type'] && ! empty( $section['name'] ) ) {
|
||||
if ( 'custom' === $section['name'] ) {
|
||||
$section['name'] = esc_html__( 'Custom Fonts', 'redux-framework' );
|
||||
}
|
||||
|
||||
if ( empty( $section['files'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->custom_fonts[ $section['name'] ] = $this->custom_fonts[ $section['name'] ] ?? array();
|
||||
|
||||
foreach ( $section['files'] as $font ) {
|
||||
if ( ! empty( $font['name'] ) ) {
|
||||
if ( empty( $font['files'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$kinds = array();
|
||||
|
||||
foreach ( $font['files'] as $f ) {
|
||||
$valid = $this->check_font_name( $f );
|
||||
if ( $valid ) {
|
||||
$kinds[] = $valid;
|
||||
}
|
||||
}
|
||||
|
||||
$this->custom_fonts[ $section['name'] ][ $font['name'] ] = $kinds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom fonts.
|
||||
*
|
||||
* @param mixed $custom_fonts Custom fonts.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_custom_fonts( $custom_fonts ): array {
|
||||
if ( empty( $custom_fonts ) ) {
|
||||
$custom_fonts = array();
|
||||
}
|
||||
|
||||
return wp_parse_args( $custom_fonts, $this->custom_fonts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax used within the panel to add and process the fonts
|
||||
*/
|
||||
public function ajax() {
|
||||
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_custom_fonts' ) ) {
|
||||
die( 0 );
|
||||
}
|
||||
|
||||
if ( isset( $_POST['type'] ) && 'delete' === $_POST['type'] ) {
|
||||
if ( isset( $_POST['section'] ) ) {
|
||||
if ( esc_html__( 'Custom Fonts', 'redux-framework' ) === $_POST['section'] ) {
|
||||
$_POST['section'] = 'custom';
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if ( isset( $_POST['section'] ) || isset( $_POST['name'] ) ) {
|
||||
$this->parent->filesystem->execute( 'rmdir', $this->upload_dir . sanitize_title( wp_unslash( $_POST['section'] ) ) . '/' . sanitize_title( wp_unslash( $_POST['name'] ) ) . '/', array( 'recursive' => true ) );
|
||||
|
||||
$result = array( 'type' => 'success' );
|
||||
|
||||
echo wp_json_encode( $result );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'msg' => esc_html__( 'Unable to delete font file(s).', 'redux-framework' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
if ( ! isset( $_POST['title'] ) ) {
|
||||
$_POST['title'] = '';
|
||||
}
|
||||
|
||||
if ( ! isset( $_POST['filename'] ) ) {
|
||||
$_POST['filename'] = '';
|
||||
}
|
||||
|
||||
if ( ! empty( $_POST['attachment_id'] ) ) {
|
||||
if ( isset( $_POST['title'] ) || isset( $_POST['mime'] ) ) {
|
||||
$msg = $this->process_web_font( sanitize_key( wp_unslash( $_POST['attachment_id'] ) ), sanitize_text_field( wp_unslash( $_POST['title'] ) ), sanitize_text_field( wp_unslash( $_POST['filename'] ) ), sanitize_text_field( wp_unslash( $_POST['mime'] ) ) );
|
||||
|
||||
if ( empty( $msg ) ) {
|
||||
$msg = '';
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'type' => 'success',
|
||||
'msg' => $msg,
|
||||
);
|
||||
|
||||
echo wp_json_encode( $result );
|
||||
}
|
||||
}
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get only valid files. Ensure everything is proper for processing.
|
||||
*
|
||||
* @param string $path Path.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_valid_files( string $path ): array {
|
||||
$output = array();
|
||||
$path = trailingslashit( $path );
|
||||
|
||||
$params = array(
|
||||
'include_hidden' => false,
|
||||
'recursive' => true,
|
||||
);
|
||||
|
||||
$files = $this->parent->filesystem->execute( 'dirlist', $path, $params );
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
if ( 'd' === $file['type'] ) {
|
||||
$output = array_merge( $output, $this->get_valid_files( $path . $file['name'] ) );
|
||||
} elseif ( 'f' === $file['type'] ) {
|
||||
$valid = $this->check_font_name( $file );
|
||||
if ( $valid ) {
|
||||
$output[ $valid ] = trailingslashit( $path ) . $file['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a valid web font and process the missing pieces.
|
||||
*
|
||||
* @param string $attachment_id ID.
|
||||
* @param string $name Name.
|
||||
* @param string $true_filename Filename.
|
||||
* @param string $mime_type Mine type.
|
||||
*/
|
||||
public function process_web_font( string $attachment_id, string $name, string $true_filename, string $mime_type ) {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( ! isset( $_POST['conversion'] ) ) {
|
||||
$_POST['conversion'] = 'false';
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$conversion = sanitize_text_field( wp_unslash( $_POST['conversion'] ) );
|
||||
|
||||
$missing = array();
|
||||
|
||||
$complete = array(
|
||||
'ttf',
|
||||
'woff',
|
||||
'woff2',
|
||||
'eot',
|
||||
'svg',
|
||||
'otf',
|
||||
);
|
||||
|
||||
$subfolder = 'custom/';
|
||||
$subtype = explode( '/', $mime_type );
|
||||
$subtype = trim( max( $subtype ) );
|
||||
|
||||
if ( ! is_dir( $this->upload_dir ) ) {
|
||||
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir );
|
||||
}
|
||||
|
||||
if ( ! is_dir( $this->upload_dir . $subfolder ) ) {
|
||||
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir . $subfolder );
|
||||
}
|
||||
|
||||
$temp = $this->upload_dir . 'temp';
|
||||
$path = get_attached_file( $attachment_id );
|
||||
|
||||
if ( empty( $path ) ) {
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'msg' => esc_html__( 'Attachment does not exist.', 'redux-framework' ),
|
||||
)
|
||||
);
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
$filename = explode( '/', $path );
|
||||
|
||||
$filename = $filename[ ( count( $filename ) - 1 ) ];
|
||||
|
||||
$fontname = ucfirst(
|
||||
str_replace(
|
||||
array(
|
||||
'.zip',
|
||||
'.ttf',
|
||||
'.woff',
|
||||
'.woff2',
|
||||
'.eot',
|
||||
'.svg',
|
||||
'.otf',
|
||||
),
|
||||
'',
|
||||
strtolower( $filename )
|
||||
)
|
||||
);
|
||||
|
||||
if ( empty( $name ) ) {
|
||||
$name = $fontname;
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
|
||||
if ( ! is_dir( $temp ) ) {
|
||||
$this->parent->filesystem->execute( 'mkdir', $temp );
|
||||
}
|
||||
|
||||
if ( 'zip' === $subtype ) {
|
||||
$unzipfile = unzip_file( $path, $temp );
|
||||
|
||||
if ( is_wp_error( $unzipfile ) ) {
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'msg' => $unzipfile->get_error_message() . '<br><br>' . esc_html__( 'Unzipping failed.', 'redux-framework' ),
|
||||
)
|
||||
);
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
$output = $this->get_valid_files( $temp );
|
||||
|
||||
if ( ! empty( $output ) ) {
|
||||
foreach ( $complete as $test ) {
|
||||
if ( ! isset( $output[ $test ] ) ) {
|
||||
$missing[] = $test;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! is_dir( $this->upload_dir . $subfolder . $name . '/' ) ) {
|
||||
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir . $subfolder . $name . '/' );
|
||||
}
|
||||
|
||||
foreach ( $output as $key => $value ) {
|
||||
$param_array = array(
|
||||
'destination' => $this->upload_dir . $subfolder . $name . '/' . $fontname . '.' . $key,
|
||||
'overwrite' => true,
|
||||
'chmod' => 755,
|
||||
);
|
||||
|
||||
$this->parent->filesystem->execute( 'copy', $value, $param_array );
|
||||
}
|
||||
|
||||
if ( true === $this->can_convert && 'true' === $conversion ) {
|
||||
$ret = $this->get_missing_files( $name, $fontname, $missing, $output, $subfolder, $true_filename );
|
||||
}
|
||||
}
|
||||
|
||||
$this->parent->filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
|
||||
|
||||
$this->generate_css();
|
||||
|
||||
wp_delete_attachment( $attachment_id, true );
|
||||
} elseif ( 'svg+xml' === $subtype || 'vnd.ms-fontobject' === $subtype || 'x-font-ttf' === $subtype || 'ttf' === $subtype || 'otf' === $subtype || 'font-woff' === $subtype || 'font-woff2' === $subtype || 'application-octet-stream' === $subtype || 'octet-stream' === $subtype ) {
|
||||
foreach ( $complete as $test ) {
|
||||
if ( $subtype !== $test ) {
|
||||
if ( ! isset( $output[ $test ] ) ) {
|
||||
$missing[] = $test;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! is_dir( $this->upload_dir . $subfolder . $name . '/' ) ) {
|
||||
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir . $subfolder . $name . '/' );
|
||||
}
|
||||
|
||||
$output = array( $subtype => $path );
|
||||
|
||||
// TODO: COnversion error not moving single file.
|
||||
if ( true === $this->can_convert && 'true' === $conversion ) {
|
||||
$ret = $this->get_missing_files( $name, $fontname, $missing, $output, $subfolder, $true_filename );
|
||||
} else {
|
||||
$param_array = array(
|
||||
'destination' => $this->upload_dir . $subfolder . '/' . $name . '/' . $true_filename, // $fontname . '.' . $subtype,
|
||||
'overwrite' => true,
|
||||
'chmod' => 755,
|
||||
);
|
||||
|
||||
$this->parent->filesystem->execute( 'copy', $path, $param_array );
|
||||
}
|
||||
|
||||
$this->parent->filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
|
||||
|
||||
$this->generate_css();
|
||||
|
||||
wp_delete_attachment( $attachment_id, true );
|
||||
} else {
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'msg' => esc_html__( 'File type not recognized.', 'redux-framework' ) . ' ' . $subtype,
|
||||
)
|
||||
);
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
if ( is_array( $ret ) && ! empty( $ret ) ) {
|
||||
$msg = esc_html__( 'Unidentified error.', 'redux-framework' );
|
||||
|
||||
if ( isset( $ret['msg'] ) ) {
|
||||
$msg = $ret['msg'];
|
||||
}
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ping the WebFontOMatic API to get the missing files.
|
||||
*
|
||||
* @param string $name Name.
|
||||
* @param string $fontname Font name.
|
||||
* @param array $missing Missing.
|
||||
* @param array $output Output.
|
||||
* @param string $subfolder Folder.
|
||||
* @param string $true_filename Font name with extension.
|
||||
*/
|
||||
private function get_missing_files( string $name, string $fontname, array $missing, array $output, string $subfolder, string $true_filename ) {
|
||||
if ( ! empty( $name ) && ! empty( $missing ) ) {
|
||||
$temp = $this->upload_dir . 'temp';
|
||||
|
||||
$font_ext = pathinfo( $true_filename, PATHINFO_EXTENSION );
|
||||
|
||||
$unsupported = array( 'eot', 'woff', 'woff2' );
|
||||
|
||||
// Find a file to convert from.
|
||||
foreach ( $output as $key => $value ) {
|
||||
if ( 'eot' === $key ) {
|
||||
continue;
|
||||
} else {
|
||||
$main = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset( $main ) ) {
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'msg' => esc_html__( 'No valid font file was found.', 'redux-framework' ),
|
||||
)
|
||||
);
|
||||
|
||||
$this->parent->filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
|
||||
$this->parent->filesystem->execute( 'rmdir', $this->upload_dir . $subfolder . $name . '/', array( 'recursive' => true ) );
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
update_option( 'redux_custom_font_current', $name . '.zip' );
|
||||
|
||||
$boundary = wp_generate_password( 24 );
|
||||
|
||||
$headers = array(
|
||||
'content-type' => 'multipart/form-data; boundary=' . $boundary,
|
||||
'user-agent' => 'redux-custom-fonts-' . self::$version . ' using ' . wp_get_theme(),
|
||||
);
|
||||
|
||||
$payload = '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="md5"' . "\r\n\r\n";
|
||||
$payload .= md5( 'redux_custom_font' );
|
||||
$payload .= "\r\n";
|
||||
|
||||
if ( $output[ $main ] ) {
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="convert"; filename="' . basename( $output[ $main ] ) . '"' . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= $this->parent->filesystem->execute( 'get_contents', $output[ $main ] );
|
||||
$payload .= "\r\n";
|
||||
}
|
||||
|
||||
$payload .= '--' . $boundary . '--';
|
||||
|
||||
$args = array(
|
||||
'headers' => $headers,
|
||||
'body' => $payload,
|
||||
'user-agent' => $headers['user-agent'],
|
||||
'timeout' => 300,
|
||||
'sslverify' => true,
|
||||
);
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidHookName
|
||||
$api_url = apply_filters( 'redux/' . $this->parent->args['opt_name'] . '/extensions/custom_fonts/api_url', 'https://redux.io/fonts' );
|
||||
|
||||
$response = wp_remote_post( $api_url, $args );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return array(
|
||||
'type' => 'error',
|
||||
'msg' => $response->get_error_message() . '<br><br>' . esc_html__( 'Your font could not be converted at this time. Please try again later.', 'redux-framework' ),
|
||||
);
|
||||
} elseif ( null !== json_decode( $response['body'] ) ) {
|
||||
return json_decode( $response['body'], true );
|
||||
}
|
||||
|
||||
$param_array = array(
|
||||
'content' => $response['body'],
|
||||
'overwrite' => true,
|
||||
'chmod' => FS_CHMOD_FILE,
|
||||
);
|
||||
|
||||
$zip_file = $temp . DIRECTORY_SEPARATOR . $fontname . '.zip';
|
||||
|
||||
$ret = $this->parent->filesystem->execute( 'put_contents', $zip_file, $param_array );
|
||||
|
||||
$zip = unzip_file( $zip_file, $temp );
|
||||
|
||||
if ( ! is_wp_error( $zip ) ) {
|
||||
$params = array(
|
||||
'include_hidden' => false,
|
||||
'recursive' => false,
|
||||
);
|
||||
|
||||
$files = $this->parent->filesystem->execute( 'dirlist', $temp . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR, $params );
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
$param_array = array(
|
||||
'destination' => $this->upload_dir . $subfolder . $name . DIRECTORY_SEPARATOR . $file['name'],
|
||||
'overwrite' => true,
|
||||
'chmod' => 755,
|
||||
);
|
||||
|
||||
$this->parent->filesystem->execute( 'move', $temp . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR . $file['name'], $param_array );
|
||||
}
|
||||
} else {
|
||||
$path_parts = pathinfo( $output[ $main ] );
|
||||
|
||||
$param_array = array(
|
||||
'destination' => $this->upload_dir . $subfolder . $name . DIRECTORY_SEPARATOR . $path_parts['basename'],
|
||||
'overwrite' => true,
|
||||
'chmod' => 755,
|
||||
);
|
||||
|
||||
$this->parent->filesystem->execute( 'move', $output[ $main ], $param_array );
|
||||
|
||||
if ( in_array( $font_ext, $unsupported, true ) ) {
|
||||
return array(
|
||||
'type' => 'error',
|
||||
// translators: %s = font extension.
|
||||
'msg' => $zip->get_error_message() . '<br><br>' . sprintf( esc_html__( 'The font converter does not support %s fonts.', 'redux-framework' ), $font_ext ),
|
||||
);
|
||||
} else {
|
||||
return array(
|
||||
'type' => 'error',
|
||||
'msg' => $zip->get_error_message() . '<br><br>' . esc_html__( 'ZIP error. Your font could not be converted at this time. Please try again later.', 'redux-framework' ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
delete_option( 'redux_custom_font_current' );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file name is a valid font file.
|
||||
*
|
||||
* @param array $file File.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function check_font_name( array $file ) {
|
||||
if ( '.woff' === strtolower( substr( $file['name'], - 5 ) ) ) {
|
||||
return 'woff';
|
||||
}
|
||||
|
||||
if ( '.woff2' === strtolower( substr( $file['name'], - 6 ) ) ) {
|
||||
return 'woff2';
|
||||
}
|
||||
|
||||
$sub = strtolower( substr( $file['name'], - 4 ) );
|
||||
|
||||
if ( '.ttf' === $sub ) {
|
||||
return 'ttf';
|
||||
}
|
||||
|
||||
if ( '.eot' === $sub ) {
|
||||
return 'eot';
|
||||
}
|
||||
|
||||
if ( '.svg' === $sub ) {
|
||||
return 'svg';
|
||||
}
|
||||
|
||||
if ( '.otf' === $sub ) {
|
||||
return 'otf';
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new custom CSS file for enqueuing on the frontend and backend.
|
||||
*/
|
||||
private function generate_css() {
|
||||
$params = array(
|
||||
'include_hidden' => false,
|
||||
'recursive' => true,
|
||||
);
|
||||
|
||||
$fonts = $this->parent->filesystem->execute( 'dirlist', $this->upload_dir . 'custom/', $params );
|
||||
|
||||
if ( empty( $fonts ) || ! is_array( $fonts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $fonts as $font ) {
|
||||
if ( 'd' === $font['type'] ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
|
||||
$this->parent->filesystem->execute( 'delete', $this->upload_dir . 'fonts.css' );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$css = '';
|
||||
|
||||
foreach ( $fonts as $font ) {
|
||||
if ( 'd' === $font['type'] ) {
|
||||
$css .= $this->generate_font_css( $font['name'], $this->upload_dir . 'custom/' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( '' !== $css ) {
|
||||
$param_array = array(
|
||||
'content' => $css,
|
||||
'chmod' => FS_CHMOD_FILE,
|
||||
);
|
||||
|
||||
$this->parent->filesystem->execute( 'put_contents', $this->upload_dir . 'fonts.css', $param_array );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process to actually construct the custom font css file.
|
||||
*
|
||||
* @param string $name Name.
|
||||
* @param string $dir Directory.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generate_font_css( string $name, string $dir ): ?string {
|
||||
$path = $dir . $name;
|
||||
|
||||
$params = array(
|
||||
'include_hidden' => false,
|
||||
'recursive' => true,
|
||||
);
|
||||
|
||||
$files = $this->parent->filesystem->execute( 'dirlist', $path, $params );
|
||||
|
||||
if ( empty( $files ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$output = array();
|
||||
|
||||
foreach ( $files as $file ) {
|
||||
$output[ $this->check_font_name( $file ) ] = $file['name'];
|
||||
}
|
||||
|
||||
$css = '@font-face {';
|
||||
|
||||
$css .= 'font-family:"' . $name . '";';
|
||||
|
||||
$src = array();
|
||||
|
||||
if ( isset( $output['eot'] ) ) {
|
||||
$src[] = "url('{$this->upload_url}custom/$name/{$output['eot']}?#iefix') format('embedded-opentype')";
|
||||
}
|
||||
|
||||
if ( isset( $output['woff'] ) ) {
|
||||
$src[] = "url('{$this->upload_url}custom/$name/{$output['woff']}') format('woff')";
|
||||
}
|
||||
|
||||
if ( isset( $output['woff2'] ) ) {
|
||||
$src[] = "url('{$this->upload_url}custom/$name/{$output['woff2']}') format('woff2')";
|
||||
}
|
||||
|
||||
if ( isset( $output['ttf'] ) ) {
|
||||
$src[] = "url('{$this->upload_url}custom/$name/{$output['ttf']}') format('truetype')";
|
||||
}
|
||||
|
||||
if ( isset( $output['svg'] ) ) {
|
||||
$src[] = "url('{$this->upload_url}custom/$name/{$output['svg']}#svg$name') format('svg')";
|
||||
}
|
||||
|
||||
if ( ! empty( $src ) ) {
|
||||
$css .= 'src:' . implode( ', ', $src ) . ';';
|
||||
}
|
||||
|
||||
// Replace font weight and style with sub-sets.
|
||||
$css .= 'font-weight: normal;';
|
||||
|
||||
$css .= 'font-style: normal;';
|
||||
|
||||
$css .= '}';
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom function for filtering the section array.
|
||||
* Good for child themes to override or add to the sections.
|
||||
* Simply include this function in the child themes functions.php file.
|
||||
* NOTE: the defined constants for URLs and directories will NOT be available at this point in a child theme,
|
||||
* so you must use get_template_directory_uri() if you want to use any of the built-in icons
|
||||
*/
|
||||
public function add_section() {
|
||||
if ( ! isset( $this->parent->fontControl ) ) {
|
||||
$this->parent->sections[] = array(
|
||||
'title' => esc_html__( 'Font Control', 'redux-framework' ),
|
||||
'desc' => '<p class="description"></p>',
|
||||
'icon' => 'el-icon-font',
|
||||
'id' => 'redux_dynamic_font_control',
|
||||
// Leave this as a blank section, no options just some intro text set above.
|
||||
'fields' => array(),
|
||||
);
|
||||
|
||||
for ( $i = count( $this->parent->sections ); $i >= 1; $i-- ) {
|
||||
if ( isset( $this->parent->sections[ $i ] ) && isset( $this->parent->sections[ $i ]['title'] ) && esc_html__( 'Font Control', 'redux-framework' ) === $this->parent->sections[ $i ]['title'] ) {
|
||||
$this->parent->fontControl = $i;
|
||||
$this->parent->sections[ $this->parent->fontControl ]['fields'][] = array(
|
||||
'id' => 'redux_font_control',
|
||||
'type' => 'custom_fonts',
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class_alias( 'Redux_Extension_Custom_Fonts', 'ReduxFramework_Extension_custom_fonts' );
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
/**
|
||||
* Redux Custom Font Field Class
|
||||
*
|
||||
* @package Redux
|
||||
* @author Kevin Provance <kevin.provance@gmail.com> & Dovy Paukstys <dovy@reduxframework.com>
|
||||
* @class Redux_Custom_Fonts
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
if ( ! class_exists( 'Redux_Custom_Fonts' ) ) {
|
||||
|
||||
/**
|
||||
* Main ReduxFramework_custom_fonts class
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Redux_Custom_Fonts extends Redux_Field {
|
||||
|
||||
/**
|
||||
* Set field defaults.
|
||||
*/
|
||||
public function set_defaults() {
|
||||
$defaults = array(
|
||||
'convert' => false,
|
||||
'eot' => false,
|
||||
'svg' => false,
|
||||
'ttf' => false,
|
||||
'woff' => true,
|
||||
'woff2' => true,
|
||||
);
|
||||
|
||||
$this->value = wp_parse_args( $this->value, $defaults );
|
||||
}
|
||||
|
||||
/**
|
||||
* Field Render Function.
|
||||
* Takes the vars and outputs the HTML for the field in the settings
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function render() {
|
||||
echo '</fieldset></td></tr>';
|
||||
echo '<tr>';
|
||||
echo '<td colspan="2">';
|
||||
echo '<fieldset
|
||||
class="redux-field-container redux-field redux-field-init redux-container-custom_font"
|
||||
data-type="' . esc_attr( $this->field['type'] ) . '"
|
||||
data-id="' . esc_attr( $this->field['id'] ) . '"
|
||||
>';
|
||||
|
||||
$can_convert = true;
|
||||
|
||||
$nonce = wp_create_nonce( 'redux_custom_fonts' );
|
||||
|
||||
$this->field['custom_fonts'] = apply_filters( "redux/{$this->parent->args[ 'opt_name' ]}/field/typography/custom_fonts", array() ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
|
||||
|
||||
if ( $can_convert ) {
|
||||
echo '<div class="">';
|
||||
echo '<label for="custom-font-convert">';
|
||||
echo '<input type="hidden" class="checkbox-check" data-val="1" name="' . esc_attr( $this->field['name'] ) . '[convert]" value="' . esc_attr( $this->value['convert'] ) . '"/>';
|
||||
echo '<input type="checkbox" class="checkbox" id="custom-font-convert" value="1"' . checked( $this->value['convert'], '1', false ) . '">';
|
||||
echo 'Enable font conversion';
|
||||
echo '</label>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
if ( ! empty( $this->field['custom_fonts'] ) ) {
|
||||
foreach ( $this->field['custom_fonts'] as $section => $fonts ) {
|
||||
if ( empty( $fonts ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
echo '<h3>' . esc_html( $section ) . '</h3>';
|
||||
echo '<div class="font-error" style="display: none;"><p><strong>' . esc_html__( 'Error', 'redux-framework' ) . '</strong>: <span></span></p></div>';
|
||||
|
||||
echo '<table class="wp-list-table widefat plugins" style="border-spacing:0;"><tbody>';
|
||||
|
||||
foreach ( $fonts as $font => $pieces ) {
|
||||
echo '<tr class="active">';
|
||||
echo '<td class="plugin-title" style="min-width: 40%"><strong>' . esc_html( $font ) . '</strong></td>';
|
||||
echo '<td class="column-description desc">';
|
||||
echo '<div class="plugin-description">';
|
||||
|
||||
if ( is_array( $pieces ) && ! empty( $pieces ) ) {
|
||||
foreach ( $pieces as $piece ) {
|
||||
echo '<span class="button button-primary button-small font-pieces">' . esc_html( $piece ) . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo '</td>';
|
||||
echo '<td style="width: 140px;"><div class="action-row visible">';
|
||||
echo '<span style="display:none;"><a href="#" class="rename">Rename</a> | </span>';
|
||||
echo '<a href="#" class="fontDelete delete" data-section="' . esc_attr( $section ) . '" data-name="' . esc_attr( $font ) . '" data-type="delete">' . esc_html__( 'Delete', 'redux-framework' ) . '</a>';
|
||||
echo '<span class="spinner" style="display:none; visibility: visible;"></span>';
|
||||
echo '</div>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
|
||||
echo '<div class="upload_button_div"><span class="button media_add_font" data-nonce="' . esc_attr( $nonce ) . '" id="' . esc_attr( $this->field['id'] ) . '-custom_fonts">' . esc_html__( 'Add Font', 'redux-framework' ) . '</span></div><br />';
|
||||
} else {
|
||||
echo '<h3>' . esc_html__( 'No Custom Fonts Found', 'redux-framework' ) . '</h3>';
|
||||
echo '<div class="upload_button_div"><span class="button media_add_font" data-nonce="' . esc_attr( $nonce ) . '" id="' . esc_attr( $this->field['id'] ) . '-custom_fonts">' . esc_html__( 'Add Font', 'redux-framework' ) . '</span></div>';
|
||||
}
|
||||
|
||||
echo '</fieldset></td></tr>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions to pass data from the PHP to the JS at render time.
|
||||
*
|
||||
* @param array $field Field.
|
||||
* @param string $value Value.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function localize( $field, $value = '' ): array {
|
||||
$params = array();
|
||||
|
||||
if ( ! isset( $field['mode'] ) ) {
|
||||
$field['mode'] = 'image';
|
||||
}
|
||||
|
||||
$params['mode'] = $field['mode'];
|
||||
|
||||
if ( empty( $value ) && isset( $this->value ) ) {
|
||||
$value = $this->value;
|
||||
}
|
||||
|
||||
$params['val'] = $value;
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue Function.
|
||||
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0.0
|
||||
* @access public
|
||||
*/
|
||||
public function enqueue() {
|
||||
$min = Redux_Functions::isMin();
|
||||
|
||||
wp_enqueue_script(
|
||||
'redux-field-custom-fonts',
|
||||
$this->url . '/redux-custom-fonts' . $min . '.js',
|
||||
array( 'jquery', 'redux-block-ui' ),
|
||||
Redux_Extension_Custom_Fonts::$version,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'redux-field-custom-fonts',
|
||||
'redux_custom_fonts_l10',
|
||||
apply_filters(
|
||||
'redux_custom_fonts_localized_data',
|
||||
array(
|
||||
'delete_error' => esc_html__( 'There was an error deleting your font:', 'redux-framework' ),
|
||||
'unzip' => esc_html__( 'Unzipping archive and generating any missing font files.', 'redux-framework' ),
|
||||
'convert' => esc_html__( 'Converting font file(s)...', 'redux-framework' ),
|
||||
'partial' => esc_html__( 'The only file(s) imported were those uploaded. Please refresh the page to continue (making note of any errors before doing so, please).', 'redux-framework' ),
|
||||
'unknown' => esc_html__( 'An unknown error occurred. Please try again.', 'redux-framework' ),
|
||||
'complete' => esc_html__( 'Conversion complete. Refreshing page...', 'redux-framework' ),
|
||||
'media_title' => esc_html__( 'Choose Font file or ZIP of font files.', 'redux-framework' ),
|
||||
'media_button' => esc_html__( 'Update', 'redux-framework' ),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ( $this->parent->args['dev_mode'] ) {
|
||||
wp_enqueue_style(
|
||||
'redux-field-custom-fonts',
|
||||
$this->url . 'redux-custom-fonts.css',
|
||||
array(),
|
||||
Redux_Extension_Custom_Fonts::$version
|
||||
);
|
||||
}
|
||||
|
||||
$class = Redux_Extension_Custom_Fonts::$instance;
|
||||
|
||||
if ( ! empty( $class->custom_fonts ) ) {
|
||||
if ( file_exists( $class->upload_dir . 'fonts.css' ) ) {
|
||||
wp_enqueue_style(
|
||||
'redux-custom_fonts',
|
||||
$class->upload_url . 'fonts.css',
|
||||
array(),
|
||||
Redux_Core::$version
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
echo null;
|
||||
@@ -0,0 +1,33 @@
|
||||
.redux-container-custom_font table tr td { padding: 10px 9px !important; }
|
||||
|
||||
.redux-container-custom_font table.widefat { border-left: 1px solid #dfdfdf; border-right: 1px solid #dfdfdf; border-top: 1px solid #dfdfdf; }
|
||||
|
||||
.redux-container-custom_font .upload_button_div { margin: 10px 0; float: right; }
|
||||
|
||||
.redux-container-custom_font .spinner { margin-top: 0; }
|
||||
|
||||
.redux-container-custom_font .fontDelete { float: right; }
|
||||
|
||||
.redux-container-custom_font .action-row { text-align: right; padding-right: 5px; line-height: 20px; }
|
||||
|
||||
.redux-container-custom_font .plugins .active td, .redux-container-custom_font .plugins .active th { background-color: #FAFAFA; }
|
||||
|
||||
.redux-container-custom_font .font-error { margin: 5px 0 15px; border-left: 4px solid #dd3d36; background: #fff; -webkit-box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); padding: 1px 12px; outline: 0; }
|
||||
|
||||
.redux-container-custom_font .font-error p { margin: 0.5em 0; padding: 2px; }
|
||||
|
||||
.redux-container-custom_font .conversion-types { border: solid #e7e7e7 1px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; margin-bottom: 10px; opacity: 1; }
|
||||
|
||||
.redux-container-custom_font .conversion-types .checkbox { margin-left: 20px !important; }
|
||||
|
||||
.redux-container-custom_font .conversion-types.is-disabled { cursor: not-allowed; opacity: 0.7; }
|
||||
|
||||
.redux-container-custom_font .conversion-types.is-disabled .checkbox, .redux-container-custom_font .conversion-types.is-disabled label { cursor: not-allowed; }
|
||||
|
||||
.redux-container-custom_font .font-pieces { margin-right: 1px; }
|
||||
|
||||
.fontActionWorking { background: green !important; }
|
||||
|
||||
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtY3VzdG9tLWZvbnRzLmNzcyIsInNvdXJjZXMiOlsicmVkdXgtY3VzdG9tLWZvbnRzLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsQUFFUSw0QkFGb0IsQ0FDeEIsS0FBSyxDQUNELEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFDRixPQUFPLEVBQUUsbUJBQW1CLEdBQy9COztBQUpULEFBTVEsNEJBTm9CLENBQ3hCLEtBQUssQUFLQSxRQUFRLENBQUMsRUFDTixXQUFXLEVBQUUsaUJBQWlCLEVBQzlCLFlBQVksRUFBRSxpQkFBaUIsRUFDL0IsVUFBVSxFQUFFLGlCQUFpQixHQUNoQzs7QUFWVCxBQWFJLDRCQWJ3QixDQWF4QixrQkFBa0IsQ0FBQyxFQUNmLE1BQU0sRUFBRSxNQUFNLEVBQ2QsS0FBSyxFQUFFLEtBQUssR0FDZjs7QUFoQkwsQUFrQkksNEJBbEJ3QixDQWtCeEIsUUFBUSxDQUFDLEVBQ0wsVUFBVSxFQUFDLENBQUMsR0FDZjs7QUFwQkwsQUFzQkksNEJBdEJ3QixDQXNCeEIsV0FBVyxDQUFDLEVBQ1IsS0FBSyxFQUFFLEtBQUssR0FDZjs7QUF4QkwsQUEwQkksNEJBMUJ3QixDQTBCeEIsV0FBVyxDQUFDLEVBQ1IsVUFBVSxFQUFFLEtBQUssRUFDakIsYUFBYSxFQUFFLEdBQUcsRUFDbEIsV0FBVyxFQUFFLElBQUksR0FDcEI7O0FBOUJMLEFBa0NZLDRCQWxDZ0IsQ0FnQ3hCLFFBQVEsQ0FDSixPQUFPLENBQ0gsRUFBRSxFQWxDZCw0QkFBNEIsQ0FnQ3hCLFFBQVEsQ0FDSixPQUFPLENBRUgsRUFBRSxDQUFDLEVBQ0MsZ0JBQWdCLEVBQUUsT0FBTyxHQUM1Qjs7QUFyQ2IsQUF5Q0ksNEJBekN3QixDQXlDeEIsV0FBVyxDQUFDLEVBQ1IsTUFBTSxFQUFFLFVBQVUsRUFDbEIsV0FBVyxFQUFFLGlCQUFpQixFQUM5QixVQUFVLEVBQUUsSUFBSSxFQUNoQixrQkFBa0IsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsa0JBQW9CLEVBQ3BELFVBQVUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsa0JBQW9CLEVBQzVDLE9BQU8sRUFBRSxRQUFRLEVBQ2pCLE9BQU8sRUFBRSxDQUFDLEdBS2I7O0FBckRMLEFBaURRLDRCQWpEb0IsQ0F5Q3hCLFdBQVcsQ0FRUCxDQUFDLENBQUMsRUFDRSxNQUFNLEVBQUUsT0FBTyxFQUNmLE9BQU8sRUFBRSxHQUFHLEdBQ2Y7O0FBcERULEFBdURJLDRCQXZEd0IsQ0F1RHhCLGlCQUFpQixDQUFDLEVBQ2QsTUFBTSxFQUFFLGlCQUFpQixFQUN6QixXQUFXLEVBQUUsR0FBRyxFQUNoQixjQUFjLEVBQUUsR0FBRyxFQUNuQixZQUFZLEVBQUUsSUFBSSxFQUNsQixhQUFhLEVBQUUsSUFBSSxFQUNuQixPQUFPLEVBQUMsQ0FBQyxHQWVaOztBQTVFTCxBQStEUSw0QkEvRG9CLENBdUR4QixpQkFBaUIsQ0FRYixTQUFTLENBQUMsRUFDTixXQUFXLEVBQUUsSUFBSSxDQUFBLFVBQVUsR0FDOUI7O0FBakVULEFBbUVRLDRCQW5Fb0IsQ0F1RHhCLGlCQUFpQixBQVlaLFlBQVksQ0FBQyxFQUNWLE1BQU0sRUFBQyxXQUFXLEVBQ2xCLE9BQU8sRUFBRSxHQUFHLEdBTWY7O0FBM0VULEFBdUVZLDRCQXZFZ0IsQ0F1RHhCLGlCQUFpQixBQVlaLFlBQVksQ0FJVCxTQUFTLEVBdkVyQiw0QkFBNEIsQ0F1RHhCLGlCQUFpQixBQVlaLFlBQVksQ0FLVCxLQUFLLENBQUMsRUFDRixNQUFNLEVBQUMsV0FBVyxHQUNyQjs7QUExRWIsQUE4RUksNEJBOUV3QixDQThFeEIsWUFBWSxDQUFDLEVBQ1QsWUFBWSxFQUFFLEdBQUcsR0FDcEI7O0FBR0wsQUFBQSxrQkFBa0IsQ0FBQyxFQUNmLFVBQVUsRUFBRSxnQkFBZ0IsR0FDL0IifQ== */
|
||||
|
||||
/*# sourceMappingURL=redux-custom-fonts.css.map */
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,329 @@
|
||||
/* global redux, wp, redux_custom_fonts_l10, ajaxurl */
|
||||
|
||||
(function ( $ ) {
|
||||
'use strict';
|
||||
|
||||
var l10n;
|
||||
var reduxObject;
|
||||
var ajaxDone = false;
|
||||
|
||||
redux.field_objects = redux.field_objects || {};
|
||||
redux.field_objects.custom_fonts = redux.field_objects.custom_fonts || {};
|
||||
|
||||
redux.field_objects.custom_fonts.init = function ( selector ) {
|
||||
|
||||
// If no selector is passed, grab one from the HTML.
|
||||
if ( ! selector ) {
|
||||
selector = $( document ).find( '.redux-group-tab:visible' ).find( '.redux-container-custom_font:visible' );
|
||||
}
|
||||
|
||||
// Enum instances of our object.
|
||||
$( selector ).each(
|
||||
function () {
|
||||
var el = $( this );
|
||||
var parent = el;
|
||||
|
||||
if ( ! el.hasClass( 'redux-field-container' ) ) {
|
||||
parent = el.parents( '.redux-field-container:first' );
|
||||
}
|
||||
|
||||
if ( parent.is( ':hidden' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( parent.hasClass( 'redux-field-init' ) ) {
|
||||
parent.removeClass( 'redux-field-init' );
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Init module level code.
|
||||
redux.field_objects.custom_fonts.modInit( el );
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
redux.field_objects.custom_fonts.modInit = function ( el ) {
|
||||
var optName = $( '.redux-ajax-security' ).data( 'opt-name' );
|
||||
|
||||
l10n = redux_custom_fonts_l10;
|
||||
|
||||
if ( undefined === optName ) {
|
||||
reduxObject = redux;
|
||||
} else {
|
||||
reduxObject = redux.optName;
|
||||
}
|
||||
|
||||
el.find( '.checkbox' ).on(
|
||||
'click',
|
||||
function () {
|
||||
var val = 0;
|
||||
var checkName;
|
||||
var checkVal;
|
||||
var opVal;
|
||||
|
||||
checkName = $( this ).attr( 'id' );
|
||||
|
||||
if ( 'custom-font-convert' === checkName ) {
|
||||
if ( $( this ).is( ':checked' ) ) {
|
||||
checkVal = '';
|
||||
opVal = 1;
|
||||
|
||||
el.find( '.conversion-types' ).removeClass( 'is-disabled' );
|
||||
} else {
|
||||
checkVal = 'disabled';
|
||||
opVal = 0.7;
|
||||
|
||||
el.find( '.conversion-types' ).addClass( 'is-disabled' );
|
||||
}
|
||||
|
||||
el.find( '#custom-font-eot,#custom-font-svg,#custom-font-ttf,#custom-font-woff,#custom-font-woff2' ).prop( 'disabled', checkVal );
|
||||
el.find( '.conversion-types' ).css( 'opacity', opVal );
|
||||
}
|
||||
|
||||
if ( $( this ).is( ':checked' ) ) {
|
||||
val = $( this ).parent().find( '.checkbox-check' ).attr( 'data-val' );
|
||||
}
|
||||
|
||||
$( this ).parent().find( '.checkbox-check' ).val( val );
|
||||
|
||||
redux_change( $( this ) );
|
||||
}
|
||||
);
|
||||
|
||||
// Remove the image button.
|
||||
el.find( '.remove-font' ).off( 'click' ).on(
|
||||
'click',
|
||||
function () {
|
||||
redux.field_objects.custom_fonts.remove_font( el, $( this ).parents( 'fieldset.redux-field:first' ) );
|
||||
}
|
||||
);
|
||||
|
||||
// Upload media button.
|
||||
el.find( '.media_add_font' ).off().on(
|
||||
'click',
|
||||
function ( event ) {
|
||||
redux.field_objects.custom_fonts.add_font( el, event, $( this ).parents( 'fieldset.redux-field:first' ) );
|
||||
}
|
||||
);
|
||||
|
||||
el.find( '.fontDelete' ).on(
|
||||
'click',
|
||||
function ( e ) {
|
||||
var data;
|
||||
|
||||
var parent = $( this ).parents( 'td:first' );
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
parent.find( '.spinner' ).show();
|
||||
|
||||
data = $( this ).data();
|
||||
data.action = 'redux_custom_fonts';
|
||||
data.nonce = $( this ).parents( '.redux-container-custom_font:first' ).find( '.media_add_font' ).attr( 'data-nonce' );
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( response ) {
|
||||
var rowCount;
|
||||
|
||||
response = JSON.parse( response );
|
||||
|
||||
if ( response.type && 'success' === response.type ) {
|
||||
rowCount = parent.parents( 'table:first' ).find( 'tr' ).length;
|
||||
|
||||
if ( 1 === rowCount ) {
|
||||
parent.parents( 'table:first' ).fadeOut().remove();
|
||||
} else {
|
||||
parent.parents( 'tr:first' ).fadeOut().remove();
|
||||
}
|
||||
} else {
|
||||
alert( l10n.delete_error + ' ' + response.msg );
|
||||
|
||||
parent.find( '.spinner' ).hide();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
redux.field_objects.custom_fonts.startTimer = function ( el, status ) {
|
||||
var cur_data;
|
||||
|
||||
$.ajax(
|
||||
{
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'redux_custom_font_timer'
|
||||
},
|
||||
beforeSend: function () {
|
||||
|
||||
},
|
||||
success: function ( data ) {
|
||||
var msg;
|
||||
|
||||
if ( false === ajaxDone ) {
|
||||
setTimeout( redux.field_objects.custom_fonts.startTimer( el, status ), 500 );
|
||||
|
||||
msg = reduxObject.args.please_wait + ': ' + status + '<br><br>' + data;
|
||||
} else {
|
||||
msg = l10n.complete;
|
||||
data = 'finished';
|
||||
}
|
||||
|
||||
if ( '' !== data ) {
|
||||
if ( cur_data !== data ) {
|
||||
$( '.blockUI.blockMsg h2' ).html( msg );
|
||||
|
||||
cur_data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
redux.field_objects.custom_fonts.add_font = function ( el, event, selector ) {
|
||||
var frame;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
// If the media frame already exists, reopen it.
|
||||
if ( frame ) {
|
||||
frame.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the media frame.
|
||||
frame = wp.media(
|
||||
{
|
||||
multiple: false,
|
||||
library: {
|
||||
type: ['application', 'font'] // Only allow zip files.
|
||||
}, // Set the title of the modal.
|
||||
title: 'Redux Custom Fonts: ' + l10n.media_title, // Customize the submit button.
|
||||
button: {
|
||||
|
||||
// Set the text of the button.
|
||||
text: l10n.media_button
|
||||
|
||||
// Tell the button not to close the modal, since we're
|
||||
// going to refresh the page when the image is selected.
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// When an image is selected, run a callback.
|
||||
frame.on(
|
||||
'select',
|
||||
function () {
|
||||
var nonce;
|
||||
var data;
|
||||
var status;
|
||||
var conversion;
|
||||
|
||||
// Grab the selected attachment.
|
||||
var attachment = frame.state().get( 'selection' ).first();
|
||||
var error = selector.find( '.font-error' );
|
||||
|
||||
error.slideUp();
|
||||
error.find( 'span' ).text( '' );
|
||||
|
||||
frame.close();
|
||||
if ( 'application' !== attachment.attributes.type && 'font' !== attachment.attributes.type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
nonce = $( selector ).find( '.media_add_font' ).attr( 'data-nonce' );
|
||||
|
||||
conversion = $( '#custom-font-convert' ).is( ':checked' );
|
||||
|
||||
data = {
|
||||
action: 'redux_custom_fonts',
|
||||
nonce: nonce,
|
||||
attachment_id: attachment.id,
|
||||
title: attachment.attributes.title,
|
||||
mime: attachment.attributes.mime,
|
||||
filename: attachment.attributes.filename,
|
||||
conversion: Boolean( conversion )
|
||||
};
|
||||
|
||||
if ( 'application/zip ' === data.mime ) {
|
||||
status = l10n.unzip;
|
||||
} else {
|
||||
status = l10n.convert;
|
||||
}
|
||||
|
||||
redux.field_objects.custom_fonts.startTimer( el, status );
|
||||
|
||||
$.blockUI( { message: '<h2>' + reduxObject.args.please_wait + ': ' + status + '</h2>' } );
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( response ) {
|
||||
console.log( 'Redux Custom Fonts API Response (For support purposes)' );
|
||||
console.log( response );
|
||||
|
||||
response = JSON.parse( response );
|
||||
|
||||
if ( 'success' === response.type ) {
|
||||
if ( '' !== response.msg ) {
|
||||
$.unblockUI();
|
||||
|
||||
error.find( 'span' ).html( response.msg + ' ' + l10n.partial );
|
||||
error.slideDown();
|
||||
|
||||
ajaxDone = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.onbeforeunload = '';
|
||||
location.reload();
|
||||
} else if ( 'error' === response.type ) {
|
||||
$.unblockUI();
|
||||
error.find( 'span' ).html( response.msg );
|
||||
error.slideDown();
|
||||
} else {
|
||||
$.unblockUI();
|
||||
error.find( 'span' ).text( l10n.unknown );
|
||||
error.slideDown();
|
||||
}
|
||||
|
||||
ajaxDone = true;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Finally, open the modal.
|
||||
frame.open();
|
||||
};
|
||||
|
||||
redux.field_objects.custom_fonts.remove_font = function ( el, selector ) {
|
||||
el = null;
|
||||
|
||||
// This shouldn't have been run...
|
||||
if ( ! selector.find( '.remove-image' ).addClass( 'hide' ) ) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
redux.field_objects.custom_fonts.sleep = function ( milliseconds ) {
|
||||
var start = new Date().getTime();
|
||||
|
||||
var i;
|
||||
|
||||
for ( i = 0; i < 1e7; i += 1 ) {
|
||||
if ( ( new Date().getTime() - start ) > milliseconds ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
})( jQuery );
|
||||
@@ -0,0 +1 @@
|
||||
.redux-container-custom_font table tr td{padding:10px 9px !important}.redux-container-custom_font table.widefat{border-left:1px solid #dfdfdf;border-right:1px solid #dfdfdf;border-top:1px solid #dfdfdf}.redux-container-custom_font .upload_button_div{margin:10px 0;float:right}.redux-container-custom_font .spinner{margin-top:0}.redux-container-custom_font .fontDelete{float:right}.redux-container-custom_font .action-row{text-align:right;padding-right:5px;line-height:20px}.redux-container-custom_font .plugins .active td,.redux-container-custom_font .plugins .active th{background-color:#fafafa}.redux-container-custom_font .font-error{margin:5px 0 15px;border-left:4px solid #dd3d36;background:#fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:1px 12px;outline:0}.redux-container-custom_font .font-error p{margin:.5em 0;padding:2px}.fontActionWorking{background:green !important}
|
||||
@@ -0,0 +1 @@
|
||||
!function(r){"use strict";var a,c,f=!1;redux.field_objects=redux.field_objects||{},redux.field_objects.custom_fonts=redux.field_objects.custom_fonts||{},redux.field_objects.custom_fonts.init=function(t){t=t||r(document).find(".redux-group-tab:visible").find(".redux-container-custom_font:visible"),r(t).each(function(){var t=r(this),e=t;(e=t.hasClass("redux-field-container")?e:t.parents(".redux-field-container:first")).is(":hidden")||e.hasClass("redux-field-init")&&(e.removeClass("redux-field-init"),redux.field_objects.custom_fonts.modInit(t))})},redux.field_objects.custom_fonts.modInit=function(n){var t=r(".redux-ajax-security").data("opt-name");a=redux_custom_fonts_l10,c=void 0===t?redux:redux.optName,n.find(".checkbox").on("click",function(){var t,e,o=0;"custom-font-convert"===r(this).attr("id")&&(r(this).is(":checked")?(t="",e=1,n.find(".conversion-types").removeClass("is-disabled")):(t="disabled",e=.7,n.find(".conversion-types").addClass("is-disabled")),n.find("#custom-font-eot,#custom-font-svg,#custom-font-ttf,#custom-font-woff,#custom-font-woff2").prop("disabled",t),n.find(".conversion-types").css("opacity",e)),r(this).is(":checked")&&(o=r(this).parent().find(".checkbox-check").attr("data-val")),r(this).parent().find(".checkbox-check").val(o),redux_change(r(this))}),n.find(".remove-font").off("click").on("click",function(){redux.field_objects.custom_fonts.remove_font(n,r(this).parents("fieldset.redux-field:first"))}),n.find(".media_add_font").off().on("click",function(t){redux.field_objects.custom_fonts.add_font(n,t,r(this).parents("fieldset.redux-field:first"))}),n.find(".fontDelete").on("click",function(t){var e=r(this).parents("td:first");return t.preventDefault(),e.find(".spinner").show(),(t=r(this).data()).action="redux_custom_fonts",t.nonce=r(this).parents(".redux-container-custom_font:first").find(".media_add_font").attr("data-nonce"),r.post(ajaxurl,t,function(t){(t=JSON.parse(t)).type&&"success"===t.type?(1===e.parents("table:first").find("tr").length?e.parents("table:first"):e.parents("tr:first")).fadeOut().remove():(alert(a.delete_error+" "+t.msg),e.find(".spinner").hide())}),!1})},redux.field_objects.custom_fonts.startTimer=function(o,n){var s;r.ajax({url:ajaxurl,type:"POST",data:{action:"redux_custom_font_timer"},beforeSend:function(){},success:function(t){var e;!1===f?(setTimeout(redux.field_objects.custom_fonts.startTimer(o,n),500),e=c.args.please_wait+": "+n+"<br><br>"+t):(e=a.complete,t="finished"),""!==t&&s!==t&&(r(".blockUI.blockMsg h2").html(e),s=t)}})},redux.field_objects.custom_fonts.add_font=function(s,t,i){var d;t.preventDefault(),(d=wp.media({multiple:!1,library:{type:["application","font"]},title:"Redux Custom Fonts: "+a.media_title,button:{text:a.media_button}})).on("select",function(){var t,e,o=d.state().get("selection").first(),n=i.find(".font-error");n.slideUp(),n.find("span").text(""),d.close(),"application"!==o.attributes.type&&"font"!==o.attributes.type||(t=r(i).find(".media_add_font").attr("data-nonce"),e=r("#custom-font-convert").is(":checked"),o="application/zip "===(t={action:"redux_custom_fonts",nonce:t,attachment_id:o.id,title:o.attributes.title,mime:o.attributes.mime,filename:o.attributes.filename,conversion:Boolean(e)}).mime?a.unzip:a.convert,redux.field_objects.custom_fonts.startTimer(s,o),r.blockUI({message:"<h2>"+c.args.please_wait+": "+o+"</h2>"}),r.post(ajaxurl,t,function(t){if(console.log("Redux Custom Fonts API Response (For support purposes)"),console.log(t),"success"===(t=JSON.parse(t)).type){if(""!==t.msg)return r.unblockUI(),n.find("span").html(t.msg+" "+a.partial),n.slideDown(),void(f=!0);window.onbeforeunload="",location.reload()}else"error"===t.type?(r.unblockUI(),n.find("span").html(t.msg)):(r.unblockUI(),n.find("span").text(a.unknown)),n.slideDown();f=!0}))}),d.open()},redux.field_objects.custom_fonts.remove_font=function(t,e){e.find(".remove-image").addClass("hide")},redux.field_objects.custom_fonts.sleep=function(t){for(var e=(new Date).getTime(),o=0;o<1e7&&!((new Date).getTime()-e>t);o+=1);}}(jQuery);
|
||||
@@ -0,0 +1,86 @@
|
||||
.redux-container-custom_font {
|
||||
table {
|
||||
tr td {
|
||||
padding: 10px 9px !important;
|
||||
}
|
||||
|
||||
&.widefat {
|
||||
border-left: 1px solid #dfdfdf;
|
||||
border-right: 1px solid #dfdfdf;
|
||||
border-top: 1px solid #dfdfdf;
|
||||
}
|
||||
}
|
||||
|
||||
.upload_button_div {
|
||||
margin: 10px 0;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
margin-top:0;
|
||||
}
|
||||
|
||||
.fontDelete {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.action-row {
|
||||
text-align: right;
|
||||
padding-right: 5px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.plugins {
|
||||
.active {
|
||||
td,
|
||||
th {
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.font-error {
|
||||
margin: 5px 0 15px;
|
||||
border-left: 4px solid #dd3d36;
|
||||
background: #fff;
|
||||
-webkit-box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
|
||||
box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
|
||||
padding: 1px 12px;
|
||||
outline: 0;
|
||||
p {
|
||||
margin: 0.5em 0;
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.conversion-types {
|
||||
border: solid #e7e7e7 1px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
opacity:1;
|
||||
|
||||
.checkbox {
|
||||
margin-left: 20px!important;
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
cursor:not-allowed;
|
||||
opacity: 0.7;
|
||||
|
||||
.checkbox,
|
||||
label {
|
||||
cursor:not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.font-pieces {
|
||||
margin-right: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.fontActionWorking {
|
||||
background: green !important;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
echo null;
|
||||
Reference in New Issue
Block a user