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:
Hotel Raxa Dev
2025-07-11 07:43:22 +02:00
commit 5b1e2453c7
9816 changed files with 2784509 additions and 0 deletions

View File

@@ -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' );

View File

@@ -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
);
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -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 */

View File

@@ -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 );

View File

@@ -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}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;