<?php
/*
Plugin Name: InflatableOffice WP Integration
Plugin URI: https://rental.software
Description: Integrates your InflatableOffice inventory into your wordpress site to generate and keep updated products and categories.
Author: InflatableOffice
Author URI: https://rental.software
Version: 6.20.0
*/
$plugin_current_version = '6.20.0';//also set it above in the comments

//raise the limit on the number of items per page
ini_set('pcre.backtrack_limit', '20000000');  // 20M. tested with 360 items per page
//ini_set('pcre.recursion_limit', '1000000');   // 1M

require_once('shortcoder.php');
require_once('wp-oauth.php');
//require_once('wp-rest-api.php');
require_once ('wp_autoupdate.php');
require_once ('widget-featured.php');
require_once ('widget-filter.php');
require_once ('widget-TentCalc.php');
//require_once ('widget-datepicker.php');
require_once ('search_widget/includes/class-widget.php');
require_once ('search_widget/searchio-live-ajax-search.php');

$plugin_remote_path = 'https://rental.software/wp-plugin/update.php';
$plugin_slug = 'inflatableoffice/inflatableoffice.php';
//$license_user = 'user';
//$license_key = 'abcd';
new IOWP_AutoUpdate ( $plugin_current_version, $plugin_remote_path, $plugin_slug);//, $license_user, $license_key );

function inoff_setup($network_wide){
    if(is_user_logged_in()) {
        _wo_server_activation($network_wide);
        $wo = new WO_Server();
        $wo->setup();
        $wo->upgrade();
        //json_api_activation(false);
        sc_setup();

        //flush_rewrite_rules();//force permalink refresh which is needed due to api update

        if (!get_option('io_checkavail')) update_option("io_checkavail", 'warn');//default

        //create pages for quote integration
        create_io_pages();//running it every page load now as well as on plugin activation (bc if they switch themes we have to re-activate to create the pages)
    }
}

register_activation_hook( __FILE__, 'inoff_setup' );

function io_check_plugin_version() {
    if( !function_exists('get_plugin_data') ){
        require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
    }
    $current_version = get_plugin_data( (__FILE__), false, false )['Version'];
    $old_version = get_option( 'io_plugin_version' );
    if(empty($old_version)) $old_version= 0;
    if (version_compare($current_version,$old_version,'>')) {
        //this code only runs 1x after plug-in is upgraded
        //sc_setup();//below so it runs all the time...
        // flush_rewrite_rules();
        add_action("shutdown", "flush_rewrite_rules");

        //check shortcodes to make sure all are set to auto-upgade for this version
        if (version_compare($old_version,'4.0.0','<')) {
            $autoupdate=1;
            $shortcoder_data = get_option('shortcoder_data');
            if (!empty($shortcoder_data)) {
                foreach ($shortcoder_data as $k => $v) {
                    if (empty($shortcoder_data[$k]['autoupdate']) && $k<>'io_category' && $k<>'io_categroy') {
                        $autoupdate=0;
                    }
                }
                if($autoupdate==0) {
                    foreach ($shortcoder_data as $k => $v) {
                        $shortcoder_data[$k]['autoupdate'] = 0;
                    }
                    update_option('shortcoder_data', $shortcoder_data);
                }
            }
        }
        // remove this page, as changes may have been made to it.
        if(file_exists(get_template_directory().'/page-io_reviews.php')){
            unlink(get_template_directory().'/page-io_reviews.php');
        }

        // update not to run twice
        update_option('io_plugin_version', $current_version);
    }
}
io_check_plugin_version();

function unhash_login() {
    // Only continue if 'io_auth' parameter is set
    if (!isset($_REQUEST['io_auth'])) {
        return; // Exit early if the 'io_auth' parameter isn't set, no redirection happens
    }

    // Process login only if user is not already logged in
    if (!is_user_logged_in()) {
        $key = 'cGSmuRB/EB6P5ylv"mk!';
        $encrypted = urldecode($_REQUEST['io_auth']);
        $decrypted = base64_decode($encrypted);
        $plaintext = str_replace($key, '', $decrypted);
        $credentials = explode('&', $plaintext, 2);

        if (empty($credentials[0]) || empty($credentials[1])) {
            wp_mail("dan@inflatableoffice.com", "Unhash Login Error", "Decryption failed or incomplete credentials");
            return; // Stop further processing if decryption fails
        }

        auto_login_temp($credentials[0], $credentials[1]);
    }

    // Redirect to the admin dashboard after successful login
    if (is_user_logged_in() && !is_admin()) {
        wp_redirect(admin_url());
        exit();
    }
}
add_action('init', 'unhash_login');

function auto_login_temp($u, $p) {
    if (!is_user_logged_in()) {
        $user = get_user_by('login', $u);
        if (!$user) {
            wp_mail("dan@inflatableoffice.com", "Auto Login Temp Error", "User not found with username - {$u}");
            return;
        }

        if (!wp_check_password($p, $user->data->user_pass, $user->ID)) {
            wp_mail("dan@inflatableoffice.com", "Auto Login Temp Error", "Password check failed for user - {$u}");
            return; // Incorrect password
        }

        $loginusername = $user->user_login;
        wp_set_current_user($user->ID, $loginusername);
        wp_set_auth_cookie($user->ID, true);
        do_action('wp_login', $loginusername, $user);

        // Redirect after login
        if (isset($_REQUEST['redirect_to'])) {
            $redirect_page = $_REQUEST['redirect_to'];
        } else {
            $redirect_page = admin_url();
        }

        wp_redirect($redirect_page);
        exit();
    }
}

function extend_login_sessions($expire) {
    // Set the expiration to 30 days (30 days * 24 hours * 60 minutes * 60 seconds)
    return 90 * 24 * 3600;
}
add_filter('auth_cookie_expiration', 'extend_login_sessions');

// Fixes shortcode update issue
sc_setup();

/**
 * Retrieves the client's IP address from server headers, prioritizing headers
 * that may indicate the actual client IP in cases where a proxy or CDN is involved.
 * Falls back to a default IP of '127.0.0.1' if no valid IP is found.
 * @return string The client's IP address.
 */
function io_get_client_ip()
{
    $headers =
            [
        'HTTP_X_SUCURI_CLIENTIP',
        'HTTP_X_FORWARDED_FOR',
                    'HTTP_CLIENT_IP',
                    'REMOTE_ADDR',
            ];

    $flags = FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;

    foreach ($headers as $h)
    {
        if (empty($_SERVER[$h])) continue;

            $ip = $_SERVER[$h];

    // If header has a chain of IPs, take the left-most
        if (strpos($ip, ',') !== false) $ip = trim(explode(',', $ip, 2)[0]);
        else $ip = trim($ip);

        if (filter_var($ip, FILTER_VALIDATE_IP, ['flags' => $flags]) !== false) {
            return $ip; // raw IPv4/IPv6, public only
        }
    }
    return $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
}

// Fixes multisite activation issue. #14422
add_action('init', 'inoff_setup');

//can probably remove this eventually
//add_action( 'shutdown', 'flush_rewrite_rules');//force permalink refresh which is needed due to api update

function widget_featured() {
    register_widget( 'IO_Featured' );

}
add_action( 'widgets_init', 'widget_featured');

function widget_filter() {
    register_widget( 'Widget_Filter' );

}
add_action( 'widgets_init', 'widget_filter' );

function widget_TentCalculator() {
    register_widget( 'Widget_TentCalculator' );

}
add_action( 'widgets_init', 'widget_TentCalculator');

function searchio_live_search() {
    register_widget( 'IO_Search' );

}
add_action( 'widgets_init', 'searchio_live_search' );

/*
function widget_datepicker() {
    register_widget( 'Widget_DatePicker' );

}
add_action( 'widgets_init', 'widget_datepicker' );
*/
//removes wrong p tags that are added to descr, but didn't solve
/*add_filter('the_content', 'test_cont','10.1');
function test_cont($content) {
    $content = str_replace(' description="</p>',' description="',$content);
    $content = str_replace('<p>" notes=','" notes=',$content);
    return $content;
};*/

//links are verified externally. removing them will only delist your links
function get_io_links(){
    $links = get_option( 'io_links' );
    $links_obj = json_decode($links);
    echo get_header();
    echo "<br><br><br>";
    echo '<h2>Other great rental companies</h2>';
    if(is_iterable($links_obj)) {
        foreach ($links_obj as $item) {
            echo $item . "<br><br>";
        }
    }
    echo get_footer();
}

#region IO-27771: Improved Reviews II ----------------------------------------------------------

