View file rusnet-interactive-map/classes/class-options.php

File size: 16.14Kb
<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class Rusnetim_Options {

    private static $option_name = 'rusnetim_options';
    private static $defaults = [];
    private static $defaults_backup = [];

    public static function init() {
        self::$defaults = [
            'center_map_option'          => '53.334554,83.786980',
            'zoom_map_option'            => '12',
            'type_map_option'            => 'yandex#map',
            'height_map_option'          => '22rem',
            'controls_map_option'        => '',
            'wheelzoom_map_option'       => 'off',
            'mobiledrag_map_option'      => 'off',
            'type_icon_option'           => 'islands#dotIcon',
            'color_icon_option'          => '#1e98ff',
            'apikey_map_option'          => '',
            'reset_maps_option'          => 'off',
            'cluster_map_option'         => 'off',
            'cluster_grid_option'        => '64',
            'cluster_color_option'       => '#1e98ff',
            'custom_icon_option'         => '',
            'custom_icon_width_option'   => '',
            'custom_icon_height_option'  => '',
            'info_panel_side'            => 'right',
            'info_panel_width'           => '300px',
            'info_panel_title_position'  => 'below',
            'info_title_tag'             => 'h3',
            'info_title_font_size'       => '',
            'info_title_color'           => '',
            'info_panel_bg_color'        => '#ffffff',
            'cat_filter_container_justify'    => 'flex-start',
            'cat_filter_button_tag'            => 'button',
            'cat_filter_button_font_size'      => '',
            'cat_filter_button_color'          => '',
            'cat_filter_button_bg_color'       => '',
            'cat_filter_button_border'         => '',
            'cat_filter_button_box_shadow'     => '',
            'cat_filter_button_padding'        => '6px 12px',
            'cat_filter_button_border_radius'  => '4px',
            'cat_filter_button_active_color'   => '',
            'cat_filter_button_active_bg_color'=> '',
            'cat_filter_button_active_border'  => '',
        ];
        self::$defaults = apply_filters( 'rusnetim_default_options', self::$defaults );
        self::$defaults_backup = self::$defaults;
    }

    public static function get_option_name() {
        return self::$option_name;
    }

    public static function get( $key, $default = null ) {
        $options = get_option( self::$option_name, [] );
        if ( isset( $options[ $key ] ) ) {
            return $options[ $key ];
        }
        return $default ?? ( self::$defaults[ $key ] ?? '' );
    }

    public static function get_all() {
        $saved = get_option( self::$option_name, [] );
        $all = array_merge( self::$defaults, $saved );
        if ( isset( $all['controls_map_option'] ) ) {
            $fixpos = strripos( $all['controls_map_option'], '111' );
            if ( is_int( $fixpos ) ) {
                $fixpattern = array('111;', '111');
                $all['controls_map_option'] = str_replace( $fixpattern, '', $all['controls_map_option'] );
                self::update_all( $all );
            }
        }
        return $all;
    }

    public static function update_all( $options ) {
        update_option( self::$option_name, $options );
    }

    public static function sanitize( $input ) {
        $old_options = get_option( self::$option_name, [] );
        $sanitized = $old_options;

        if ( isset( $input['center_map_option'] ) ) {
            $sanitized['center_map_option'] = self::sanitize_coords( $input['center_map_option'] );
        }

        if ( isset( $input['zoom_map_option'] ) ) {
            $sanitized['zoom_map_option'] = (string) self::sanitize_zoom( $input['zoom_map_option'] );
        }

        if ( isset( $input['type_map_option'] ) ) {
            $sanitized['type_map_option'] = self::sanitize_map_type( $input['type_map_option'] );
        }

        if ( isset( $input['height_map_option'] ) ) {
            $height = sanitize_text_field( $input['height_map_option'] );
            if ( preg_match( '/^\d+(\.\d+)?(rem|em|px|vh)$/', $height ) ) {
                $sanitized['height_map_option'] = $height;
            } else {
                $sanitized['height_map_option'] = '22rem';
                add_settings_error( 'rusnetim_options', 'invalid_height', __( 'Map height must be specified with units: rem, em, px or vh (e.g., 400px, 30rem, 50vh). Default 22rem used.', 'rusnet-interactive-map' ), 'warning' );
            }
        }

        if ( isset( $input['info_panel_side'] ) ) {
            $side = sanitize_text_field( $input['info_panel_side'] );
            $allowed_sides = apply_filters( 'rusnetim_allowed_info_panel_sides', [ 'right', 'left' ] );
            if ( in_array( $side, $allowed_sides, true ) ) {
                $sanitized['info_panel_side'] = $side;
            } else {
                $sanitized['info_panel_side'] = 'right';
            }
        }

        if ( isset( $input['info_panel_width'] ) ) {
            $width = sanitize_text_field( $input['info_panel_width'] );
            if ( preg_match( '/^\d+(\.\d+)?(px|%|em|rem|vw|vh)$/', $width ) ) {
                $sanitized['info_panel_width'] = $width;
            } else {
                $sanitized['info_panel_width'] = '300px';
                add_settings_error(
                    'rusnetim_options',
                    'invalid_info_width',
                    __( 'Info panel width must be specified with units: px, %, em, rem, vw, vh (e.g., 300px, 50%, 20rem). Default 300px used.', 'rusnet-interactive-map' ),
                    'warning'
                );
            }
        }

        if ( isset( $input['info_panel_title_position'] ) ) {
            $pos = sanitize_text_field( $input['info_panel_title_position'] );
            if ( in_array( $pos, [ 'above', 'below' ] ) ) {
                $sanitized['info_panel_title_position'] = $pos;
            } else {
                $sanitized['info_panel_title_position'] = 'below';
            }
        }

        if ( isset( $input['info_title_tag'] ) ) {
            $tag = sanitize_text_field( $input['info_title_tag'] );
            $allowed_tags = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'span', 'p' ];
            $sanitized['info_title_tag'] = in_array( $tag, $allowed_tags, true ) ? $tag : 'h3';
        }

        if ( isset( $input['info_title_font_size'] ) ) {
            $size = sanitize_text_field( $input['info_title_font_size'] );
            if ( preg_match( '/^\d+(\.\d+)?(px|rem|em|%|vh|vw|pt|pc)$/', $size ) ) {
                $sanitized['info_title_font_size'] = $size;
            } else {
                $sanitized['info_title_font_size'] = '';
            }
        }

        if ( isset( $input['info_title_color'] ) ) {
            $color = sanitize_hex_color( $input['info_title_color'] );
            $sanitized['info_title_color'] = $color ?: '';
        }

        if ( isset( $input['info_panel_bg_color'] ) ) {
            $color = sanitize_hex_color( $input['info_panel_bg_color'] );
            $sanitized['info_panel_bg_color'] = $color ?: '#ffffff';
        }

        if ( isset( $input['cat_filter_container_justify'] ) ) {
            $valid = [ 'flex-start', 'center', 'flex-end', 'space-between', 'space-around', 'space-evenly' ];
            $sanitized['cat_filter_container_justify'] = in_array( $input['cat_filter_container_justify'], $valid, true ) ? $input['cat_filter_container_justify'] : 'flex-start';
        }

        if ( isset( $input['cat_filter_button_tag'] ) ) {
            $valid = [ 'button', 'a', 'div', 'span' ];
            $sanitized['cat_filter_button_tag'] = in_array( $input['cat_filter_button_tag'], $valid, true ) ? $input['cat_filter_button_tag'] : 'button';
        }

        if ( isset( $input['cat_filter_button_font_size'] ) ) {
            $size = sanitize_text_field( $input['cat_filter_button_font_size'] );
            if ( preg_match( '/^\d+(\.\d+)?(px|rem|em|%|vh|vw|pt|pc)$/', $size ) ) {
                $sanitized['cat_filter_button_font_size'] = $size;
            } else {
                $sanitized['cat_filter_button_font_size'] = '';
            }
        }

        if ( isset( $input['cat_filter_button_color'] ) ) {
            $color = sanitize_hex_color( $input['cat_filter_button_color'] );
            $sanitized['cat_filter_button_color'] = $color ?: '';
        }

        if ( isset( $input['cat_filter_button_bg_color'] ) ) {
            $color = sanitize_hex_color( $input['cat_filter_button_bg_color'] );
            $sanitized['cat_filter_button_bg_color'] = $color ?: '';
        }

        if ( isset( $input['cat_filter_button_border'] ) ) {
            $border = sanitize_text_field( $input['cat_filter_button_border'] );
            $sanitized['cat_filter_button_border'] = $border;
        }

        if ( isset( $input['cat_filter_button_box_shadow'] ) ) {
            $shadow = sanitize_text_field( $input['cat_filter_button_box_shadow'] );
            $sanitized['cat_filter_button_box_shadow'] = $shadow;
        }

        if ( isset( $input['cat_filter_button_padding'] ) ) {
            $padding = sanitize_text_field( $input['cat_filter_button_padding'] );
            if ( preg_match( '/^(\d+(\.\d+)?(px|em|rem|%)?\s*){1,4}$/', $padding ) ) {
                $sanitized['cat_filter_button_padding'] = $padding;
            } else {
                $sanitized['cat_filter_button_padding'] = '6px 12px';
            }
        }

        if ( isset( $input['cat_filter_button_border_radius'] ) ) {
            $radius = sanitize_text_field( $input['cat_filter_button_border_radius'] );
            if ( preg_match( '/^\d+(\.\d+)?(px|%|em|rem)?$/', $radius ) ) {
                $sanitized['cat_filter_button_border_radius'] = $radius;
            } else {
                $sanitized['cat_filter_button_border_radius'] = '4px';
            }
        }

        if ( isset( $input['cat_filter_button_active_color'] ) ) {
            $color = sanitize_hex_color( $input['cat_filter_button_active_color'] );
            $sanitized['cat_filter_button_active_color'] = $color ?: '';
        }

        if ( isset( $input['cat_filter_button_active_bg_color'] ) ) {
            $color = sanitize_hex_color( $input['cat_filter_button_active_bg_color'] );
            $sanitized['cat_filter_button_active_bg_color'] = $color ?: '';
        }

        if ( isset( $input['cat_filter_button_active_border'] ) ) {
            $border = sanitize_text_field( $input['cat_filter_button_active_border'] );
            $sanitized['cat_filter_button_active_border'] = $border;
        }

        if ( isset( $input['controls_map_option'] ) ) {
            $allowed_controls = array(
                'fullscreenControl', 'geolocationControl', 'routeEditor', 'rulerControl',
                'searchControl', 'trafficControl', 'typeSelector', 'zoomControl',
                'routeButtonControl', 'routePanelControl', 'smallMapDefaultSet',
                'mediumMapDefaultSet', 'largeMapDefaultSet', 'default',
            );
            $controls_array = array_map( 'trim', explode( ';', $input['controls_map_option'] ) );
            $valid_controls = array();
            foreach ( $controls_array as $control ) {
                $control = sanitize_text_field( $control );
                if ( in_array( $control, $allowed_controls, true ) ) {
                    $valid_controls[] = $control;
                }
            }
            $sanitized['controls_map_option'] = implode( ';', $valid_controls );
        }

        $checkbox_fields = [
            'wheelzoom_map_option',
            'mobiledrag_map_option',
            'cluster_map_option',
            'reset_maps_option',
        ];
        foreach ( $checkbox_fields as $field ) {
            if ( isset( $input[ $field ] ) ) {
                $sanitized[ $field ] = ( $input[ $field ] === 'on' ) ? 'on' : 'off';
            }
        }

        if ( isset( $input['cluster_grid_option'] ) ) {
            $grid = intval( $input['cluster_grid_option'] );
            $sanitized['cluster_grid_option'] = ( $grid >= 2 && $grid <= 512 ) ? (string) $grid : '64';
        }

        if ( isset( $input['cluster_color_option'] ) ) {
            $color = sanitize_hex_color( $input['cluster_color_option'] );
            $sanitized['cluster_color_option'] = $color ? $color : '#1e98ff';
        }

        if ( isset( $input['type_icon_option'] ) ) {
            $icon = sanitize_text_field( $input['type_icon_option'] );
            if ( preg_match( '/^[a-zA-Z0-9#_\-]+$/', $icon ) || filter_var( $icon, FILTER_VALIDATE_URL ) ) {
                $sanitized['type_icon_option'] = $icon;
            } else {
                $sanitized['type_icon_option'] = 'islands#dotIcon';
            }
        }

        if ( isset( $input['color_icon_option'] ) ) {
            $color = sanitize_hex_color( $input['color_icon_option'] );
            $sanitized['color_icon_option'] = $color ? $color : '#1e98ff';
        }

        if ( isset( $input['custom_icon_option'] ) ) {
            $custom = sanitize_text_field( $input['custom_icon_option'] );
            if ( is_numeric( $custom ) || filter_var( $custom, FILTER_VALIDATE_URL ) ) {
                $sanitized['custom_icon_option'] = $custom;
            } else {
                $sanitized['custom_icon_option'] = '';
            }
        }

        if ( isset( $input['custom_icon_width_option'] ) ) {
            $w = intval( $input['custom_icon_width_option'] );
            $sanitized['custom_icon_width_option'] = $w > 0 ? $w : '';
        }

        if ( isset( $input['custom_icon_height_option'] ) ) {
            $h = intval( $input['custom_icon_height_option'] );
            $sanitized['custom_icon_height_option'] = $h > 0 ? $h : '';
        }

        if ( isset( $input['apikey_map_option'] ) ) {
            $apikey = sanitize_text_field( $input['apikey_map_option'] );
            if ( preg_match( '/^[a-zA-Z0-9\-_]*$/', $apikey ) ) {
                $sanitized['apikey_map_option'] = $apikey;
            } else {
                $sanitized['apikey_map_option'] = '';
            }
        }

        $sanitized = apply_filters( 'rusnetim_sanitize_options', $sanitized, $input );

        return $sanitized;
    }

    public static function sanitize_coords( $coord ) {
        $sanitized = preg_replace( '/[^0-9.,\s\-]/', '', $coord );
        if ( preg_match( '/^-?\d+\.?\d*\s*,\s*-?\d+\.?\d*$/', trim( $sanitized ) ) ) {
            return trim( $sanitized );
        }
        return '55.7558, 37.6173';
    }

    public static function sanitize_zoom( $zoom ) {
        $zoom_int = intval( $zoom );
        if ( $zoom_int < 0 ) return 0;
        if ( $zoom_int > 21 ) return 21;
        return $zoom_int;
    }

    public static function sanitize_map_type( $type ) {
        $type_map = array(
            'map'              => 'yandex#map',
            'satellite'        => 'yandex#satellite',
            'hybrid'           => 'yandex#hybrid',
            'yandex#map'       => 'yandex#map',
            'yandex#satellite' => 'yandex#satellite',
            'yandex#hybrid'    => 'yandex#hybrid',
        );
        $type = sanitize_text_field( $type );
        return $type_map[ $type ] ?? 'yandex#map';
    }

    public static function sanitize_controls( $controls ) {
        $allowed_controls = array(
            'fullscreenControl', 'geolocationControl', 'routeEditor', 'rulerControl',
            'searchControl', 'trafficControl', 'typeSelector', 'zoomControl',
            'routeButtonControl', 'routePanelControl', 'smallMapDefaultSet',
            'mediumMapDefaultSet', 'largeMapDefaultSet', 'default',
        );

        $controls_array = array_map( 'trim', explode( ';', $controls ) );
        $sanitized      = array();

        foreach ( $controls_array as $control ) {
            $control = sanitize_text_field( $control );
            if ( in_array( $control, $allowed_controls, true ) ) {
                $sanitized[] = $control;
            }
        }

        return $sanitized;
    }

    public static function sanitize_apikey( $key ) {
        $key = sanitize_text_field( $key );
        return preg_match( '/^[a-zA-Z0-9\-_]*$/', $key ) ? $key : '';
    }

    public static function sanitize_locale( $locale ) {
        return preg_match( '/^[a-z]{2}_[A-Z]{2}$/', $locale ) ? $locale : 'en_US';
    }
}