Plugin Directory

Changeset 3230461


Ignore:
Timestamp:
01/28/2025 11:57:25 AM (14 months ago)
Author:
visualmodo
Message:

1.6.0 - Jan 28 2025

  • Fixed - General Vulnerabilities.
Location:
borderless
Files:
210 added
3 edited

Legend:

Unmodified
Added
Removed
  • borderless/trunk/borderless.php

    r3209805 r3230461  
    55Plugin URI: https://visualmodo.com/borderless/
    66Description: One service packed with powerful tools to help you reach your purposes.
    7 Version: 1.5.9
     7Version: 1.6.0
    88Author: Visualmodo
    99Author URI: https://visualmodo.com
     
    2121/*-----------------------------------------------------------------------------------*/
    2222
    23 define( 'BORDERLESS__VERSION', '1.5.9' );
     23define( 'BORDERLESS__VERSION', '1.6.0' );
    2424define( 'BORDERLESS__DIR', plugin_dir_path( __FILE__ ) );
    2525define( 'BORDERLESS__URL', plugins_url( '/', __FILE__ ) );
  • borderless/trunk/includes/icon-manager/icon-manager.php

    r2483040 r3230461  
    11<?php
    22if ( ! defined( 'ABSPATH' ) ) {
    3     die( '-1' );
     3    die( '-1' );
    44}
    55
    66if ( ! class_exists( 'Borderless_IF' ) ) {
    7     class Borderless_IF {
    8         var $paths = array();
    9         var $svg_file;
    10         var $json_file;
    11         var $ip_name = 'unknown';
    12         var $svg_config = array();
    13         var $json_config = array();
    14         static $ip_list = array();
    15        
    16         function __construct() {
    17             $this->paths            = wp_upload_dir();
    18             $this->paths['fonts']   = 'borderless_icon_fonts';
    19             $this->paths['temp']    = trailingslashit( $this->paths['fonts'] ) . 'borderless_temp';
    20             $this->paths['fontdir'] = trailingslashit( $this->paths['basedir'] ) . $this->paths['fonts'];
    21             $this->paths['tempdir'] = trailingslashit( $this->paths['basedir'] ) . $this->paths['temp'];
    22             $this->paths['fonturl'] = set_url_scheme( trailingslashit( $this->paths['baseurl'] ) . $this->paths['fonts'] );
    23             $this->paths['tempurl'] = trailingslashit( $this->paths['baseurl'] ) . trailingslashit( $this->paths['temp'] );
    24             $this->paths['config']  = 'charmap.php';
    25             add_action( 'wp_ajax_borderless_ajax_add_zipped_font', array( $this, 'add_zipped_font' ) );
    26             add_action( 'wp_ajax_borderless_ajax_remove_zipped_font', array( $this, 'remove_zipped_font' ) );
    27            
    28         }
    29        
    30         function admin_scripts() {
    31             $upload_paths = wp_upload_dir();
    32             wp_enqueue_script( 'borderless-admin-media', plugin_dir_url( __FILE__ ) . 'assets/js/icon-manager.min.js', array( 'jquery' ) );
    33             wp_enqueue_script( 'media-upload' );
    34             wp_enqueue_media();
    35             wp_enqueue_style( 'borderless-wpbakery-icon-manager-admin', plugin_dir_url( __FILE__ ) . 'assets/css/icon-manager.css' );
    36             $custom_fonts = get_option( 'borderless_icon_fonts' );
    37             if ( is_array( $custom_fonts ) ) {
    38                 foreach ( $custom_fonts as $font => $info ) {
    39                     if ( strpos( $info['style'], 'http://' ) !== false ) {
    40                         wp_enqueue_style( 'borderless-' . $font, $info['style'], null, '1.0', 'all' );
    41                     } else {
    42                         wp_enqueue_style( 'borderless-' . $font, trailingslashit( $upload_paths['baseurl'] . '/borderless_icon_fonts/' ) . $info['style'], null, '1.0', 'all' );
    43                     }
    44                 }
    45             }
    46         }
    47        
    48         /*-----------------------------------------------------------------------------------*/
    49         /*  *.  Icon Pack Manager On Page Edit
    50         /*-----------------------------------------------------------------------------------*/
    51        
    52         public function get_icon_manager( $input_name, $icon ) {
    53             $font_manager = self::get_font_manager( $id );
    54             $output       = '<div class="my_param_block">';
    55             $output .= '<input name="' . $input_name . '" class="textinput ' . $input_name . ' text_field" type="text" value="' . $icon . '"/>';
    56             $output .= '</div>';
    57             $output .= '<script type="text/javascript">
    58             jQuery(document).ready(function(){
    59                
    60                 //debugger;
    61                 //alert("' . $id . '");
    62                 jQuery(".icon-manager-preview-icon-' . $id . '").html("<i class=\'' . $icon . '\'></i>");
    63                 jQuery(".icons-list-' . $id . ' li[data-icons=\'' . $icon . '\']").addClass("selected");
    64             });
    65             jQuery(".icons-list-' . $id . ' li").click(function() {
    66                 jQuery(this).attr("class","selected").siblings().removeAttr("class");
    67                 var icon = jQuery(this).attr("data-icons");
    68                 jQuery("input[name=\'' . $input_name . '\']").val(icon);
    69                 jQuery(".icon-manager-preview-icon-' . $id . '").html("<i class=\'"+icon+"\'></i>");
    70             });
    71             </script>';
    72             $output .= $font_manager;
    73            
    74             return $output;
    75         }
    76        
    77         public function get_font_manager( $id ) {
    78            
    79             $fonts  = get_option( 'borderless_icon_fonts' );
    80             $output = '<div class="icon-manager-preview"><div class="icon-manager-preview-icon preview-icon-' . $id . '"><i class=""></i></div><input class="icon-manager-search-icon" type="text" placeholder="Search for a suitable icon.." /></div>';
    81             $output .= '<div id="icon-manager-search-icon-inner">';
    82             $output .= '<ul class="icons-list borderless_icon icon-list-' . $id . '">';
    83             foreach ( $fonts as $font => $info ) {
    84                 $icon_set   = array();
    85                 $icons      = array();
    86                 $upload_dir = wp_upload_dir();
    87                 $path       = trailingslashit( $upload_dir['basedir'] );
    88                 $file       = $path . $info['include'] . '/' . $info['config'];
    89                 include( $file );
    90                 if ( ! empty( $icons ) ) {
    91                     $icon_set = array_merge( $icon_set, $icons );
    92                 }
    93                
    94                 $set_name = ucfirst( $font );
    95                
    96                 if ( ! empty( $icon_set ) ) {
    97                     $output .= '<p><strong>' . $set_name . '</strong></p>';
    98                     $output .= '<li title="no-icon" data-icons="none" data-icons-tag="none,blank" style="cursor: pointer;" id="' . $id . '"></li>';
    99                     foreach ( $icon_set as $icons ) {
    100                         foreach ( $icons as $icon ) {
    101                             $output .= '<li title="' . $icon['class'] . '" data-icons="' . $font . '-' . $icon['class'] . '" data-icons-tag="' . $icon['tags'] . '" id="' . $id . '">';
    102                             $output .= '<i class="icon-manager-icon ' . $font . '-' . $icon['class'] . '"></i><label class="icon">' . $icon['class'] . '</label></li>';
    103                         }
    104                     }
    105                 }
    106             }
    107             $output . '</ul>';
    108             $output .= '<script type="text/javascript">
    109             jQuery(document).ready(function(){
    110                 jQuery(".icon-manager-search-icon").keyup(function(){
    111                     // Retrieve the input field text and reset the count to zero
    112                     var filter = jQuery(this).val(), count = 0;
    113                     // Loop through the icon list
    114                     jQuery(".icons-list li").each(function(){
    115                         // If the list item does not contain the text phrase fade it out
    116                         if (jQuery(this).attr("data-icons-tag").search(new RegExp(filter, "i")) < 0) {
    117                             jQuery(this).fadeOut();
    118                         } else {
    119                             jQuery(this).show();
    120                             count++;
    121                         }
    122                     });
    123                 });
    124             });
    125             </script>';
    126             $output .= '</div>';
    127            
    128             return $output;
    129         }
    130        
    131         /*-----------------------------------------------------------------------------------*/
    132         /*  *.  Icon Pack Manager
    133         /*-----------------------------------------------------------------------------------*/
    134        
    135         function icon_pack_manager() {
    136             ?>
    137             <div class="wrap">
    138             <h2>
    139             <?php esc_html_e( 'Icon Pack Manager', 'borderless' ); ?>
    140             <a href="#borderless_upload_icon" class="button button-primary borderless-upload-icon" data-target="iconfont_upload"
    141             data-title="<?php echo esc_html__( "Upload/Select Fontello Font Zip", "borderless" ) ?>"
    142             data-type="application/octet-stream, application/zip"
    143             data-button="<?php echo esc_html__( "Insert Fonts Zip File", "borderless" ); ?>" data-trigger="borderless_insert_zip"
    144             data-class="media-frame ">
    145             <?php esc_html_e( 'Add New Icon Pack', 'borderless' ); ?>
    146             </a> &nbsp;<span class="spinner"></span></h2>
    147             <div id="msg"></div>
    148             <?php
    149             $fonts = get_option( 'borderless_icon_fonts' );
    150             if ( is_array( $fonts ) ) :
    151                 ?>
    152                 <div class="metabox-holder meta-search">
    153                 <div class="postbox borderless-postbox-search">
    154                 <h2 class="hndle ui-sortable-handle"><span>Search for Icons</h2>
    155                 <div class="inside">
    156                 <div class="search-area">
    157                 <input class="search-icon" type="text" placeholder="<?php esc_attr_e( 'Start typing to search', 'borderless' ); ?>"/>
    158                 <span class="search-count"></span>
    159                 </div>
    160                 </div>
    161                 </div>
    162                 </div>
    163                 <?php self::get_ipm(); ?>
    164                 </div>
    165                 <?php else: ?>
    166                 <div class="error">
    167                 <p>
    168                 <?php esc_html_e( 'No icon pack uploaded. Upload some icon pack to display here.', 'borderless' ); ?>
    169                 </p>
    170                 </div>
    171                 <?php
    172             endif;
    173         }
    174        
    175         // Generate Icon Pack Preview and settings page
    176         static function get_ipm() {
    177             $fonts = get_option( 'borderless_icon_fonts' );
    178             $n     = count( $fonts );
    179             foreach ( $fonts as $font => $info ) {
    180                 $icon_set   = array();
    181                 $icons      = array();
    182                 $upload_dir = wp_upload_dir();
    183                 $path       = trailingslashit( $upload_dir['basedir'] );
    184                 $file       = $path . $info['include'] . '/' . $info['config'];
    185                 $output     = '<div class="icon_set-' . $font . ' metabox-holder">';
    186                 $output .= '<div class="postbox borderless-postbox-icon-manager">';
    187                 include( $file );
    188                 if ( ! empty( $icons ) ) {
    189                     $icon_set = array_merge( $icon_set, $icons );
    190                 }
    191                 if ( ! empty( $icon_set ) ) {
    192                     foreach ( $icon_set as $icons ) {
    193                         $count = count( $icons );
    194                     }
    195                    
    196                     $output .= '<h3 class="ip_name"><strong>' . esc_html( ucfirst( $font ) ) . '</strong>';
    197                    
    198                     $output .= '<span class="fonts-count wp-core-ui wp-ui-notification count-' . esc_attr( $font ) . '">' . esc_html( $count ) . '</span>';
    199                     if ( $n != 1 ) {
    200                         $output .= '<button class="button button-primary button-small borderless_del_icon" data-delete=' . esc_attr( $font ) . ' data-title="' . esc_attr__( 'Remove Pack', 'borderless' ) . '">' . esc_html__( 'Remove Pack', 'borderless' ) . '</button>';
    201                     }
    202                     $output .= '</h3>';
    203                     $output .= '<div class="inside"><div class="icon_actions">';
    204                     $output .= '</div>';
    205                     $output .= '<div class="icon_search"><ul class="icons-list borderless_icon">';
    206                     foreach ( $icon_set as $icons ) {
    207                         foreach ( $icons as $icon ) {
    208                             $output .= '<li " data-icons="' . esc_attr( $icon['class'] ) . '" data-icons-tag="' . esc_attr( $icon['tags'] ) . '">';
    209                             $output .= '<i class="' . esc_attr( $font ) . '-' . esc_attr( $icon['class'] ) . '"></i><a class="tooltips" href="#"><span>' . esc_html( $icon['class'] ) . '</span></a></li>';
    210                         }
    211                     }
    212                     $output . '</ul>';
    213                     $output .= '</div><!-- .icon_search-->';
    214                     $output .= '</div><!-- .inside-->';
    215                     $output .= '</div><!-- .postbox-->';
    216                     $output .= '</div><!-- .icon_set-' . esc_html( $font ) . ' -->';
    217                     echo $output;
    218                 }
    219             }
    220             $script = '<script type="text/javascript">
    221             jQuery(document).ready(function(){
    222                 jQuery(".search-icon").keyup(function(){
    223                     jQuery(".fonts-count").hide();
    224                     // Retrieve the input field text and reset the count to zero
    225                     var filter = jQuery(this).val(), count = 0;
    226                     // Loop through the icon list
    227                     jQuery(".icons-list li").each(function(){
    228                         // If the list item does not contain the text phrase fade it out
    229                         if (jQuery(this).attr("data-icons-tag").search(new RegExp(filter, "i")) < 0) {
    230                             jQuery(this).fadeOut();
    231                         } else {
    232                             jQuery(this).show();
    233                             count++;
    234                         }
    235                         if(count == 0)
    236                         jQuery(".search-count").html(" ' . esc_js( __( 'Can\'t find the icon?', 'borderless' ) ) . ' <a href=\'#borderless_upload_icon\' class=\'button button-primary borderless_upload_icon\' data-target=\'iconfont_upload\' data-title=\' ' . esc_js( __( 'Upload/Select Fontello Font Zip', 'borderless' ) ) . ' \' data-type=\'application/octet-stream, application/zip\' data-button=\' ' . esc_js( __( 'Insert Fonts Zip File', 'borderless' ) ) . ' \' data-trigger=\'borderless_insert_zip\' data-class=\'media-frame\'>' . esc_js( __( 'Upload New Font Pack', 'borderless' ) ) . '</a>");
    237                         else
    238                         jQuery(".search-count").html(count+" ' . esc_js( __( 'Icons found.', 'borderless' ) ) . '");
    239                         jQuery( ".search-count" ).addClass( "search-count-open" );
    240                         if(filter == "")
    241                         jQuery(".fonts-count").show();
    242                     });
    243                 });
    244             });
    245             </script>';
    246             echo $script;
    247         }
    248        
    249         function add_zipped_font() {
    250             $cap = apply_filters( 'avf_file_upload_capability', 'update_plugins' );
    251             if ( ! current_user_can( $cap ) ) {
    252                 die( esc_html__( "Using this feature is reserved for Super Admins. You unfortunately don't have the necessary permissions.", "borderless" ) );
    253             }
    254             //get the file path of the zip file
    255             $attachment = $_POST['values'];
    256             $path       = realpath( get_attached_file( sanitize_text_field( $attachment['id'] ) ) );
    257             $unzipped   = $this->zip_flatten( $path, array( '\.eot', '\.svg', '\.ttf', '\.woff', '\.json', '\.css' ) );
    258             // if we were able to unzip the file and save it to our temp folder extract the svg file
    259             if ( $unzipped ) {
    260                 $this->create_config();
    261             }
    262             //if we got no name for the font dont add it and delete the temp folder
    263             if ( $this->ip_name == 'unknown' ) {
    264                 $this->delete_folder( $this->paths['tempdir'] );
    265                 die( esc_html__( 'Was not able to retrieve the Icon Pack name from your Uploaded Folder', 'borderless' ) );
    266             }
    267             die( esc_html__( 'borderless_font_added:', 'borderless' ) . $this->ip_name );
    268         }
    269        
    270         function remove_zipped_font() {
    271             //get the file path of the zip file
    272             $font   = sanitize_text_field( $_POST['del_font'] );
    273             $list   = self::load_iconfont_list();
    274             $delete = isset( $list[ $font ] ) ? $list[ $font ] : false;
    275             if ( $delete ) {
    276                 $this->delete_folder( $delete['include'] );
    277                 $this->remove_font( $font );
    278                 die( esc_html__( 'borderless_font_removed', 'borderless' ) );
    279             }
    280             die( esc_html__( 'Was not able to remove Icon Pack', 'borderless' ) );
    281         }
    282        
    283         //extract the zip file to a flat folder and remove the files that are not needed
    284         function zip_flatten( $zipfile, $filter ) {
    285             if ( is_dir( $this->paths['tempdir'] ) ) {
    286                 $this->delete_folder( $this->paths['tempdir'] );
    287                 $tempdir = borderless_backend_create_folder( $this->paths['tempdir'], false );
    288             } else {
    289                 $tempdir = borderless_backend_create_folder( $this->paths['tempdir'], false );
    290             }
    291             //$fontdir = borderless_backend_create_folder($this->paths['fontdir'], false);
    292             if ( ! $tempdir ) {
    293                 die( esc_html__( 'Could not create temporary folder.', 'borderless' ) );
    294             }
    295             $zip = new ZipArchive;
    296             if ( $zip->open( $zipfile ) ) {
    297                 for ( $i = 0; $i < $zip->numFiles; $i ++ ) {
    298                     $entry = $zip->getNameIndex( $i );
    299                     if ( ! empty( $filter ) ) {
    300                         $delete  = true;
    301                         $matches = array();
    302                         foreach ( $filter as $regex ) {
    303                             preg_match( "!" . $regex . "!", $entry, $matches );
    304                             if ( ! empty( $matches ) ) {
    305                                 $delete = false;
    306                                 break;
    307                             }
    308                         }
    309                     }
    310                     if ( substr( $entry, - 1 ) == '/' || ! empty( $delete ) ) {
    311                         continue;
    312                     } // skip directories and non matching files
    313                     $fp  = $zip->getStream( $entry );
    314                     $ofp = fopen( $this->paths['tempdir'] . '/' . basename( $entry ), 'w' );
    315                     if ( ! $fp ) {
    316                         die( esc_html__( 'Unable to unpack Icon Pack.', 'borderless' ) );
    317                     }
    318                     while ( ! feof( $fp ) ) {
    319                         fwrite( $ofp, fread( $fp, 8192 ) );
    320                     }
    321                     fclose( $fp );
    322                     fclose( $ofp );
    323                 }
    324                 $zip->close();
    325             } else {
    326                 die( esc_html__( "Icon Pack Zip file is corrupted.", 'borderless' ) );
    327             }
    328            
    329             return true;
    330         }
    331        
    332         //iterate over xml file and extract the glyphs for the font
    333         function create_config() {
    334             $this->json_file = $this->find_json();
    335             $this->svg_file  = $this->find_svg();
    336             if ( empty( $this->json_file ) || empty( $this->svg_file ) ) {
    337                 $this->delete_folder( $this->paths['tempdir'] );
    338                 die( esc_html__( 'SVG file or selection.json not found. Please check the integrity of the Icon Pack files.', 'borderless' ) );
    339             }
    340             //$response     = wp_remote_get( $this->paths['tempurl'].$this->svg_file );
    341             $response = wp_remote_fopen( trailingslashit( $this->paths['tempurl'] ) . $this->svg_file );
    342             //if wordpress wasnt able to get the file which is unlikely try to fetch it old school
    343             $json = file_get_contents( trailingslashit( $this->paths['tempdir'] ) . $this->json_file );
    344             if ( empty( $response ) ) {
    345                 $response = file_get_contents( trailingslashit( $this->paths['tempdir'] ) . $this->svg_file );
    346             }
    347             if ( ! is_wp_error( $json ) && ! empty( $json ) ) {
    348                 $xml             = simplexml_load_string( $response );
    349                 $font_attr       = $xml->defs->font->attributes();
    350                 $glyphs          = $xml->defs->font->children();
    351                 $this->ip_name = (string) $font_attr['id'];
    352                 $font_folder = trailingslashit( $this->paths['fontdir'] ) . $this->ip_name;
    353                 if ( is_dir( $font_folder ) ) {
    354                     $this->delete_folder( $this->paths['tempdir'] );
    355                     die( esc_html__( "There is already an Icon Pack with this name, add an icon with another name.", "borderless" ) );
    356                 }
    357                 $file_contents = json_decode( $json );
    358                 if ( ! isset( $file_contents->IcoMoonType ) ) {
    359                     $this->delete_folder( $this->paths['tempdir'] );
    360                     die( esc_html__( "This Icon Pack does not belong to Icomoon. Use only Icomoon's Icon Pack.", 'borderless' ) );
    361                 }
    362                 $icons = $file_contents->icons;
    363                 $n = 1;
    364                 foreach ( $icons as $icon ) {
    365                     $icon_name                                           = $icon->properties->name;
    366                     $icon_class                                          = str_replace( ' ', '', $icon_name );
    367                     $icon_class                                          = str_replace( ',', ' ', $icon_class );
    368                     $tags                                                = implode( ",", $icon->icon->tags );
    369                     $this->json_config[ $this->ip_name ][ $icon_name ] = array(
    370                         "class"   => $icon_class,
    371                         "tags"    => $tags
    372                     );
    373                     $n ++;
    374                 }
    375                 if ( ! empty( $this->json_config ) && $this->ip_name != 'unknown' ) {
    376                     $this->write_config();
    377                     $this->re_write_css();
    378                     $this->rename_files();
    379                     $this->rename_folder();
    380                     $this->add_font();
    381                 }
    382             }
    383            
    384             return false;
    385         }
    386        
    387         //writes the php config file for the font
    388         function write_config() {
    389             $charmap = $this->paths['tempdir'] . '/' . $this->paths['config'];
    390             $handle  = @fopen( $charmap, 'w' );
    391             if ( $handle ) {
    392                 fwrite( $handle, '<?php $icons = array();' );
    393                 foreach ( $this->json_config[ $this->ip_name ] as $icon => $info ) {
    394                     if ( ! empty( $info ) ) {
    395                         $delimiter = "'";
    396                         fwrite( $handle, "\r\n" . '$icons[\'' . $this->ip_name . '\'][' . $delimiter . $icon . $delimiter . '] = array("class"=>' . $delimiter . $info["class"] . $delimiter . ',"tags"=>' . $delimiter . $info["tags"] . $delimiter . ');' );
    397                     } else {
    398                         $this->delete_folder( $this->paths['tempdir'] );
    399                         die( esc_html__( 'Error generating configuration file.', 'borderless' ) );
    400                     }
    401                 }
    402                 fclose( $handle );
    403             } else {
    404                 $this->delete_folder( $this->paths['tempdir'] );
    405                 die( esc_html__( 'Error generating configuration file.', 'borderless' ) );
    406             }
    407         }
    408        
    409         //re-writes the php config file for the font
    410         function re_write_css() {
    411             $style = $this->paths['tempdir'] . '/style.css';
    412             $file  = @file_get_contents( $style );
    413             if ( $file ) {
    414                 $str = str_replace( 'fonts/', '', $file );
    415                 $str = str_replace( 'icon-', $this->ip_name . '-', $str );
    416                 $str = str_replace( '.icon {', '[class^="' . $this->ip_name . '-"], [class*=" ' . $this->ip_name . '-"] {', $str );
    417                     $str = str_replace( 'i {', '[class^="' . $this->ip_name . '-"], [class*=" ' . $this->ip_name . '-"] {', $str );
    418                        
    419                         /* remove comments */
    420                         $str = preg_replace( '!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $str );
    421                        
    422                         /* remove tabs, spaces, newlines, etc. */
    423                         $str = str_replace( array( "\r\n", "\r", "\n", "\t", '  ', '    ', '    ' ), '', $str );
    424                        
    425                         @file_put_contents( $style, $str );
    426                     } else {
    427                         die( esc_html__( "Error generating CSS file. Use only Icomoon's Icon Pack.", 'borderless' ) );
    428                     }
    429                 }
    430                
    431                 function rename_files() {
    432                     $extensions = array( 'eot', 'svg', 'ttf', 'woff', 'css' );
    433                     $folder     = trailingslashit( $this->paths['tempdir'] );
    434                     foreach ( glob( $folder . '*' ) as $file ) {
    435                         $path_parts = pathinfo( $file );
    436                         if ( strpos( $path_parts['filename'], '.dev' ) === false && in_array( $path_parts['extension'], $extensions ) ) {
    437                             if ( $path_parts['filename'] !== $this->ip_name ) {
    438                                 rename( $file, trailingslashit( $path_parts['dirname'] ) . $this->ip_name . '.' . $path_parts['extension'] );
    439                             }
    440                         }
    441                     }
    442                 }
    443                
    444                 //rename the temp folder and all its font files
    445                 function rename_folder() {
    446                     $new_name = trailingslashit( $this->paths['fontdir'] ) . $this->ip_name;
    447                     //delete folder and contents if they already exist
    448                     $this->delete_folder( $new_name );
    449                     if ( rename( $this->paths['tempdir'], $new_name ) ) {
    450                         return true;
    451                     } else {
    452                         $this->delete_folder( $this->paths['tempdir'] );
    453                         die( esc_html__( "This Icon Pack could not be added.", "borderless" ) );
    454                     }
    455                 }
    456                
    457                 //delete a folder
    458                 function delete_folder( $new_name ) {
    459                     //delete folder and contents if they already exist
    460                     if ( is_dir( $new_name ) ) {
    461                         $objects = scandir( $new_name );
    462                         foreach ( $objects as $object ) {
    463                             if ( $object != "." && $object != ".." ) {
    464                                 unlink( $new_name . "/" . $object );
    465                             }
    466                         }
    467                         reset( $objects );
    468                         rmdir( $new_name );
    469                     } else {
    470                         echo $new_name . ' no found<br/>';
    471                     }
    472                 }
    473                
    474                 function add_font() {
    475                     $fonts = get_option( 'borderless_icon_fonts' );
    476                     if ( empty( $fonts ) ) {
    477                         $fonts = array();
    478                     }
    479                     $fonts[ $this->ip_name ] = array(
    480                         'include' => sanitize_text_field( trailingslashit( $this->paths['fonts'] ) ) . $this->ip_name,
    481                         'folder'  => sanitize_text_field( trailingslashit( $this->paths['fonts'] ) ) . $this->ip_name,
    482                         'style'   => $this->ip_name . '/' . $this->ip_name . '.css',
    483                         'config'  => sanitize_text_field( $this->paths['config'] )
    484                     );
    485                     update_option( 'borderless_icon_fonts', $fonts );
    486                 }
    487                
    488                 function remove_font( $font ) {
    489                     $fonts = get_option( 'borderless_icon_fonts' );
    490                     if ( isset( $fonts[ $font ] ) ) {
    491                         unset( $fonts[ $font ] );
    492                         update_option( 'borderless_icon_fonts', $fonts );
    493                     }
    494                 }
    495                
    496                 //finds the json file we need to create the config
    497                 function find_json() {
    498                     $files = scandir( $this->paths['tempdir'] );
    499                     foreach ( $files as $file ) {
    500                         if ( strpos( strtolower( $file ), '.json' ) !== false && $file[0] != '.' ) {
    501                             return $file;
    502                         }
    503                     }
    504                 }
    505                
    506                 //finds the svg file we need to create the config
    507                 function find_svg() {
    508                     $files = scandir( $this->paths['tempdir'] );
    509                     foreach ( $files as $file ) {
    510                         if ( strpos( strtolower( $file ), '.svg' ) !== false && $file[0] != '.' ) {
    511                             return $file;
    512                         }
    513                     }
    514                 }
    515                
    516                 static function load_iconfont_list() {
    517                     if ( ! empty( self::$ip_list ) ) {
    518                         return self::$ip_list;
    519                     }
    520                     $extra_fonts = get_option( 'borderless_icon_fonts' );
    521                     if ( empty( $extra_fonts ) ) {
    522                         $extra_fonts = array();
    523                     }
    524                     $font_configs = $extra_fonts;//array_merge(borderlessBuilder::$default_iconfont, $extra_fonts);
    525                     //if we got any include the charmaps and add the chars to an array
    526                     $upload_dir = wp_upload_dir();
    527                     $path       = trailingslashit( $upload_dir['basedir'] );
    528                     $url        = trailingslashit( $upload_dir['baseurl'] );
    529                     foreach ( $font_configs as $key => $config ) {
    530                         if ( empty( $config['full_path'] ) ) {
    531                             $font_configs[ $key ]['include'] = $path . $font_configs[ $key ]['include'];
    532                             $font_configs[ $key ]['folder']  = $url . $font_configs[ $key ]['folder'];
    533                         }
    534                     }
    535                     //cache the result
    536                     self::$ip_list = $font_configs;
    537                    
    538                     return $font_configs;
    539                 }
    540             }// End class
    541            
    542             /*
    543             * creates a folder for the theme framework
    544             */
    545            
    546             if ( ! function_exists( 'borderless_backend_create_folder' ) ) {
    547                 function borderless_backend_create_folder( &$folder, $addindex = true ) {
    548                     if ( is_dir( $folder ) && $addindex == false ) {
    549                         return true;
    550                     }
    551                     $created = wp_mkdir_p( trailingslashit( $folder ) );
    552                     @chmod( $folder, 0777 );
    553                     if ( $addindex == false ) {
    554                         return $created;
    555                     }
    556                     $index_file = trailingslashit( $folder ) . 'index.php';
    557                     if ( file_exists( $index_file ) ) {
    558                         return $created;
    559                     }
    560                     $handle = @fopen( $index_file, 'w' );
    561                     if ( $handle ) {
    562                         fwrite( $handle, "<?php\r\necho 'We're sorry for the inconvenience, but you're not allowed to browse the directory.';\r\n?>
    563                         " );
    564                         fclose( $handle );
    565                     }
    566                    
    567                     return $created;
    568                 }
    569             }
    570             // Instantiate the Icon Fonts
    571             new Borderless_IF;
    572         }
    573        
    574         function borderless_custom_icons_menu() {
    575             $Borderless_IF = new Borderless_IF;
    576             $Borderless_IF->icon_pack_manager();
    577         }
    578        
    579         function borderless_custom_icons() {
    580             $upload_paths = wp_upload_dir();
    581             $custom_fonts = get_option( 'borderless_icon_fonts' );
    582             if ( is_array( $custom_fonts ) ) {
    583                 foreach ( $custom_fonts as $font => $info ) {
    584                     if ( strpos( $info['style'], 'http://' ) !== false ) {
    585                         wp_enqueue_style( 'borderless-' . $font, $info['style'], null, '1.0', 'all' );
    586                     } else {
    587                         wp_enqueue_style( 'borderless-' . $font, trailingslashit( $upload_paths['baseurl'] . '/borderless_icon_fonts/' ) . $info['style'], null, '1.0', 'all' );
    588                     }
    589                 }
    590             }
    591         }
    592        
    593         add_action( 'wp_enqueue_scripts', 'borderless_custom_icons' );
     7    class Borderless_IF {
     8        var $paths = array();
     9        var $svg_file;
     10        var $json_file;
     11        var $ip_name = 'unknown';
     12        var $svg_config = array();
     13        var $json_config = array();
     14        static $ip_list = array();
     15       
     16        function __construct() {
     17            $this->paths            = wp_upload_dir();
     18            $this->paths['fonts']   = 'borderless_icon_fonts';
     19            $this->paths['temp']    = trailingslashit( $this->paths['fonts'] ) . 'borderless_temp';
     20            $this->paths['fontdir'] = trailingslashit( $this->paths['basedir'] ) . $this->paths['fonts'];
     21            $this->paths['tempdir'] = trailingslashit( $this->paths['basedir'] ) . $this->paths['temp'];
     22            $this->paths['fonturl'] = set_url_scheme( trailingslashit( $this->paths['baseurl'] ) . $this->paths['fonts'] );
     23            $this->paths['tempurl'] = trailingslashit( $this->paths['baseurl'] ) . trailingslashit( $this->paths['temp'] );
     24            $this->paths['config']  = 'charmap.php';
     25
     26            add_action( 'wp_ajax_borderless_ajax_add_zipped_font', array( $this, 'add_zipped_font' ) );
     27            add_action( 'wp_ajax_borderless_ajax_remove_zipped_font', array( $this, 'remove_zipped_font' ) );
     28        }
     29       
     30        /**
     31         * Loads admin scripts and styles
     32         */
     33        function admin_scripts() {
     34            $upload_paths = wp_upload_dir();
     35            wp_enqueue_script( 'borderless-admin-media', plugin_dir_url( __FILE__ ) . 'assets/js/icon-manager.min.js', array( 'jquery' ) );
     36            wp_enqueue_script( 'media-upload' );
     37            wp_enqueue_media();
     38            wp_enqueue_style( 'borderless-wpbakery-icon-manager-admin', plugin_dir_url( __FILE__ ) . 'assets/css/icon-manager.css' );
     39            $custom_fonts = get_option( 'borderless_icon_fonts' );
     40            if ( is_array( $custom_fonts ) ) {
     41                foreach ( $custom_fonts as $font => $info ) {
     42                    if ( strpos( $info['style'], 'http://' ) !== false ) {
     43                        wp_enqueue_style( 'borderless-' . $font, $info['style'], null, '1.0', 'all' );
     44                    } else {
     45                        wp_enqueue_style( 'borderless-' . $font, trailingslashit( $upload_paths['baseurl'] . '/borderless_icon_fonts/' ) . $info['style'], null, '1.0', 'all' );
     46                    }
     47                }
     48            }
     49        }
     50       
     51        /**
     52         * Creates an icon selector interface
     53         */
     54        public function get_icon_manager( $input_name, $icon ) {
     55            $font_manager = self::get_font_manager( $id );
     56            $output       = '<div class="my_param_block">';
     57            $output      .= '<input name="' . $input_name . '" class="textinput ' . $input_name . ' text_field" type="text" value="' . $icon . '"/>';
     58            $output      .= '</div>';
     59            $output      .= '<script type="text/javascript">
     60            jQuery(document).ready(function(){
     61                jQuery(".icon-manager-preview-icon-' . $id . '").html("<i class=\'' . $icon . '\'></i>");
     62                jQuery(".icons-list-' . $id . ' li[data-icons=\'' . $icon . '\']").addClass("selected");
     63            });
     64            jQuery(".icons-list-' . $id . ' li").click(function() {
     65                jQuery(this).attr("class","selected").siblings().removeAttr("class");
     66                var icon = jQuery(this).attr("data-icons");
     67                jQuery("input[name=\'' . $input_name . '\']").val(icon);
     68                jQuery(".icon-manager-preview-icon-' . $id . '").html("<i class=\'"+icon+"\'></i>");
     69            });
     70            </script>';
     71            $output      .= $font_manager;
     72           
     73            return $output;
     74        }
     75       
     76        /**
     77         * Generates the list of icons in the manager
     78         */
     79        public function get_font_manager( $id ) {
     80            $fonts  = get_option( 'borderless_icon_fonts' );
     81            $output = '<div class="icon-manager-preview"><div class="icon-manager-preview-icon preview-icon-' . $id . '"><i class=""></i></div><input class="icon-manager-search-icon" type="text" placeholder="Search for a suitable icon.." /></div>';
     82            $output .= '<div id="icon-manager-search-icon-inner">';
     83            $output .= '<ul class="icons-list borderless_icon icon-list-' . $id . '">';
     84           
     85            foreach ( $fonts as $font => $info ) {
     86                $icon_set   = array();
     87                $icons      = array();
     88                $upload_dir = wp_upload_dir();
     89                $path       = trailingslashit( $upload_dir['basedir'] );
     90                $file       = $path . $info['include'] . '/' . $info['config'];
     91
     92                include( $file );
     93                if ( ! empty( $icons ) ) {
     94                    $icon_set = array_merge( $icon_set, $icons );
     95                }
     96
     97                $set_name = ucfirst( $font );
     98               
     99                if ( ! empty( $icon_set ) ) {
     100                    $output .= '<p><strong>' . $set_name . '</strong></p>';
     101                    $output .= '<li title="no-icon" data-icons="none" data-icons-tag="none,blank" style="cursor: pointer;" id="' . $id . '"></li>';
     102                    foreach ( $icon_set as $icons ) {
     103                        foreach ( $icons as $icon ) {
     104                            $output .= '<li title="' . $icon['class'] . '" data-icons="' . $font . '-' . $icon['class'] . '" data-icons-tag="' . $icon['tags'] . '" id="' . $id . '">';
     105                            $output .= '<i class="icon-manager-icon ' . $font . '-' . $icon['class'] . '"></i><label class="icon">' . $icon['class'] . '</label></li>';
     106                        }
     107                    }
     108                }
     109            }
     110            $output .= '</ul>';
     111            $output .= '<script type="text/javascript">
     112            jQuery(document).ready(function(){
     113                jQuery(".icon-manager-search-icon").keyup(function(){
     114                    var filter = jQuery(this).val(), count = 0;
     115                    jQuery(".icons-list li").each(function(){
     116                        if ( jQuery(this).attr("data-icons-tag").search(new RegExp(filter, "i")) < 0 ) {
     117                            jQuery(this).fadeOut();
     118                        } else {
     119                            jQuery(this).show();
     120                            count++;
     121                        }
     122                    });
     123                });
     124            });
     125            </script>';
     126            $output .= '</div>';
     127           
     128            return $output;
     129        }
     130       
     131        /**
     132         * Generates the Icon Pack Manager page
     133         */
     134        function icon_pack_manager() {
     135            ?>
     136            <div class="wrap">
     137                <h2>
     138                    <?php esc_html_e( 'Icon Pack Manager', 'borderless' ); ?>
     139                    <a href="#borderless_upload_icon" class="button button-primary borderless-upload-icon"
     140                       data-target="iconfont_upload"
     141                       data-title="<?php echo esc_html__( "Upload or Select Fontello Font Zip", "borderless" ); ?>"
     142                       data-type="application/octet-stream, application/zip"
     143                       data-button="<?php echo esc_html__( "Insert Fonts Zip File", "borderless" ); ?>"
     144                       data-trigger="borderless_insert_zip"
     145                       data-class="media-frame ">
     146                       <?php esc_html_e( 'Add New Icon Pack', 'borderless' ); ?>
     147                    </a> &nbsp;<span class="spinner"></span>
     148                </h2>
     149                <div id="msg"></div>
     150            <?php
     151            $fonts = get_option( 'borderless_icon_fonts' );
     152            if ( is_array( $fonts ) ) :
     153                ?>
     154                <div class="metabox-holder meta-search">
     155                    <div class="postbox borderless-postbox-search">
     156                        <h2 class="hndle ui-sortable-handle"><span>Search for Icons</span></h2>
     157                        <div class="inside">
     158                            <div class="search-area">
     159                                <input class="search-icon" type="text" placeholder="<?php esc_attr_e( 'Start typing to search', 'borderless' ); ?>"/>
     160                                <span class="search-count"></span>
     161                            </div>
     162                        </div>
     163                    </div>
     164                </div>
     165                <?php self::get_ipm(); ?>
     166            </div>
     167            <?php else: ?>
     168                <div class="error">
     169                    <p>
     170                        <?php esc_html_e( 'No icon pack uploaded. Please upload at least one icon pack to display here.', 'borderless' ); ?>
     171                    </p>
     172                </div>
     173            <?php
     174            endif;
     175        }
     176       
     177        /**
     178         * Generates Icon Pack Preview and settings
     179         */
     180        static function get_ipm() {
     181            $fonts = get_option( 'borderless_icon_fonts' );
     182            $n     = count( $fonts );
     183            foreach ( $fonts as $font => $info ) {
     184                $icon_set   = array();
     185                $icons      = array();
     186                $upload_dir = wp_upload_dir();
     187                $path       = trailingslashit( $upload_dir['basedir'] );
     188                $file       = $path . $info['include'] . '/' . $info['config'];
     189                $output     = '<div class="icon_set-' . $font . ' metabox-holder">';
     190                $output    .= '<div class="postbox borderless-postbox-icon-manager">';
     191
     192                include( $file );
     193                if ( ! empty( $icons ) ) {
     194                    $icon_set = array_merge( $icon_set, $icons );
     195                }
     196               
     197                if ( ! empty( $icon_set ) ) {
     198                    foreach ( $icon_set as $icons ) {
     199                        $count = count( $icons );
     200                    }
     201                   
     202                    $output .= '<h3 class="ip_name"><strong>' . esc_html( ucfirst( $font ) ) . '</strong>';
     203                    $output .= '<span class="fonts-count wp-core-ui wp-ui-notification count-' . esc_attr( $font ) . '">' . esc_html( $count ) . '</span>';
     204                   
     205                    if ( $n != 1 ) {
     206                        $output .= '<button class="button button-primary button-small borderless_del_icon" data-delete=' . esc_attr( $font ) . ' data-title="' . esc_attr__( 'Remove Pack', 'borderless' ) . '">' . esc_html__( 'Remove Pack', 'borderless' ) . '</button>';
     207                    }
     208                    $output .= '</h3>';
     209                    $output .= '<div class="inside"><div class="icon_actions"></div>';
     210                    $output .= '<div class="icon_search"><ul class="icons-list borderless_icon">';
     211                   
     212                    foreach ( $icon_set as $icons ) {
     213                        foreach ( $icons as $icon ) {
     214                            $output .= '<li data-icons="' . esc_attr( $icon['class'] ) . '" data-icons-tag="' . esc_attr( $icon['tags'] ) . '">';
     215                            $output .= '<i class="' . esc_attr( $font ) . '-' . esc_attr( $icon['class'] ) . '"></i><a class="tooltips" href="#"><span>' . esc_html( $icon['class'] ) . '</span></a></li>';
     216                        }
     217                    }
     218                    $output .= '</ul>';
     219                    $output .= '</div><!-- .icon_search-->';
     220                    $output .= '</div><!-- .inside-->';
     221                    $output .= '</div><!-- .postbox-->';
     222                    $output .= '</div><!-- .icon_set-' . esc_html( $font ) . ' -->';
     223                    echo $output;
     224                }
     225            }
     226            $script = '<script type="text/javascript">
     227            jQuery(document).ready(function(){
     228                jQuery(".search-icon").keyup(function(){
     229                    jQuery(".fonts-count").hide();
     230                    var filter = jQuery(this).val(), count = 0;
     231                    jQuery(".icons-list li").each(function(){
     232                        if (jQuery(this).attr("data-icons-tag").search(new RegExp(filter, "i")) < 0) {
     233                            jQuery(this).fadeOut();
     234                        } else {
     235                            jQuery(this).show();
     236                            count++;
     237                        }
     238                        if(count === 0) {
     239                            jQuery(".search-count").html("Can\'t find the icon? <a href=\'#borderless_upload_icon\' class=\'button button-primary borderless_upload_icon\' data-target=\'iconfont_upload\' data-title=\'Upload or Select Fontello Font Zip\' data-type=\'application/octet-stream, application/zip\' data-button=\'Insert Fonts Zip File\' data-trigger=\'borderless_insert_zip\' data-class=\'media-frame\'>Upload New Font Pack</a>");
     240                        } else {
     241                            jQuery(".search-count").html(count + " Icons found.");
     242                        }
     243                        jQuery(".search-count").addClass("search-count-open");
     244                        if(filter === "") {
     245                            jQuery(".fonts-count").show();
     246                        }
     247                    });
     248                });
     249            });
     250            </script>';
     251            echo $script;
     252        }
     253       
     254        /**
     255         * Handles the Ajax call for adding a zipped font
     256         */
     257        function add_zipped_font() {
     258            $cap = apply_filters( 'avf_file_upload_capability', 'update_plugins' );
     259            if ( ! current_user_can( $cap ) ) {
     260                die( esc_html__( "You do not have sufficient permissions to use this feature.", "borderless" ) );
     261            }
     262            // Retrieve the file path of the zip file
     263            $attachment = $_POST['values'];
     264            $path       = realpath( get_attached_file( sanitize_text_field( $attachment['id'] ) ) );
     265            $unzipped   = $this->zip_flatten( $path, array( '\.eot', '\.svg', '\.ttf', '\.woff', '\.json', '\.css' ) );
     266           
     267            // If we managed to unzip the file and save it, extract the SVG file
     268            if ( $unzipped ) {
     269                $this->create_config();
     270            }
     271           
     272            // If we did not get a name for the font, do not add it and remove the temp folder
     273            if ( $this->ip_name == 'unknown' ) {
     274                $this->delete_folder( $this->paths['tempdir'] );
     275                die( esc_html__( 'Unable to retrieve the Icon Pack name from your uploaded folder.', 'borderless' ) );
     276            }
     277            die( esc_html__( 'borderless_font_added:', 'borderless' ) . $this->ip_name );
     278        }
     279       
     280        /**
     281         * Handles the Ajax call for removing a zipped font
     282         */
     283        function remove_zipped_font() {
     284            // Nonce verification for CSRF protection
     285            check_ajax_referer( 'borderless_remove_zipped_font_nonce', 'security' );
     286           
     287            // Capability check to ensure only authorized users can delete
     288            $cap = apply_filters( 'avf_file_upload_capability', 'update_plugins' );
     289            if ( ! current_user_can( $cap ) ) {
     290                die( esc_html__( "You do not have sufficient permissions to use this feature.", "borderless" ) );
     291            }
     292           
     293            // Retrieve the font to be deleted
     294            $font   = sanitize_text_field( $_POST['del_font'] );
     295            $list   = self::load_iconfont_list();
     296            $delete = isset( $list[ $font ] ) ? $list[ $font ] : false;
     297            if ( $delete ) {
     298                $this->delete_folder( $delete['include'] );
     299                $this->remove_font( $font );
     300                die( esc_html__( 'borderless_font_removed', 'borderless' ) );
     301            }
     302            die( esc_html__( 'Unable to remove Icon Pack', 'borderless' ) );
     303        }
     304       
     305        /**
     306         * Unzips a font file to a flat folder and removes unneeded files
     307         */
     308        function zip_flatten( $zipfile, $filter ) {
     309            if ( is_dir( $this->paths['tempdir'] ) ) {
     310                $this->delete_folder( $this->paths['tempdir'] );
     311                $tempdir = borderless_backend_create_folder( $this->paths['tempdir'], false );
     312            } else {
     313                $tempdir = borderless_backend_create_folder( $this->paths['tempdir'], false );
     314            }
     315            if ( ! $tempdir ) {
     316                die( esc_html__( 'Could not create the temporary folder.', 'borderless' ) );
     317            }
     318           
     319            $zip = new ZipArchive;
     320            if ( $zip->open( $zipfile ) ) {
     321                for ( $i = 0; $i < $zip->numFiles; $i++ ) {
     322                    $entry = $zip->getNameIndex( $i );
     323                    if ( ! empty( $filter ) ) {
     324                        $delete  = true;
     325                        $matches = array();
     326                        foreach ( $filter as $regex ) {
     327                            preg_match( "!" . $regex . "!", $entry, $matches );
     328                            if ( ! empty( $matches ) ) {
     329                                $delete = false;
     330                                break;
     331                            }
     332                        }
     333                    }
     334                    // Skip directories and non-matching files
     335                    if ( substr( $entry, -1 ) == '/' || ! empty( $delete ) ) {
     336                        continue;
     337                    }
     338                    $fp  = $zip->getStream( $entry );
     339                    $ofp = fopen( $this->paths['tempdir'] . '/' . basename( $entry ), 'w' );
     340                    if ( ! $fp ) {
     341                        die( esc_html__( 'Unable to unpack the Icon Pack.', 'borderless' ) );
     342                    }
     343                    while ( ! feof( $fp ) ) {
     344                        fwrite( $ofp, fread( $fp, 8192 ) );
     345                    }
     346                    fclose( $fp );
     347                    fclose( $ofp );
     348                }
     349                $zip->close();
     350            } else {
     351                die( esc_html__( "The Icon Pack zip file is corrupted.", 'borderless' ) );
     352            }
     353           
     354            return true;
     355        }
     356       
     357        /**
     358         * Reads JSON and SVG files, sanitizes them, and prepares the config
     359         */
     360        function create_config() {
     361            $this->json_file = $this->find_json();
     362            $this->svg_file  = $this->find_svg();
     363            if ( empty( $this->json_file ) || empty( $this->svg_file ) ) {
     364                $this->delete_folder( $this->paths['tempdir'] );
     365                die( esc_html__( 'SVG file or selection.json not found. Please check the integrity of the Icon Pack files.', 'borderless' ) );
     366            }
     367
     368            // Attempt to read the SVG file
     369            $response = wp_remote_fopen( trailingslashit( $this->paths['tempurl'] ) . $this->svg_file );
     370            $json     = file_get_contents( trailingslashit( $this->paths['tempdir'] ) . $this->json_file );
     371
     372            if ( empty( $response ) ) {
     373                $response = file_get_contents( trailingslashit( $this->paths['tempdir'] ) . $this->svg_file );
     374            }
     375
     376            if ( ! is_wp_error( $json ) && ! empty( $json ) ) {
     377                // Load and parse the SVG
     378                $xml       = simplexml_load_string( $response );
     379                $font_attr = $xml->defs->font->attributes();
     380                $glyphs    = $xml->defs->font->children();
     381
     382                // Sanitize the font name (ip_name)
     383                $this->ip_name = (string) $font_attr['id'];
     384                $this->ip_name = sanitize_text_field( $this->ip_name );
     385
     386                $font_folder = trailingslashit( $this->paths['fontdir'] ) . $this->ip_name;
     387                if ( is_dir( $font_folder ) ) {
     388                    $this->delete_folder( $this->paths['tempdir'] );
     389                    die( esc_html__( "There is already an Icon Pack with this name. Please upload with another name.", "borderless" ) );
     390                }
     391
     392                // Decode JSON content
     393                $file_contents = json_decode( $json );
     394                if ( ! isset( $file_contents->IcoMoonType ) ) {
     395                    $this->delete_folder( $this->paths['tempdir'] );
     396                    die( esc_html__( "This Icon Pack is not an Icomoon pack. Use only Icomoon Icon Pack files.", 'borderless' ) );
     397                }
     398               
     399                // Iterate over icons to build $this->json_config
     400                $icons = $file_contents->icons;
     401                foreach ( $icons as $icon ) {
     402                    // Sanitize each piece of data to prevent injection
     403                    $raw_name   = isset( $icon->properties->name ) ? $icon->properties->name : 'unknown';
     404                    $icon_name  = sanitize_text_field( $raw_name );
     405                   
     406                    // Create a "class" by removing spaces and sanitizing further
     407                    $icon_class = str_replace( ' ', '', $icon_name );
     408                    // Remove any other characters that are not typical in a CSS class
     409                    $icon_class = preg_replace( '/[^A-Za-z0-9\-_]/', '', $icon_class );
     410                   
     411                    $raw_tags   = isset( $icon->icon->tags ) ? $icon->icon->tags : array();
     412                    // Sanitize each tag
     413                    $safe_tags  = array_map( 'sanitize_text_field', $raw_tags );
     414                    $tags       = implode( ",", $safe_tags );
     415                   
     416                    $this->json_config[ $this->ip_name ][ $icon_name ] = array(
     417                        "class" => $icon_class,
     418                        "tags"  => $tags
     419                    );
     420                }
     421
     422                if ( ! empty( $this->json_config ) && $this->ip_name != 'unknown' ) {
     423                    $this->write_config();
     424                    $this->re_write_css();
     425                    $this->rename_files();
     426                    $this->rename_folder();
     427                    $this->add_font();
     428                }
     429            }
     430
     431            return false;
     432        }
     433       
     434        /**
     435         * Writes the charmap.php config file with sanitized data
     436         */
     437        function write_config() {
     438            $charmap = $this->paths['tempdir'] . '/' . $this->paths['config'];
     439            $handle  = @fopen( $charmap, 'w' );
     440            if ( $handle ) {
     441                fwrite( $handle, '<?php $icons = array();' );
     442               
     443                // Safely build the PHP array with sanitized content
     444                foreach ( $this->json_config[ $this->ip_name ] as $icon => $info ) {
     445                    if ( ! empty( $info ) ) {
     446                        $delimiter   = "'";
     447                        $safe_icon   = esc_attr( $icon );
     448                        $safe_class  = esc_attr( $info["class"] );
     449                        $safe_tags   = esc_attr( $info["tags"] );
     450
     451                        fwrite( $handle, "\r\n" . '$icons[\'' . $this->ip_name . '\'][' . $delimiter . $safe_icon . $delimiter . '] = array("class"=>' . $delimiter . $safe_class . $delimiter . ',"tags"=>' . $delimiter . $safe_tags . $delimiter . ');' );
     452                    } else {
     453                        $this->delete_folder( $this->paths['tempdir'] );
     454                        die( esc_html__( 'Error generating the configuration file.', 'borderless' ) );
     455                    }
     456                }
     457                fclose( $handle );
     458            } else {
     459                $this->delete_folder( $this->paths['tempdir'] );
     460                die( esc_html__( 'Error generating the configuration file.', 'borderless' ) );
     461            }
     462        }
     463       
     464        /**
     465         * Rewrites the CSS file to replace paths and standardize classes
     466         */
     467        function re_write_css() {
     468            $style = $this->paths['tempdir'] . '/style.css';
     469            $file  = @file_get_contents( $style );
     470            if ( $file ) {
     471                $str = str_replace( 'fonts/', '', $file );
     472                $str = str_replace( 'icon-', $this->ip_name . '-', $str );
     473                $str = str_replace( '.icon {', '[class^="' . $this->ip_name . '-"], [class*=" ' . $this->ip_name . '-"] {', $str );
     474                $str = str_replace( 'i {', '[class^="' . $this->ip_name . '-"], [class*=" ' . $this->ip_name . '-"] {', $str );
     475               
     476                // Remove comments
     477                $str = preg_replace( '!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $str );
     478                // Remove tabs, spaces, newlines, etc.
     479                $str = str_replace( array( "\r\n", "\r", "\n", "\t", '  ', '    ', '    ' ), '', $str );
     480               
     481                @file_put_contents( $style, $str );
     482            } else {
     483                die( esc_html__( "Error generating the CSS file. Make sure you are using Icomoon's Icon Pack.", 'borderless' ) );
     484            }
     485        }
     486       
     487        /**
     488         * Renames font files to match the sanitized ip_name
     489         */
     490        function rename_files() {
     491            $extensions = array( 'eot', 'svg', 'ttf', 'woff', 'css' );
     492            $folder     = trailingslashit( $this->paths['tempdir'] );
     493            foreach ( glob( $folder . '*' ) as $file ) {
     494                $path_parts = pathinfo( $file );
     495                if ( strpos( $path_parts['filename'], '.dev' ) === false && in_array( $path_parts['extension'], $extensions ) ) {
     496                    if ( $path_parts['filename'] !== $this->ip_name ) {
     497                        rename( $file, trailingslashit( $path_parts['dirname'] ) . $this->ip_name . '.' . $path_parts['extension'] );
     498                    }
     499                }
     500            }
     501        }
     502       
     503        /**
     504         * Renames the temporary folder to a final folder
     505         */
     506        function rename_folder() {
     507            $new_name = trailingslashit( $this->paths['fontdir'] ) . $this->ip_name;
     508            // Delete folder if it already exists
     509            $this->delete_folder( $new_name );
     510            if ( rename( $this->paths['tempdir'], $new_name ) ) {
     511                return true;
     512            } else {
     513                $this->delete_folder( $this->paths['tempdir'] );
     514                die( esc_html__( "This Icon Pack could not be added.", "borderless" ) );
     515            }
     516        }
     517       
     518        /**
     519         * Deletes a given folder and its contents
     520         */
     521        function delete_folder( $new_name ) {
     522            if ( is_dir( $new_name ) ) {
     523                $objects = scandir( $new_name );
     524                foreach ( $objects as $object ) {
     525                    if ( $object != "." && $object != ".." ) {
     526                        @unlink( $new_name . "/" . $object );
     527                    }
     528                }
     529                reset( $objects );
     530                @rmdir( $new_name );
     531            }
     532        }
     533       
     534        /**
     535         * Adds new font info to the WP option 'borderless_icon_fonts'
     536         */
     537        function add_font() {
     538            $fonts = get_option( 'borderless_icon_fonts' );
     539            if ( empty( $fonts ) ) {
     540                $fonts = array();
     541            }
     542            $fonts[ $this->ip_name ] = array(
     543                'include' => sanitize_text_field( trailingslashit( $this->paths['fonts'] ) ) . $this->ip_name,
     544                'folder'  => sanitize_text_field( trailingslashit( $this->paths['fonts'] ) ) . $this->ip_name,
     545                'style'   => $this->ip_name . '/' . $this->ip_name . '.css',
     546                'config'  => sanitize_text_field( $this->paths['config'] )
     547            );
     548            update_option( 'borderless_icon_fonts', $fonts );
     549        }
     550       
     551        /**
     552         * Removes specified font info from the WP option
     553         */
     554        function remove_font( $font ) {
     555            $fonts = get_option( 'borderless_icon_fonts' );
     556            if ( isset( $fonts[ $font ] ) ) {
     557                unset( $fonts[ $font ] );
     558                update_option( 'borderless_icon_fonts', $fonts );
     559            }
     560        }
     561       
     562        /**
     563         * Finds the first JSON file in the temp folder
     564         */
     565        function find_json() {
     566            $files = scandir( $this->paths['tempdir'] );
     567            foreach ( $files as $file ) {
     568                if ( strpos( strtolower( $file ), '.json' ) !== false && $file[0] != '.' ) {
     569                    return $file;
     570                }
     571            }
     572            return null;
     573        }
     574       
     575        /**
     576         * Finds the first SVG file in the temp folder
     577         */
     578        function find_svg() {
     579            $files = scandir( $this->paths['tempdir'] );
     580            foreach ( $files as $file ) {
     581                if ( strpos( strtolower( $file ), '.svg' ) !== false && $file[0] != '.' ) {
     582                    return $file;
     583                }
     584            }
     585            return null;
     586        }
     587       
     588        /**
     589         * Loads the list of iconfonts from the WP option (cached locally)
     590         */
     591        static function load_iconfont_list() {
     592            if ( ! empty( self::$ip_list ) ) {
     593                return self::$ip_list;
     594            }
     595            $extra_fonts = get_option( 'borderless_icon_fonts' );
     596            if ( empty( $extra_fonts ) ) {
     597                $extra_fonts = array();
     598            }
     599            $font_configs = $extra_fonts;
     600            $upload_dir   = wp_upload_dir();
     601            $path         = trailingslashit( $upload_dir['basedir'] );
     602            $url          = trailingslashit( $upload_dir['baseurl'] );
     603
     604            foreach ( $font_configs as $key => $config ) {
     605                if ( empty( $config['full_path'] ) ) {
     606                    $font_configs[ $key ]['include'] = $path . $font_configs[ $key ]['include'];
     607                    $font_configs[ $key ]['folder']  = $url . $font_configs[ $key ]['folder'];
     608                }
     609            }
     610            self::$ip_list = $font_configs;
     611            return $font_configs;
     612        }
     613    } // End class Borderless_IF
     614
     615    /**
     616     * Creates a folder for the plugin framework
     617     */
     618    if ( ! function_exists( 'borderless_backend_create_folder' ) ) {
     619        function borderless_backend_create_folder( &$folder, $addindex = true ) {
     620            if ( is_dir( $folder ) && $addindex == false ) {
     621                return true;
     622            }
     623            $created = wp_mkdir_p( trailingslashit( $folder ) );
     624            @chmod( $folder, 0777 );
     625            if ( $addindex == false ) {
     626                return $created;
     627            }
     628            $index_file = trailingslashit( $folder ) . 'index.php';
     629            if ( file_exists( $index_file ) ) {
     630                return $created;
     631            }
     632            $handle = @fopen( $index_file, 'w' );
     633            if ( $handle ) {
     634                fwrite( $handle, "<?php\r\necho 'We are sorry, but you are not allowed to browse this directory.';\r\n?>" );
     635                fclose( $handle );
     636            }
     637            return $created;
     638        }
     639    }
     640   
     641    // Instantiate the main Icon Fonts class
     642    new Borderless_IF;
     643}
     644
     645/**
     646 * Adds the Icon Pack Manager to the WP admin menu
     647 */
     648function borderless_custom_icons_menu() {
     649    $Borderless_IF = new Borderless_IF;
     650    $Borderless_IF->icon_pack_manager();
     651}
     652
     653/**
     654 * Enqueues the custom icon fonts on the frontend
     655 */
     656function borderless_custom_icons() {
     657    $upload_paths = wp_upload_dir();
     658    $custom_fonts = get_option( 'borderless_icon_fonts' );
     659    if ( is_array( $custom_fonts ) ) {
     660        foreach ( $custom_fonts as $font => $info ) {
     661            if ( strpos( $info['style'], 'http://' ) !== false ) {
     662                wp_enqueue_style( 'borderless-' . $font, $info['style'], null, '1.0', 'all' );
     663            } else {
     664                wp_enqueue_style( 'borderless-' . $font, trailingslashit( $upload_paths['baseurl'] . '/borderless_icon_fonts/' ) . $info['style'], null, '1.0', 'all' );
     665            }
     666        }
     667    }
     668}
     669add_action( 'wp_enqueue_scripts', 'borderless_custom_icons' );
  • borderless/trunk/readme.txt

    r3209805 r3230461  
    33Tags: Gutenberg, Elementor, elements, widgets, templates
    44Requires at least: 5.0
    5 Tested up to: 6.6.1
     5Tested up to: 6.7.1
    66Requires PHP: 7.4
    7 Stable tag: 1.5.9
     7Stable tag: 1.6.0
    88License: GPLv3
    99License URI: https://www.gnu.org/licenses/gpl-3.0.html
     
    8282== Changelog ==
    8383
    84 = 1.5.9 -Dec 18 2024 =
     84= 1.6.0 - Jan 28 2025 =
    8585* Fixed - General Vulnerabilities.
    8686
    87 = 1.5.8 -Dec 06 2024 =
     87= 1.5.9 - Dec 18 2024 =
     88* Fixed - General Vulnerabilities.
     89
     90= 1.5.8 - Dec 06 2024 =
    8891* Fixed - General Vulnerabilities.
    8992
Note: See TracChangeset for help on using the changeset viewer.