// Create or replace pages with the widget
function create_io_pages() {
    #region other pages
    if(!file_exists(get_template_directory().'/page-io_quoteform.php')) file_put_contents ( get_template_directory().'/page-io_quoteform.php' , '<?php $page_type = \'quoteme\'; require_once(get_template_directory() . \'/../../plugins/inflatableoffice/io-getpagecontent.php\'); ?>');
    /*file_put_contents ( get_template_directory().'/page-io_quoteform.php' , '<?php $page_type = \'quoteme\'; require_once(\'/var/www/wp/wp-content/plugins/inflatableoffice/io-getpagecontent.php\'); ?>');*/
    /* jpa - dev  note: switch line above. don't use //.  change $base_qt_url in io-getpagecontent */
    $page = get_page_by_path( 'io_quoteform' , OBJECT );
    if(empty($page)) $id = wp_insert_post(array('post_title'=>'Quote Form','post_name'=>'io_quoteform', 'post_type'=>'page', 'post_status'=>'publish','post_content'=>'Do not delete. This page\'s content is generated.'));

    if(!file_exists(get_template_directory().'/page-io_quoteconfirm.php')) file_put_contents ( get_template_directory().'/page-io_quoteconfirm.php' , '<?php $page_type = \'quote_confirm\'; require_once(get_template_directory() . \'/../../plugins/inflatableoffice/io-getpagecontent.php\'); ?>');
    $page = get_page_by_path( 'io_quoteconfirm' , OBJECT );
    if(empty($page)) $id = wp_insert_post(array('post_title'=>'Quote Details','post_name'=>'io_quoteconfirm', 'post_type'=>'page', 'post_status'=>'publish','post_content'=>'Do not delete. This page\'s content is generated.'));

    if(!file_exists(get_template_directory().'/page-io_contract.php')) file_put_contents ( get_template_directory().'/page-io_contract.php' , '<?php $page_type = \'contractme\'; require_once(get_template_directory() . \'/../../plugins/inflatableoffice/io-getpagecontent.php\'); ?>');
    $page = get_page_by_path( 'io_contract' , OBJECT );
    if(empty($page)) $id = wp_insert_post(array('post_title'=>'Event Contract','post_name'=>'io_contract', 'post_type'=>'page', 'post_status'=>'publish','post_content'=>'Do not delete. This page\'s content is generated.'));

    if(!file_exists(get_template_directory().'/page-io_contactform.php')) file_put_contents ( get_template_directory().'/page-io_contactform.php' , '<?php $page_type = \'contactme\'; require_once(get_template_directory() . \'/../../plugins/inflatableoffice/io-getpagecontent.php\'); ?>');
    $page = get_page_by_path( 'io_contactform' , OBJECT );
    if(empty($page)) $id = wp_insert_post(array('post_title'=>'Contact Us','post_name'=>'io_contactform', 'post_type'=>'page', 'post_status'=>'publish','post_content'=>'Do not delete. This page\'s content is generated.'));

    if(!file_exists(get_template_directory().'/page-io_receipt.php')) file_put_contents ( get_template_directory().'/page-io_receipt.php' , '<?php $page_type = \'receipt\'; require_once(get_template_directory() . \'/../../plugins/inflatableoffice/io-getpagecontent.php\'); ?>');
    $page = get_page_by_path( 'io_receipt' , OBJECT );
    if(empty($page)) $id = wp_insert_post(array('post_title'=>'Payment Receipt','post_name'=>'io_receipt', 'post_type'=>'page', 'post_status'=>'publish','post_content'=>'Do not delete. This page\'s content is generated.'));

    if(!file_exists(get_template_directory().'/page-io_vendor.php')) file_put_contents ( get_template_directory().'/page-io_vendor.php' , '<?php $page_type = \'vendorme\'; require_once(get_template_directory() . \'/../../plugins/inflatableoffice/io-getpagecontent.php\'); ?>');
    $page = get_page_by_path( 'io_vendor' , OBJECT );
    if(empty($page)) $id = wp_insert_post(array('post_title'=>'Vendor Contract','post_name'=>'io_vendor', 'post_type'=>'page', 'post_status'=>'publish','post_content'=>'Do not delete. This page\'s content is generated.'));

    if(!file_exists(get_template_directory().'/page-io_quotedone.php')) file_put_contents ( get_template_directory().'/page-io_quotedone.php' , '<?php $page_type = \'quote_done\'; require_once(get_template_directory() . \'/../../plugins/inflatableoffice/io-getpagecontent.php\'); ?>');
    $page = get_page_by_path( 'io_quotedone' , OBJECT );
    if(empty($page)) $id = wp_insert_post(array('post_title'=>'Quote Done','post_name'=>'io_quotedone', 'post_type'=>'page', 'post_status'=>'publish','post_content'=>'Do not delete. This page\'s content is generated.'));
    #endregion
}

if (strpos($_SERVER['REQUEST_URI'],'io_') !== false) {
    create_io_pages();
}

function does_io_reviews_widget_exist($post_id) {
    if (is_plugin_active('elementor/elementor.php')) {
        // Ensure that the Elementor instance exists before proceeding
        if (class_exists('\Elementor\Plugin') && \Elementor\Plugin::$instance->documents->get($post_id)->is_built_with_elementor()) {

            // Get the Elementor data
            $elementor_data = get_post_meta($post_id, '_elementor_data', true);

            if ($elementor_data) {
                // Decode the JSON data
                $elementor_content = json_decode($elementor_data, true);

                // Search for the IO_Reviews_Widget in the content
                return search_for_widget($elementor_content, 'io_reviews_widget');
            }
        }
    }

    return false;
}

function search_for_widget($elements, $widget_name) {
    foreach ($elements as $element) {
        // Check if the element is a widget and matches the widget name
        if (isset($element['widgetType']) && $element['widgetType'] === $widget_name) {
            return true;
        }

        // Recursively check inner elements if they exist
        if (isset($element['elements']) && is_array($element['elements'])) {
            if (search_for_widget($element['elements'], $widget_name)) {
                return true;
            }
        }
    }

    return false;
}


function create_or_update_reviews_page()
{

    if ( is_plugin_active( 'elementor/elementor.php' ) )
    {

        $review_page = get_page_by_path('reviews', OBJECT);
        $post_id = $review_page->ID;

        //basically a short circuit where if the page exists and has the widgety we don't care about the rest of the code
        if ($review_page && does_io_reviews_widget_exist($post_id))
            return;

        // If /reviews/ exists without the widget, delete it to allow re-creation
        if ($review_page && !does_io_reviews_widget_exist($post_id)) {
            wp_delete_post($post_id, true);
        }

        // Create the new Reviews page (this should only ever run if the page doesn't exist with the widget on it)
        $page_id = wp_insert_post
        (
                array
                (
                        'post_title' => 'Reviews',
                        'post_name' => 'reviews',
                        'post_type' => 'page',
                        'post_status' => 'publish',
                )
        );

        if (!$page_id)
            error_log('Failed to create the Reviews page.');
        else
            error_log('Reviews page created with ID: ' . $page_id);

        // Set the page to use Elementor
        if (defined('ELEMENTOR_VERSION'))
        {
            update_post_meta($page_id, '_elementor_edit_mode', 'builder');
            update_post_meta($page_id, '_elementor_version', ELEMENTOR_VERSION);
        }

        // Generate unique IDs for section, column, and widget
        $unique_section_id = uniqid('section_');
        $unique_column_id = uniqid('column_');
        $unique_widget_id = uniqid('widget_');

        // Add Elementor widget data using actual widget settings
        $elementor_data =
                [
                        [
                                'id' => $unique_section_id,
                                'elType' => 'section',
                                'elements' =>
                                        [
                                                [
                                                        'id' => $unique_column_id,
                                                        'elType' => 'column',
                                                        'elements' =>
                                                                [
                                                                        [
                                                                                'id' => $unique_widget_id,
                                                                                'elType' => 'widget',
                                                                                'widgetType' => 'io_reviews_widget',
                                                                                'settings' =>
                                                                                        [
                                                                                                'slides_to_show' => 3,
                                                                                                'autoplay' => 'yes',
                                                                                                'autoplay_speed' => 2,
                                                                                                'infinite' => 'yes',
                                                                                                'slides_to_scroll' => 1,
                                                                                                'show_all_reviews' => 'yes',
                                                                                                'number_of_reviews' => 5,
                                                                                                'show_average_rating' => 'yes',
                                                                                                'show_stars' => 'yes',
                                                                                                'show_review_date' => 'yes',
                                                                                                'show_reviewer_name' => 'yes',
                                                                                                'show_reviewer_photo' => 'yes',
                                                                                                'review_order' => 'random',
                                                                                        ],
                                                                        ]
                                                                ]
                                                ]
                                        ]
                        ]
                ];

        update_post_meta($page_id, '_elementor_data', json_encode($elementor_data));
        if (function_exists('force_elementor_rebuild'))
        {
            force_elementor_rebuild($page_id);
        }
    }
}
add_action('wp_loaded', 'create_or_update_reviews_page');

#endregion -----------------------------------------------------------------------------------

// #5474 - add adwords tracking
// #6028 - add facebook tracking
function io_analytics_tracking() {
    // IO-28339
    $io_url_params = get_option('io_url_params');
    if($io_url_params) {
        $io_url_params = json_decode($io_url_params);
        foreach ($io_url_params as $io_url_param) {
            if (array_key_exists($io_url_param->urlparam_paramname, $_REQUEST)) {
                $param_value = stripslashes($_REQUEST[$io_url_param->urlparam_paramname]);
                // Protect against XSS by only allowing alphanumeric characters and basic punctuation
                if (preg_match('/^[a-zA-Z0-9\s\-_.,;:!?\'"\(\)]+$/', $param_value)) {
                    //setcookie($io_url_param->urlparam_cookiename, $param_value, time() + $io_url_param->urlparam_expiresin, '/');
                    setcookie(
                            $io_url_param->urlparam_cookiename,
                            $param_value,
                            [
                                    'expires'  => time() + $io_url_param->urlparam_expiresin,
                                    'path'     => '/',
                                    'domain'   => '',         // leave empty to use current host; set explicitly if needed
                                    'secure'   => true,       // only send over HTTPS
                                    'httponly' => true,       // inaccessible to JS
                                    'samesite' => 'Lax'       // or 'Strict' or 'None' (None requires Secure)
                            ]
                    );
                }
            }
        }
    }
}
add_action( 'init', 'io_analytics_tracking' );

add_action( 'wp_footer', 'io_addtracking_allpages' );
function io_addtracking_allpages() {
    // IO-28339 add additional
    if(strpos(get_site_url(), 'localhost') !== false){
        $url = "http://localhost/io/bugs/include/iotracking.php";
    }else{
        $url = "https://rental.software/include/iotracking.php";
    }
    $io_url_params = get_option('io_url_params');
    if($io_url_params) {
        $io_url_params = json_decode($io_url_params);
        $is_first = true;
        foreach ($io_url_params as $key => $io_url_param) {
            if (array_key_exists($io_url_param->urlparam_cookiename, $_COOKIE) && isset($_COOKIE[$io_url_param->urlparam_cookiename])) {
                $cookie_value = stripslashes($_COOKIE[$io_url_param->urlparam_cookiename]);
                // Protect against XSS by only allowing alphanumeric characters and basic punctuation
                if (preg_match('/^[a-zA-Z0-9\s\-_.,;:!?\'"\(\)]+$/', $cookie_value)) {
                    if ($is_first) {
                        $url .= "?" . $io_url_param->urlparam_paramname . "=" . $cookie_value;
                        $is_first = false;
                    } else {
                        $url .= "&" . $io_url_param->urlparam_paramname . "=" . $cookie_value;
                    }
                }
            }
        }
    }
    $html = '<img src="'.$url.'" style="display:none;" importance="low" alt="dynamic io trk code" />';
    echo $html;
}
if(get_option('io_username')<>'inflatableoffice'){
    add_action( 'wp_footer', 'io_add_code_allpages' );
}
function set_custom_referrer_policy() {
    header('Referrer-Policy: no-referrer-when-downgrade');
}
add_action('send_headers', 'set_custom_referrer_policy');

//for pci compliance - force cache-control output if non specified
add_action('send_headers', function () {
    // Only care about POST responses
    if (empty($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'POST') {
        return;
    }

    $headers = headers_list();

    $has_cache_control = false;
    $has_pragma        = false;
    $has_expires       = false;

    foreach ($headers as $header) {
        $header_lower = strtolower($header);
        if (strpos($header_lower, 'cache-control:') === 0) {
            $has_cache_control = true;
        } elseif (strpos($header_lower, 'pragma:') === 0) {
            $has_pragma = true;
        } elseif (strpos($header_lower, 'expires:') === 0) {
            $has_expires = true;
        }
    }

    // Only set these if nothing else has already set them
    if (! $has_cache_control) {
        header('Cache-Control: no-cache', false);
    }
    if (! $has_expires) {
        header('Expires: 0', false);
    }
}, 999); // run late so other plugins have already added their headers

function io_add_code_allpages(){

    $showCategoryLong = get_option('io_showCategoryLong');
    $showCategoryLong_css = '';
    if($showCategoryLong && $showCategoryLong =='off'){
        $showCategoryLong_css = '.io_cat_longdescription{display:none !important;}';
    }

    // Base CSS: Always hide list view on inventory/all-items pages (no category ID)
    $hide_listview_css = "
    /* ALWAYS hide toggle buttons and list view on inventory/all-items pages (no category ID) */
    body.io-no-category-id .io_view_toggle_container,
    body.io-no-category-id .io_list_view_content
    {
        display: none !important;
    }
    
    /* Force grid/tile layout on pages without category IDs */
    body.io-no-category-id .io_catdiv2.list-view {
        display: grid !important;
        grid-template-columns: repeat(auto-fit, minmax(250px, 350px)) !important;
        grid-gap: 10px !important;
        margin: 50px !important;
        max-width: none !important;
        justify-content: space-evenly !important;
    }
    body.io-no-category-id .io_catdiv2.list-view .io_item2_list {
        display: block !important;
        flex-direction: column !important;
        margin-bottom: 0 !important;
        padding: 0 !important;
        align-items: initial !important;
        text-align: center !important;
    }
    body.io-no-category-id .io_catdiv2.list-view .cat_div {
        flex: initial !important;
        margin-right: 0 !important;
        position: relative !important;
    }
    body.io-no-category-id .io_catdiv2.list-view .cat_img {
        width: 100% !important;
        height: auto !important;
        object-fit: cover !important;
    }
    body.io-no-category-id .io_catdiv2.list-view .io_item2_list_inner {
        flex: initial !important;
        margin-top: initial !important;
        display: block !important;
        flex-direction: initial !important;
        justify-content: initial !important;
        min-height: auto !important;
        height: auto !important;
    }
    ";

    // Admin option: Hide list view on actual category pages (has category ID) when enabled
    $io_disable_listview = get_option('io_disable_listview');
    if($io_disable_listview=='on'){
        $hide_listview_css .= "
        /* Admin option enabled: Hide toggle buttons and list view on all pages */
        .io_view_toggle_container,
        .io_list_view_content
        {
            display: none !important;
        }
        
        /* Force grid/tile layout when admin option is enabled */
        .io_catdiv2.list-view {
            display: grid !important;
            grid-template-columns: repeat(auto-fit, minmax(250px, 350px)) !important;
            grid-gap: 10px !important;
            margin: 50px !important;
            max-width: none !important;
            justify-content: space-evenly !important;
        }
        .io_catdiv2.list-view .io_item2_list {
            display: block !important;
            flex-direction: column !important;
            margin-bottom: 0 !important;
            padding: 0 !important;
            align-items: initial !important;
            text-align: center !important;
        }
        .io_catdiv2.list-view .cat_div {
            flex: initial !important;
            margin-right: 0 !important;
            position: relative !important;
        }
        .io_catdiv2.list-view .cat_img {
            width: 100% !important;
            height: auto !important;
            object-fit: cover !important;
        }
        .io_catdiv2.list-view .io_item2_list_inner {
            flex: initial !important;
            margin-top: initial !important;
            display: block !important;
            flex-direction: initial !important;
            justify-content: initial !important;
            min-height: auto !important;
            height: auto !important;
        }
        ";
    }

    $io_hidetimes = get_option('io_hidetimes');
    $hidetimes_css = '';
    if($io_hidetimes=='on'){
        $hidetimes_css = "#cartTimePicker .timepicker,#cartTimePicker .fa-clock{display: none !important;}
        .ioCartCompanyTimeslots{display: none !important;}
        .calTimeLabel{display: none !important;}       
        #cartDateRange{margin-bottom: 10px;margin-left: 40px;font-size: x-large;}";
    }
    $io_checkavail = get_option('io_checkavail');
    $hide_checkavail_css = '';
    if($io_checkavail=='off'){
        $hide_checkavail_css = ".item-availability{display: none !important;}";
    }

    //hide price setting
    $hide_price_css = '';
    $io_hide_prices = get_option('io_hide_prices');
    if($io_hide_prices==1){
        $hide_price_css = "
        .rentNameIO_price, .io_product_price_box, .item-total, .cartSubtotalBox
        {
            display: none !important;
        }
        ";
    }

    //hide cat price setting
    $hide_price_catpages_css = '';
    $io_hide_prices_catpages = get_option('io_hide_prices_catpages');
    if($io_hide_prices_catpages==1){
        $hide_price_catpages_css = "
        .rentNameIO_price
        {
            display: none !important;
        }
        ";
    }

    //hide price setting
    $hide_live_price_css = '';
    $io_hide_live_prices = get_option('io_hide_live_prices');
    if($io_hide_live_prices==1 && get_option('io_always_display_live_price') != "on"){
        $hide_live_price_css = "
        .io_product_cust_price
        {
            display: none !important;
        }
        #item_live_price_time_set_message
        {
            display: none !important;
        }
        ";
    }

    //product page price settings
    //todo  master theme has settings on
    //todo mega menu choices (theme menu section)
    $price_override_css = '';
    $prices_css_hide_defaults = '';
    $prices_override_hide_css = '';
    $prices_default_product_page_css = '';
    $prices = get_option('io_prices');
    if(!empty($prices)) {
        //hide the defaults
        $prices_css_hide_defaults = '.io_product_price_4h,.io_product_price_8h,.io_product_price_24h,.io_product_price_additionalday{display:none}';
        //show these
        foreach ($prices as $v) {
            if(is_array($v)) continue;
            $split = explode('_', $v);
            if(isset($split[1])) {
                if (sizeof($split) == 4 && $split[1] == 'product' && $split[2] == 'price') {
                    $prices_default_product_page_css .= '.' . $v . ',';
                } else if(sizeof($split) == 5 && $split[1] == 'product' && $split[2] == 'price'){
                    $price_override_css .= '.' . $v . ',';
                }else if(sizeof($split) == 6 && $split[1] == 'product' && $split[2] == 'price'){
                    // IO-21808
                    $price_override_css .= '.' . $v . ',';
                }
            }
        }
        $prices_default_product_page_css = rtrim($prices_default_product_page_css, ',');
        $price_override_css = rtrim($price_override_css, ',');
        if (!empty($prices_default_product_page_css)) {
            $prices_default_product_page_css .= '{display: grid !important}';
        }
        if (!empty($price_override_css)) {
            $price_override_css .= '{display: grid !important}';
        }
        //for override prices, we must hide default pricing
        $prices_override_hide_css = '';
        foreach ($prices as $v) {
            if(is_array($v)) continue;
            $split = explode('_', $v);
            //for each default price
            if(!is_array($split)) continue;
            if (sizeof($split) == 4 && ($split[1] == 'product' || $split[1] == 'custom' || $split[1] == 'delivery')) {
                //for each override
                foreach ($prices as $ov) {
                    if(is_array($ov)) continue;
                    $osplit = explode('_', $ov);
                    if(!is_array($osplit)) continue;
                    if (sizeof($osplit) >= 5 && ($split[1] == 'product' || $split[1] == 'custom' || $split[1] == 'delivery')) {
                        if(sizeof($osplit) == 5){
                            if (!in_array('io_product_price_' . $split[3] . '_' . $osplit[4], $prices)) {
                                $prices_override_hide_css .= '.io_product_price_' . $split[3] . '_' . $osplit[4].',';//disable it
                            }
                        }else if(sizeof($osplit) == 6){
                            if (!in_array('io_product_price_' . $split[3] . '_' . $osplit[4] . '_' . $osplit[5], $prices)) {
                                $prices_override_hide_css .= '.io_product_price_' . $split[3] . '_' . $osplit[4] . '_' . $osplit[5].',';//disable it
                            }
                        }

                        //if 0h, hide on cat too
                        if($osplit[3]=="0h"){
                            $prices_override_hide_css .= '.rentNameIO_price_'.$osplit[4].',';
                        }
                    }
                }
            }
        }
        $prices_override_hide_css = rtrim($prices_override_hide_css, ',');
        if(!empty($prices_override_hide_css)){
            $prices_override_hide_css.='{display: none !important}';
        }
    }

    $LOCAL_PATH = get_bloginfo('url');
    $LOCAL_PATH = parse_url($LOCAL_PATH, PHP_URL_PATH);

    $timeslots = get_option('io_company_timeslots');
    if(empty($timeslots)) $timeslots = '""';//so js doesn't error below

    $delivery_methods = get_option('io_delivery_methods');
    if(empty($delivery_methods)) $delivery_methods = '""';//so js doesn't error below

    $io_delivery_prices_json = get_option('io_delivery_prices');
    if(!$io_delivery_prices_json || empty($io_delivery_prices_json)) {
        $io_delivery_prices_json = '{"default":[], "override":[]}';//so js doesn't error below
    }else{
        $io_delivery_prices_json = json_encode($io_delivery_prices_json);
    }

    $io_custom_prices_json = get_option('io_custom_prices');
    if(!$io_custom_prices_json || empty($io_custom_prices_json)) {
        $io_custom_prices_json = '{"default":[], "override":[]}';//so js doesn't error below
    }else{
        $io_custom_prices_json = json_encode($io_custom_prices_json);
    }

    $io_info_required_data_json = get_option('io_info_required_data');
    if(!$io_info_required_data_json || empty($io_info_required_data_json)) {
        $io_info_required_data_json = "[]";//so js doesn't error below
    }else{
        $io_info_required_data_json = json_encode($io_info_required_data_json);
    }

    $io_prices_json = json_encode(get_option('io_prices'));
    if(empty($io_prices_json)) $io_prices_json = "[]";//so js doesn't error below

    $delivery_methods_restrict = get_option('io_deliveryMethodRestrict');
    if(empty($delivery_methods_restrict)) $delivery_methods_restrict = '""';//so js doesn't error below

    $io_hideQuantityAvail = get_option('io_hideQuantityAvail');
    if(empty($io_hideQuantityAvail)) $io_hideQuantityAvail = "off";

    $io_hide_live_prices = get_option('io_hide_live_prices');
    if(empty($io_hide_live_prices)) $io_hide_live_prices = 1;

    $io_default_duration = get_option('io_default_duration');
    if(empty($io_default_duration)) $io_default_duration = 0;

    $customer_ip = io_get_client_ip(); //IO-21896 customer geolocation

    $html = '
     <style>
     '.$prices_css_hide_defaults
            .$prices_default_product_page_css
            .$hide_price_css
            .$hide_price_catpages_css
            .$price_override_css
            .$prices_override_hide_css
            .$hide_checkavail_css
            .$hidetimes_css
            .$hide_live_price_css
            .$showCategoryLong_css
            .$hide_listview_css
            .'
    .io_all_item_cat{
        display:none;
        float:none;
        width:100%;
        margin-top:20px;
    }
    </style>

<!-- Magic List -->
    <script>
    var io_wp_local_path = "'.$LOCAL_PATH.'";
    var io_checkavail = "'.$io_checkavail.'";
    var io_hidetimes = "'.$io_hidetimes.'";
    var io_user_country = "'.get_option('io_user_country').'";
    var io_user_currency = "'.get_option('io_user_currency').'";
    var io_default_start_time = "'.get_option('io_default_start_time').'";
    var io_default_end_time = "'.get_option('io_default_end_time').'";
    var io_default_duration = '.$io_default_duration.';
    var io_force_blank_timepickers = "'.get_option('io_cartForceBlank').'";
    var io_hide_end_time = "'.get_option('io_cartHideEndTime').'";
    var io_cart_date_format = "'.get_option('io_cart_date_format').'";
    var io_cart_message = "'.get_option('io_cartmessage').'";
    var io_cart_time_format = "'.get_option('io_cart_time_format').'";
    var io_multidayquote = "'.get_option('io_multidayquote').'";
    var io_cartdayselect = "'.get_option('io_cartdayselect').'";
    var io_cartAllowSameDay = "'.get_option('io_cartAllowSameDay').'";
    var io_overnightPickupTime = "'.get_option('io_overnightPickupTime').'";
    var io_incartupsell = "'.get_option('io_incartupsell').'";
    var io_distancecharge = "'.get_option('io_distancecharge').'";
    var io_deliverymethod = "'.get_option('io_deliverymethod').'";
    var io_brand = "'.get_option('io_brand').'";
    var io_restrict_times = "'.get_option('io_restricttimes').'";
    var io_restrict_time_start = "'.get_option('io_restrictTimeStart').'";
    var io_restrict_time_end = "'.get_option('io_restrictTimeEnd').'";
    var io_default_state = "'.get_option('io_default_state').'";
    var io_hide_zero = "'.get_option('io_hide_zero').'";
    var io_weekEndPrice = "'.get_option('io_weekEndPrice').'";
    var io_weekDayText = "'.get_option('io_weekDayText').'";
    var io_weekEndText = "'.get_option('io_weekEndText').'";
    var io_weekendDefine = "'.get_option('io_weekendDefine').'";
    var io_accessory_price = "'.get_option('io_accessory_price').'";
    var io_accessory_select = "'.get_option('io_accessoriesSelect').'";
    var io_upsell_price = "'.get_option('io_upsell_price').'";
    var io_cart_party_planner_email = "'.get_option('io_cartPartyPlannerEmail').'";
    var io_cart_party_planner_destination = "'.get_option('io_cartPartyPlannerDestination').'";
    var io_hideQuantityAvail = "'.$io_hideQuantityAvail.'";
    var io_company_timeslots = '.$timeslots.';
    var io_info_required = "'.get_option('io_info_required').'";
    var io_always_display_live_price = "'.get_option('io_always_display_live_price').'";
    var io_default_delivery_method = "'.get_option('io_defaultDeliveryMethod').'";
    var io_hide_live_prices = '.$io_hide_live_prices.';
    var io_info_required_data = '.$io_info_required_data_json.';
    var io_prices = '.$io_prices_json.';
    var io_delivery_prices = '.$io_delivery_prices_json.';
    var io_custom_prices = '.$io_custom_prices_json.';
    var io_delivery_methods = '.$delivery_methods.';
    var io_customer_geolocation = "'.get_option('io_customer_geolocation').'";
    var io_customer_ip = "'.$customer_ip .'";
    var io_delivery_methods_restrict = '.$delivery_methods_restrict.';
    var io_pagename = "'.get_option('io_pagename').'";
    var io_categoryVariantImages = "'.get_option('io_categoryVariantImages').'";
    //var io_seocitylinktext = "'.get_option('io_seocitylinktext').'";
    jQuery( document ).ready(function() {

        //force all quote form links to use cart data
        //removing back to cart shortcode as this needs to only be done if cart is not empty IO-22561
        /*
        let headerBookButton = jQuery("a[href$=\'io_quoteform/\']");
        headerBookButton.addClass("ioCart_link");
        headerBookButton.attr("href", "javascript:;");
        */


        let last_cat_name = "";
        let ioTrigger = false;
        jQuery(".io_all_item_cat").each(function() {
            current_cat_name = jQuery(this).html();
            if(last_cat_name !== current_cat_name) {
                jQuery(this).show();
                ioTrigger = true;
            }
            last_cat_name = current_cat_name;
        });

        // Setup gen page blocks
		let io_divs = document.querySelectorAll(".io_item2_list, .io_item2_listcat, .io_item2_listrent, .io_all_item_cat");
		let io_divscat = document.querySelectorAll(".io_item2_listcat");
		let io_divsrent = document.querySelectorAll(".io_item2_listrent");
		let io_divcat = document.querySelector(".io_catdiv2");
		let io_pcc = document.querySelector(".page-content");
		let io_html;

		if (io_divs.length > 0) {
	      for (let i of io_divs) {
	        if(i.parentNode.className.indexOf("io_mm_") === -1){
	          io_divcat.appendChild(i);
	        }
		  }
		  if(io_divcat!==null) io_divcat.style.display = "grid";
		}

		if (ioTrigger) {
            let pageBlock = document.querySelector(".io_catdiv2");
            pageBlock.classList.add("elementor-widget-heading");
            let scanRes = pageBlock.querySelectorAll(".io_item2_listrent");
            pageBlock.style.display = "block";
            pageBlock.style.margin = "auto";
            pageBlock.style.textAlign = "center";
            pageBlock.style.marginLeft = "5px";
            pageBlock.style.marginRight = "5px";
            for (let i of scanRes) {
                i.style.display = "inline-block";
                i.style.marginLeft = "5px";
                i.style.marginRight = "5px";
            }
        }

		/* fix font color on older sites */
		if(jQuery("#cartData").css("background-color")=="rgb(35, 36, 37)"){
		    jQuery("#cartData").css("color","white");
		}
    });
  </script>';

    //add the cart code to all pages
    $html .= shortcoder(Array('io_cart','page'=>get_option('io_pagename')),'');

    //add the review code to all pages
    $html .= io_get_review_script();

//remove contact us form from checkout pages
    if (get_option('is_template_site') == 1)
    {
        $html .= io_hide_contact_form_from_checkout();
    }
    if(is_multisite()){
        $io_multisiteRedirect = get_option('io_multisiteRedirect');
        $home = network_home_url();
        if($io_multisiteRedirect == "on"){
            $html .= '
                <script>
                    jQuery(document).on("click", ".io_locationRedirectLink", io_location_redirect_click);
                    jQuery(document).ready(function(){
                        let url = window.location.href;

                        if(!getCookie("io_location") || !url.includes(getCookie("io_location"))){
                            jQuery(".io_locationRedirectLink").css("display", "block");
                        }
                    });
                    function io_location_redirect_click(){
                        window.location.href = "'.$home.'";
                    }
                </script>
            ';
        }
    }

    echo $html;
}

function io_get_review_script(){
    $show_all_reviews = get_option('io_showAllReviews');
    $number_of_reviews = '10';
    if($show_all_reviews && $show_all_reviews == 'off'){
        $number_of_reviews = get_option('io_reviewAmount');
    }else if($show_all_reviews && $show_all_reviews == 'on'){
        $number_of_reviews = 'all';
    }
    $show_average_rating = get_option('io_showAverageRating');
    $show_average_style = '';
    if($show_average_rating && $show_average_rating =='off'){
        $show_average_style = 'style="display:none"';
    }
    $show_review_stars = get_option('io_showReviewStars');
    if(!$show_review_stars){
        $show_review_stars = 'on';
    }
    $show_review_date = get_option('io_showReviewDate');
    $show_date_style = '';
    if($show_review_date && $show_review_date =='off'){
        $show_date_style = 'style="display:none"';
    }
    $show_reviewer_name = get_option('io_showReviewerName');
    $show_name_style = '';
    if($show_reviewer_name && $show_reviewer_name =='off'){
        $show_name_style = 'style="display:none"';
    }
    $review_order = 'time';
    if(get_option('io_reviewOrder')){
        $review_order = get_option('io_reviewOrder');
    }
    $html = '
        <script>
        jQuery(".io_testimonials, #io_testimonials").each(function(){
           io_get_reviews(this);
        })
        setTimeout(function(){
            jQuery(".io_testimonials .w3-ul li p").each(function(){
                const container = jQuery(this).parent()
                const element = jQuery(this);

                if (element[0].scrollHeight > container[0].clientHeight) {

                    jQuery(this).parent().parent().append(create_read_more());
                }
            });
        }, 500);

        function create_read_more(){
            let html = "<p class=\"io_review_readmore\" onClick=\"review_readmore_clicked(this)\">read more</p>"
            return html;
        }

        function review_readmore_clicked(element){
            let review_li = jQuery(element).parent().find("li:eq(3)");
            new_height = jQuery(review_li).find("p").height() + 16;
            jQuery(review_li).height(new_height);
            jQuery(element).hide();
        }

        function io_get_reviews(element){
        let io_un = "' . get_option('io_username') . '";
	  let io_loc = "' . get_option('io_locationid') . '";
	  let io_url1 = \'https://rental.software/testimonials_iframe.php?user=\';
	  if (location.hostname === "localhost"){
	      io_url1 = \'http://localhost/io/bugs/testimonials_iframe.php?user=\';
          //io_url1 = \'http://localhost/jbug/trunk/testimonials_iframe.php?user=\';
        }
	  let io_url2 = \'&location_id=\';
	  let io_url3 = \'&width=100%&number_of_reviews='.$number_of_reviews.'&show_average_rating=1&show_stars=1&show_date=&show_reviewer_name=1&orderby='.$review_order.'&iframe=0\';
	  let io_url_c = io_url1 + io_un + io_url2 + io_loc + io_url3;
	  fetch(io_url_c, {
		method: \'get\'
	}).then(
	  function(response){
		 return response.json();
		}
	).then(function(data) {



	//let element = document.getElementById("io_testimonials");
	let out = "";
	let review_cnt=0;
	let rating_sum = 0;
	data.forEach((user) => {
				const { name, review, rating, time } = user;
				rating_sum += Number(rating);
				review_cnt++;
				let img_star = Math.round(parseFloat(rating));
				star = `<img class="review_img" src="https://rental.software/images/${img_star}star.png" />`;
				';
    if ($show_review_stars == "off"){
        $html.="star=``;";
    }
    $html.='
				out +=
				`<div>
					<ul class="w3-ul">
						<li '.$show_name_style.'>${name}</li>
						<li>${rating} ${star}</li>
						<li '.$show_date_style.'>${time}</li>
						<li> <p>${review}</p> </li>
					</ul>
				</div>`;
	});
	let avg = (parseFloat(rating_sum)/parseFloat(review_cnt)).toFixed(1);
	let avg_img = Math.round(avg);
	let head = `<div '.$show_average_style.'><h2>Avg Rating: ${avg}</h2><img class="review_avg_img" src="https://rental.software/images/${avg_img}star.png" /></div>`;
	element.innerHTML = head + out;
	return head+out;
	}).catch(function(err) {
		console.log(err);
	});
}

	  </script>';
    return $html;
}

function io_hide_contact_form_from_checkout()
{
    $keywords = array
    (
            'io_quoteform',
            'io_quoteconfirm',
            'io_contract',
            'io_contactform',
            'io_receipt',
            'io_vendor',
            'io_quotedone'
    );

    $current_uri = $_SERVER['REQUEST_URI'];

    // If any keyword is found in the URL, inject the CSS to hide .btm-sec
    foreach ($keywords as $keyword)
    {
        if ( strpos( $current_uri, $keyword ) !== false )
        {
            echo '<style>
                    .btm-sec 
                    {
                        display: none !important;
                    }
                  </style>';
            break;
        }
    }
}

function io_add_assets() {
    global $plugin_current_version;
    wp_enqueue_script( 'jquery' );
    wp_enqueue_style( 'io_styles', plugin_dir_url( __FILE__ ) . "io_styles_v6.css" );//WARN: Don't add v=? to URL can cause issues. css combiners detect changes, but we need to still version in case they aren't using one
    wp_enqueue_style('font-awesome', 'https://use.fontawesome.com/releases/v5.12.0/css/all.css');//if elementor installed, this gets skipped
    wp_enqueue_script( 'simpleCart', plugin_dir_url( __FILE__ ) . "simpleCart_v9.js" );


    wp_enqueue_script( 'jquery-ui-core' );
    wp_enqueue_script( 'jquery-ui-dialog' );
    wp_enqueue_script( 'jquery-ui-datepicker' );;
    wp_enqueue_style('datepicker_css', plugin_dir_url( __FILE__ ) . "jquery.datepicker.css" );
    wp_enqueue_script( 'timePicker', plugin_dir_url( __FILE__ ) . "jquery.timepicker.1_8_1.js" );
    wp_enqueue_style( 'timePicker_css', plugin_dir_url( __FILE__ ) . "jquery.timepicker.css" );
    wp_enqueue_script( 'fancyBox', plugin_dir_url( __FILE__ ) . "jquery.fancybox.js" );
    wp_enqueue_script( 'flickity', plugin_dir_url( __FILE__ ) . "flickity.js" );
    wp_enqueue_style( 'fancyBox_css', plugin_dir_url( __FILE__ ) . "jquery.fancybox.css" );
    wp_enqueue_script( 'widget-TentCalcJS', plugin_dir_url( __FILE__ ) . "widget-TentCalculator.js" );

}
function io_add_admin_assets(){
    wp_enqueue_script( 'timePicker', plugin_dir_url( __FILE__ ) . "jquery.timepicker.1_8_1.js" );
    wp_enqueue_style( 'timePicker_css', plugin_dir_url( __FILE__ ) . "jquery.timepicker.css" );
    wp_enqueue_script( 'jquery-ui-core' );
    wp_enqueue_script( 'io_url_protection', plugin_dir_url( __FILE__ ) . "io_url_protection.js" );
    // IO-30509 - Disabling for now because it doesn't seem necessary anymore.
    //wp_enqueue_script( 'hide_visual_tab_tinymce', plugin_dir_url( __FILE__ ) . "hide_visual_tab_tinymce.js" );
}
add_action( 'admin_footer', 'io_admin_footer' );
function io_admin_footer() {
    $html = '<style>.e-notice--dismissible,.e-notice-bar{display:none}</style>';
    echo $html;
}

if(get_option('io_username')<>'inflatableoffice') {
    add_action('wp_enqueue_scripts', 'io_add_assets');
    add_action('admin_enqueue_scripts', 'io_add_admin_assets');
    /*
    add_action( 'elementor/editor/before_enqueue_scripts', function() {
        wp_enqueue_script( 'hide_visual_tab_tinymce', plugin_dir_url( __FILE__ ) . "hide_visual_tab_tinymce.js" );
    } );
    */
}

add_action( 'wp_head', 'io_add_analytics_code_allpages' );
function io_add_analytics_code_allpages(){
    if(strpos($_SERVER['REQUEST_URI'],'io_')!==FALSE) return;
    $html = '';
    $io_analytics_active = get_option('io_analytics_active');
    if($io_analytics_active==1){
        $html .= get_option('io_analytics_code');
    }
    echo $html;
}



//custom options
function customtheme_customize_register_io( $wp_customize ) {

    $wp_customize->add_section(
            'customtheme_header_options2',
            array(
                    'title'       => __( 'IO Plugin Settings', 'customtheme' ),
                    'priority'    => 100,
                    'capability'  => 'edit_theme_options',
                    'description' => __('Change IO plugin options here.', 'customtheme'),
            )
    );
    $wp_customize->add_setting( 'darkmode_enable',
            array(
                    'default' => '',
                    "transport" => "refresh",
                    'sanitize_callback' => 'io_sanitize_checkbox',
            )
    );
    $wp_customize->add_control( new WP_Customize_Control(
            $wp_customize,
            'darkmode_enable_control',
            array(
                    'label'    => __( 'Enable Dark Mode', 'customtheme' ),
                    'description' => __( 'Warning! Experimental Feature' ),
                    'section'  => 'customtheme_header_options2',
                    'settings' => 'darkmode_enable',
                    'priority' => 10,
                    'type'  => 'checkbox',
            )
    ));
    $wp_customize->add_setting( 'iopageext_enable',
            array(
                    'default' => '',
                    "transport" => "refresh",
                    'sanitize_callback' => 'io_sanitize_checkbox',
            )
    );
    $wp_customize->add_control( new WP_Customize_Control(
            $wp_customize,
            'iopageext_enable_control',
            array(
                    'label'    => __( 'Enable Extended Feature Mode', 'customtheme' ),
                    'description' => __( 'Warning! Experimental Feature' ),
                    'section'  => 'customtheme_header_options2',
                    'settings' => 'iopageext_enable',
                    'priority' => 10,
                    'type'  => 'checkbox',
            )
    ));

    function io_sanitize_checkbox( $checked ) {
        return ( ( isset( $checked ) && true == $checked ) ? true : false );
    }
}
//add_action( 'customize_register', 'customtheme_customize_register_io', 11 );

//allows sync of elementor pages via meta tbl
function register_posts_meta_field() {
    $object_type = 'post';
    $args1 = array( // Validate and sanitize the meta value.
        // Note: currently (4.7) one of 'string', 'boolean', 'integer',
        // 'number' must be used as 'type'. The default is 'string'.
            'type'         => 'string',
        // Shown in the schema for the meta key.
            'description'  => 'A meta key associated with a string meta value.',
        // Return a single value of the type.
            'single'       => true,
        // Show in the WP REST API response. Default: false.
            'show_in_rest' => true,
            'auth_callback' => function() {
                return current_user_can( 'edit_posts' );
            },
    );
    register_meta( $object_type, '_elementor_data', $args1 );
    register_meta( $object_type, 'io_meta_description', $args1 );
}
add_action( 'rest_api_init', 'register_posts_meta_field' );


//allows sync of analytics code (or any option)
function register_site_options() {
    register_rest_route( 'inflatableoffice/v1', '/options/(?P<id>[-_a-zA-Z0-9-]+)', array(
            'methods' => 'GET,POST',
            'callback' => 'io_options',
            'permission_callback' => function() {
                return current_user_can( 'edit_posts' );
                //     return true;
            },
    ) );
}
function io_options($data) {
    if($data->get_method()=='POST'){
        if($data['id']=='io_cart_time_format'){
            //$value = get_option($data['id']);
            //so we only run this if it's changed, but okay to run it every time
            //if($value<>$data->get_body()){
            //convert times. the sync handles this as well for start/end but not for the other time fields
            //it's good to have it in both places in case they aren't using newer plugin that has this
            $time = date($data->get_body(), strtotime(get_option('io_default_start_time')));
            update_option('io_default_start_time', $time);
            $time = date($data->get_body(), strtotime(get_option('io_default_end_time')));
            update_option('io_default_end_time', $time);
            $time = date($data->get_body(), strtotime(get_option('io_overnightPickupTime')));
            update_option('io_overnightPickupTime', $time);
            $time = date($data->get_body(), strtotime(get_option('io_restrictTimeStart')));
            update_option('io_restrictTimeStart', $time);
            $time = date($data->get_body(), strtotime(get_option('io_restrictTimeEnd')));
            update_option('io_restrictTimeEnd', $time);
            //}
        }
        update_option($data['id'],$data->get_body());
    }
    $value = get_option($data['id']);
    return $value;
}

add_action( 'rest_api_init', 'register_site_options' );

add_action('TentCalcSubmit', function(){
    $thing = 1;
});

//add to the submit of the elementor form to call our contact us page
add_action( 'elementor_pro/forms/new_record', "io_handle_elementor_form_submit", 10, 3);
function io_handle_elementor_form_submit($record, $handler){
    $io_makeLeadsOnForms = get_option('io_makeLeadsOnForms');
    $io_excludeforms = get_option('io_excludeforms');
    $io_excludeforms_arr = array_map('trim', explode(',', $io_excludeforms));

    if($io_makeLeadsOnForms == 'on'){
        $form_name = $record->get_form_settings( 'form_name' );
        if(in_array($form_name,$io_excludeforms_arr)) return;
        $io_pagename = get_option('io_pagename');
        $page_name = urlencode($io_pagename);//'Demo+Rentals+LLC';
        $page_name = '&name='.$page_name;
        $link_params = '&elemCTA=1';
        // IO-28339 add additional
        $io_url_params = get_option('io_url_params');
        if($io_url_params) {
            $io_url_params = json_decode($io_url_params);
            foreach ($io_url_params as $io_url_param) {
                if (isset($_COOKIE[$io_url_param->urlparam_cookiename])) {
                    $cookie_value = $_COOKIE[$io_url_param->urlparam_cookiename];
                    // Protect against XSS by only allowing alphanumeric characters and basic punctuation
                    if (preg_match('/^[a-zA-Z0-9\s\-_.,;:!?\'"\(\)]+$/', $cookie_value)) {
                        $link_params .= '&' . $io_url_param->urlparam_paramname . '=' . $cookie_value;
                    }
                }
            }
        }


        $cust_ip = $_SERVER['REMOTE_ADDR'];
        if(!empty($_SERVER['HTTP_CLIENT_IP']) && filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP)) $cust_ip = $_SERVER['HTTP_CLIENT_IP'];
        if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP)) $cust_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        if(!empty($_SERVER['HTTP_X_SUCURI_CLIENTIP']) && filter_var($_SERVER['HTTP_X_SUCURI_CLIENTIP'], FILTER_VALIDATE_IP)) $cust_ip = $_SERVER['HTTP_X_SUCURI_CLIENTIP'];
        $ips = explode(',', $cust_ip, 2);
        $cust_ip = urlencode(trim($ips[0]));
        $link_params .= '&io_custip='.$cust_ip.'&io_custguid='.urlencode($_COOKIE['guid']);

        $link = 'https://rental.software/quotes/contactme.php?nowrap=1'.$page_name.$link_params;
        //$link = 'http://localhost/io/bugs/quotes/contactme.php?nowrap=1'.$page_name.$link_params;
        $fields = Array();
        $raw_fields = $record->get( 'fields' );
        foreach ($raw_fields as $k=>$v){
            if($k=='name') $k='firstandlastname';
            if($k=='message') $k='notes';
            if($v['type']=='html') continue;
            if(strpos($k,'customfield_')!==FALSE) $k=str_replace('customfield_','customfield-',$k);
            $v = trim($v["value"]);

            //non-standard fields will additionally get appended to the notes
            // setupduration
            if(!in_array($k,Array('okToTextPresent','oktotext','startdate','starttime','enddate','endtime','taxexempt',
                            'eventname','salesrep','eventstreet','eventzip','eventcity','eventstate','deliverytype', 'street',
                            'zip','state','city','officephone','custtags','oktotext','firstandlastname','cellphone','email',
                            'firstname','lastname','eventorganization','notes','title', 'attachment', 'surface',
                            'elementor_statusid', 'utm_source', 'utm_medium', 'utm_campaign')) && strpos($k,'customfield-')===FALSE){
                $fields['notes'] .= "\n".$k.': '.$v;
            }

            $fields[$k] .= $v;
        }
        $fields['notes'] = trim($fields['notes']);
        $fields['from_wp'] = 1;
        //$fields['notes'].="\nPage URL: ".$_POST['referrer'];

        $result = wp_safe_remote_post( $link, [
                'body' => $fields,
                'timeout' => 20
        ]);
        $result = json_decode($result['body']);
        if($result->redirect_url && empty($record->get_form_settings('redirect_to'))){
            $handler->add_response_data( 'redirect_url', $result->redirect_url );
        }
        //echo $result;
    }
}

//prevent sg optimizer from combining our js files otherwise it screws up the quote page (if that option is turned on)
add_filter( 'sgo_javascript_combine_exclude_all_inline', '__return_true' );
add_filter( 'sgo_javascript_combine_excluded_external_paths', 'js_combine_exclude_external_script' );
function js_combine_exclude_external_script( $exclude_list ) {
    $exclude_list[] = 'rental.software';

    return $exclude_list;
}

add_action('admin_head-edit.php','add_remove_dupes_button');
function add_remove_dupes_button(){
    global $current_screen;
    $username = get_option('io_username');
    $location_id = get_option('io_locationid');
    add_thickbox();

    if($current_screen->post_type == "page"){
        ?>
        <style>
            .io_load_spinner {
                margin-left: 5px;
                border: 5px solid #d4d3d3;
                border-top: 5px solid #2271b1;
                border-radius: 50%;
                width: 16px;
                height: 16px;
                animation: spin 2s linear infinite;
                display: none;
            }

            @keyframes spin {
                0% { transform: rotate(0deg); }
                100% { transform: rotate(360deg); }
            }
        </style>
        <script>
            jQuery(document).ready(function(){
                let html = '<div style="display:inline-flex">' +
                    '<a title="Warning" href="#TB_inline?width=600&height=220&inlineId=io-remove-pages_warning" class="page-title-action thickbox">Remove Duplicate IO Pages</a>' +
                    '<div class="io_load_spinner"></div>' +
                    '</div>' +
                    '<div id="io-remove-pages_warning" style="display:none;">' +
                    '<p> Be aware. This is a fully automated process with NO human supervision. Pages you may not want removed may be moved to trash or deleted. If you are not hosted on an IO server be sure to make a backup of your site in case you need to restore.</p>' +
                    '<p> If you have a very large number of pages to sift through this process may take some time and will time out after 10 minutes. While the process is running do not close this page and do not attempt to start another.</p>' +
                    '<div style="width:100%;display: inline-flex;justify-content: space-between;">' +
                    '<button onClick="cancel_io_page_remove()">Cancel</button>' +
                    '<button onClick="remove_orphan_pages()" style="background-color: #d63638;border-color: #d63638;" class="button button-primary">I Understand. Proceed.</button></div></div>';
                jQuery(html).insertBefore(".wp-header-end");
                jQuery('#io_remove_dupe').on("click", remove_orphan_pages);
            });

            function cancel_io_page_remove(){
                jQuery("#TB_closeWindowButton").trigger("click");
            }

            function remove_orphan_pages(){
                jQuery("#TB_closeWindowButton").trigger("click");
                jQuery(".io_load_spinner").show();
                var params = "username=<?php echo $username ?>&location=<?php echo $location_id ?>&url=";
                var domain = window.location.href.replace("/wp-admin/edit.php", "").split("?")[0];
                params += domain;
                var io_filter_dir = "<?php echo$_SERVER['SCRIPT_NAME'] ?>";
                var io_filter_server_name = "<?php echo$_SERVER['SERVER_NAME'] ?>";
                var io_filter_server_scheme = "<?php echo$_SERVER['REQUEST_SCHEME'] ?>";
                var url = io_filter_server_scheme+"://"+io_filter_server_name+io_filter_dir.replace("/wp-admin/edit.php", "/wp-content/plugins/inflatableoffice/remove_orphan_pages.php?");
                url += params;
                jQuery.ajax({
                    type: "POST",
                    url: url,
                    dataType: "text",
                    success: function(data){location.reload()},
                    error: function(data){location.reload()},
                    timeout: 600000 // 10 minute timer
                });
            }

            function reload_after_remove(data){
                window.location.reload();
            }
        </script>
        <?php
    }
}

add_action("add_meta_boxes", "add_custom_meta_box");
function add_custom_meta_box(){
    add_meta_box("demo-meta-box", "InflatableOffice", "custom_meta_box_markup", "page", "side", "high", null);
}

function custom_meta_box_markup($object){
    wp_nonce_field(basename(__FILE__), "meta-box-nonce");
    $checkbox_value = get_post_meta($object->ID, "io-include-featured", true);

    if($checkbox_value == "")
    {
        ?>
        <input name="io-include-featured" type="checkbox" value="true">
        <label>Make this page selectable in IO Featured Product Widget</label>
        <?php
    }
    else if($checkbox_value == "true")
    {
        ?>
        <input name="io-include-featured" type="checkbox" value="true" checked>
        <label>Make this page selectable in IO Featured Product Widget</label>
        <?php
    }
}
add_action("save_post", "save_custom_meta_box", 10, 3);
function save_custom_meta_box($post_id, $post, $update)
{
    if (!isset($_POST["meta-box-nonce"]) || !wp_verify_nonce($_POST["meta-box-nonce"], basename(__FILE__)))
        return $post_id;

    if(!current_user_can("edit_post", $post_id))
        return $post_id;

    if(defined("DOING_AUTOSAVE") && DOING_AUTOSAVE)
        return $post_id;

    $slug = "page";
    if($slug != $post->post_type)
        return $post_id;

    $meta_box_checkbox_value = "";

    if(isset($_POST["io-include-featured"]))
    {
        $meta_box_checkbox_value = $_POST["io-include-featured"];
    }
    update_post_meta($post_id, "io-include-featured", $meta_box_checkbox_value);
}

/* IO-14955: get/set option in wp_options */
function register_social_api() {
    register_rest_route( 'inflatableoffice/v1', '/social_posts/(?P<id>[-_a-zA-Z0-9-]+)', array(
            'methods' => 'POST',
            'callback' => 'io_social_posts'
    ) );
}

/**
 * The call back for when the REST endpoint for marketing posts gets hit
 * $data['id'] = 'wp_options' table => 'option_name' field
 * @param $data
 * @return mixed
 */
function io_social_posts(WP_REST_Request $request) {

//Route data based on optionName param
    $params = $request->get_params();
    $optionName = urldecode($params['optionName']);

    switch($optionName) {
        case "io_gmb_access":

            require_once(dirname(__FILE__) . '/social_api_factory.php');

            $data = array
            (
                    'option_name' => $optionName,
                    'site_url'=> urldecode($params['siteURL']),
                    'rental_name' => urldecode($params['rentalName']),
                    'rental_description' => urldecode($params['rentalDescription']),
                    'rental_image' => urldecode($params['rentalImage']),
                    'rental_url' => urldecode($params['rentalURL']),
                    'category_name' => urldecode($params['categoryName']),
                    'category_description' => urldecode($params['categoryDescription']),
                    'category_image' => urldecode($params['categoryImage']),
                    'category_url' => urldecode($params['categoryURL']),
            );

            $logoURL = get_media_url_by_name('logoForGooglePosts.png');
            if ($logoURL)
            {
                $data['hype_description'] = urldecode($params['hypeText']);
                $data['hype_image'] = $logoURL;
            }

            //logging
            if (! update_option('io_gmb_rest_params', json_encode($data))){
                add_option('io_gmb_rest_params', json_encode($data));
            }

            $gmb = social_api_factory::create("GoogleMyBusiness");

            return $gmb->createPost($data);
    }

}
add_action('rest_api_init', 'register_social_api');

#region IO-27771 Improved Reviews II
function register_testimonials_api()
{
    register_rest_route('inflatableoffice/v1', '/sync_testimonials', array
    (
            'methods' => 'POST',
            'callback' => 'io_sync_testimonials'
    ));
}
/**
 * The callback for when the REST endpoint for syncing testimonials gets hit.
 * @param WP_REST_Request $request
 * @return mixed
 */
function io_sync_testimonials(WP_REST_Request $request)
{
    $testimonials = $request->get_params();

// Get the excluded testimonial IDs
    $excludedTestimonials = get_option('io_reviews_iotestimonials_exclusions', []);

// Filter out excluded testimonials
    $filteredTestimonials = array_filter($testimonials, function($testimonial) use ($excludedTestimonials)
    {
        return !in_array($testimonial['testimonial_id'], $excludedTestimonials);
    });

    if (!update_option('io_reviews_iotestimonials', json_encode($filteredTestimonials)))
    {
        add_option('io_reviews_iotestimonials', json_encode($filteredTestimonials));
    }
}
add_action('rest_api_init', 'register_testimonials_api');

function enqueue_review_styles($hook)
{
    if ($hook === 'inflatableoffice_page_io_reviews')
    {
        wp_enqueue_style('bootstrap-css', 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css');
        wp_enqueue_script('popper-js', 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js', array('jquery'), null, true);
        wp_enqueue_script('bootstrap-js', 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js', array('jquery'), null, true);
        wp_enqueue_style('font-awesome', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css');
    }
}
add_action('admin_enqueue_scripts', 'enqueue_review_styles');

function register_io_reviews_widget()
{
    require_once( __DIR__ . '/widget-reviews.php' );
}
add_action( 'elementor/widgets/widgets_registered', 'register_io_reviews_widget' );

function enqueue_slick_carousel()
{
    wp_enqueue_style( 'slick-carousel-css', 'https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.css' );
    wp_enqueue_style( 'slick-carousel-theme-css', 'https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.min.css' );
    wp_enqueue_script( 'slick-carousel-js', 'https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.js', [ 'jquery' ], '1.8.1', true );
}
add_action( 'wp_enqueue_scripts', 'enqueue_slick_carousel' );


function enqueue_dashicons()
{
    wp_enqueue_style('dashicons');
}
add_action('wp_enqueue_scripts', 'enqueue_dashicons');

function schedule_import_google_reviews_cron()
{
    if ( ! wp_next_scheduled( 'import_new_google_reviews_hook' ) )
    {
        wp_schedule_event( time(), 'hourly', 'import_new_google_reviews_hook' );
    }
}
add_action( 'wp_loaded', 'schedule_import_google_reviews_cron' );

function import_google_reviews_cron()
{
    $last_run = get_option('io_reviews_last_import_run', 0);
    $current_time = time();
    $one_day = 24 * 60 * 60; // 24 hours in seconds

    if (($current_time - $last_run) < $one_day)
    {
        return; // Exit early if less than 24 hours since last run
    }

    $controller_file_path = plugin_dir_path( __FILE__ ) . 'reviews/controller.php';

    if ( file_exists( $controller_file_path ) )
    {
        require_once $controller_file_path;

        if (class_exists('IO_Reviews_Admin_Page'))
        {
            $admin_page = new IO_Reviews_Admin_Page();
            if (method_exists($admin_page, 'check_reviews'))
            {
                $admin_page->check_reviews();
                //update timestamp of last run
                update_option('io_reviews_last_import_run', $current_time);
            }
        }
    }
}
add_action( 'import_new_google_reviews_hook', 'import_google_reviews_cron' );

#endregion IO-27771


add_filter('autoptimize_filter_noptimize','stop_autoptimize_on_quote_page',10,1);
function stop_autoptimize_on_quote_page($flag) {
    if (strpos($_SERVER['REQUEST_URI'],'io_')!== false) {
        return true;
    } else {
        return $flag;
    }
}


add_filter( 'sgs_whitelist_wp_content' , 'whitelist_filter_file_in_wp_content' );
function whitelist_filter_file_in_wp_content( $whitelist ) {
    $whitelist[] = 'remove_orphan_pages.php';
    $whitelist[] = 'website_filter.php';
    $whitelist[] = 'TentCalcSubmit.php';
    $whitelist[] = 'login.php';
    return $whitelist;
}

function io_get_variable($atts){
    return $_GET[$atts['name']];
}
add_shortcode( 'io_get_variable', 'io_get_variable');

function get_media_url_by_name($file_name)
{
    global $wpdb;

// Remove the file extension
    $file_name_without_extension = pathinfo($file_name, PATHINFO_FILENAME);

    $query = $wpdb->prepare("
        SELECT ID
        FROM {$wpdb->prefix}posts
        WHERE post_type = 'attachment'
        AND post_mime_type LIKE 'image/%'
        AND post_title = %s
        LIMIT 1
    ", $file_name_without_extension);

    $attachment_id = $wpdb->get_var($query);

    if ($attachment_id)
    {
        return wp_get_attachment_url($attachment_id);
    }
    else
    {
        return false;
    }
}
//IO-31013: sometimes a native wp function wraps scripts with <br> tags and then forgets to clean them up
function remove_br_after_shortcode_script($content){
    return preg_replace(
            '/(<script\b[^>]*>.*?<\/script>)(?:<br\s*\/?>\s*)+/is',
            '$1',
            $content
    );
}
add_filter('the_content','remove_br_after_shortcode_script',20);

add_action('rest_api_init', function() {
    register_rest_route('inflatableoffice/v1', '/clear_elementor_cache', [
            'methods'             => 'POST',
            'permission_callback' => function() {
                return current_user_can('edit_posts');
            },
            'callback'            => function() {
                if ( ! class_exists( \Elementor\Plugin::class ) ) {
                    return new WP_Error( 'elementor_missing', 'Elementor plugin not installed/activated', [ 'status' => 404 ] );
                }

                $el = \Elementor\Plugin::instance();
                $caches_cleared = [];
                foreach ( [ 'files_manager', 'assets_manager' ] as $mgr ) {
                    if ( isset( $el->$mgr ) && is_callable( [ $el->$mgr, 'clear_cache' ] ) ) {
                        $el->$mgr->clear_cache();
                        $caches_cleared[] = $mgr;
                    }
                }

                return rest_ensure_response( [ 'success' => true, 'cleared' => $caches_cleared, 'code' => 200] );
            },
    ]);

});
