Hoşgeldin Misafir

Wisecp Datawise Tema

richard

19 Şub 2023
300 Mesaj

Aktiflik

Seviye

Deneyim

TIM / GÖREV:

@N0STR4 Datawise 1.0.9.1 surum icinde theme.php dosyasını cözdüm ama diyer modul cözdüm ama biraz ugraşın diye paylaşmıyorum tama calıştırmak icin FonPageBuilder icinde lisans mekanizması var theme icinde lisans mekanızması yok @Graves şifreli 3 dosyayı sana yolladım zaten istersen paylaş kırabilen varsa kırsın​

PHP:
<?php

class Datawise_Theme
{
    public $name = 'Datawise';
    public $error = null;
    public $db_prefix = null;
    public $lang = null;
    public $language = null;
    public $languages = null;
    public array $config = [];
    private array $assets = [];
    private array $styles = [];
    private array $scripts = [];
    private array $headerCodes = [];
    private static $builderConfig = [];
    private static $lcpHandled = false;

    public function __construct()
    {
        if (!$this->languages) {
            $this->languages = View::$init->theme_language_loader($this->name);
        }

        if (!$this->language) {
            $this->language = View::$init->theme_lang(Language::selected(), $this->languages);
        }

        if (!$this->lang) {
            $this->lang = Language::selected();
        }

        $this->db_prefix = (Config::get('database/prefix') ? Config::get('database/prefix') . '_' : '');
        $this->config = include __DIR__ . DS . 'theme-config.php';
        self::$builderConfig = Modules::Config('Addons', 'FonPageBuilder');
        $this->checkAndUpdateVersion();

        if (DEMO_MODE) {
            $headerType = Cookie::get('fon_header_type');

            if (isset($_GET['setHeaderType'])) {
                $setHeaderType = $_GET['setHeaderType'];
                Cookie::set('fon_header_type', $setHeaderType ?: 'header');
                $headerType = $setHeaderType;
            }

            Config::set('theme', ['header-type' => $headerType ?: 'header']);
            $headerStyle = Cookie::get('fon_header_style');

            if (isset($_GET['setHeaderStyle'])) {
                $setHeaderStyle = $_GET['setHeaderStyle'];
                Cookie::set('fon_header_style', $setHeaderStyle ?: 'header_compact');
                $headerStyle = $setHeaderStyle;
            }

            Config::set('theme', ['header_style' => $headerStyle ?: 'header_compact']);
            $primaryColor = Cookie::get('fon_primary_color');

            if (isset($_GET['setPrimaryColor'])) {
                $setPrimaryColor = $_GET['setPrimaryColor'];
                Cookie::set('fon_primary_color', $setPrimaryColor ?: Config::get('theme/color1'));
                $primaryColor = $setPrimaryColor;
            }

            Config::set('theme', ['color1' => ltrim($primaryColor, '#') ?: Config::get('theme/color1')]);
        }
    }

    public function router(array $params = []): mixed
    {
        $raw = implode('/', $params);
        $page = Filter::folder((isset($params[0]) ? $params[0] : ''));
        if (($params[0] ?? false) && $params[1] ?? false && file_exists(__DIR__ . DS . 'pages' . DS . Filter::folder($params[0] ?? false) . DS . Filter::folder($params[1] ?? false) . '.php')) {
            return ['include_file' => __DIR__ . DS . 'pages' . DS . Filter::folder($params[0] ?? false) . DS . Filter::folder($params[1] ?? false) . '.php'];
        }
        else if ($page && file_exists(__DIR__ . DS . 'pages' . DS . $page . '.php')) {
            return ['include_file' => __DIR__ . DS . 'pages' . DS . $page . '.php'];
        }

        return false;
    }

    public function change_settings(): array
    {
        $settings = (isset($this->config['settings']) ? $this->config['settings'] : []);
        $languages = Bootstrap::$lang->rank_list('active');
        $header_type = Filter::init('POST/header_type', 'hclear');
        $clientArea_type = (int) Filter::init('POST/clientArea_type', 'numbers');
        $color1 = ltrim(Filter::init('POST/color1'), '#');
        $color2 = ltrim(Filter::init('POST/color2'), '#');
        $text_color = ltrim(Filter::init('POST/text-color'), '#');
        $link_color = ltrim(Filter::init('POST/link_color'), '#');
        $link_color_hover = ltrim(Filter::init('POST/link_color_hover'), '#');
        $link_color_active = ltrim(Filter::init('POST/link_color_active'), '#');
        $articles_style = (int) Filter::init('POST/articles_style', 'numbers');
        $news_style = (int) Filter::init('POST/news_style', 'numbers');
        $references_style = (int) Filter::init('POST/references_style', 'numbers');
        $software_style = (int) Filter::init('POST/software_style', 'numbers');
        $image_sizes = Filter::init('POST/image_sizes', 'array');
        $sticky_header = (bool) Filter::init('POST/sticky_header', 'numbers');
        $cache_pages = (bool) Filter::init('POST/cache_pages', 'numbers');
        $show_preloader = (bool) Filter::init('POST/show_preloader', 'numbers');
        $preloader = Filter::init('POST/site_preloader', 'hclear');
        $preloader_bg = ltrim(Filter::init('POST/site_preloader_bg'), '#');
        $show_totop = (bool) Filter::init('POST/show_totop', 'numbers');
        $show_contact_info = (bool) Filter::init('POST/show_contact_info', 'numbers');
        $top_notify_show = (bool) Filter::init('POST/top_notify_show', 'numbers');
        $top_notify_text = Filter::init('POST/top_notify_text', 'array');
        $top_notify_show_link = (bool) Filter::init('POST/top_notify_show_link', 'numbers');
        $top_notify_link = Filter::init('POST/top_notify_link', 'array');
        $top_notify_link_text = Filter::init('POST/top_notify_link_text', 'array');
        $top_notify_show_countdown = (bool) Filter::init('POST/top_notify_show_countdown', 'numbers');
        $top_notify_countdown_date = Filter::init('POST/top_notify_countdown_date', 'hclear');
        $top_notify_countdown_time = Filter::init('POST/top_notify_countdown_time', 'hclear');
        $top_notify_show_close = (bool) Filter::init('POST/top_notify_show_close', 'numbers');
        $popup_notify_show = (bool) Filter::init('POST/popup_notify_show', 'numbers');
        $popup_notify_image = Filter::init('POST/popup_notify_image', 'array');
        $popup_notify_show_link = (bool) Filter::init('POST/popup_notify_show_link', 'numbers');
        $popup_notify_link = Filter::init('POST/popup_notify_link', 'array');
        $popup_notify_link_text = Filter::init('POST/popup_notify_link_text', 'array');
        $popup_notify_show_countdown = (bool) Filter::init('POST/popup_notify_show_countdown', 'numbers');
        $popup_notify_countdown_date = Filter::init('POST/popup_notify_countdown_date', 'hclear');
        $popup_notify_countdown_time = Filter::init('POST/popup_notify_countdown_time', 'hclear');
        $popup_notify_display = Filter::init('POST/popup_notify_display', 'hclear');
        $popup_notify_display_when = Filter::init('POST/popup_notify_display_when', 'hclear');
        $right_click = (bool) Filter::init('POST/right_click', 'numbers');
        $header_style = Filter::init('POST/header_style', 'hclear');
        $header_style_align = Filter::init('POST/header_style_align', 'hclear');
        $header_search = (bool) Filter::init('POST/header_search', 'numbers');
        $header_phone = (bool) Filter::init('POST/header_phone', 'numbers');
        $header_email = (bool) Filter::init('POST/header_email', 'numbers');
        $header_social = (bool) Filter::init('POST/header_social', 'numbers');
        $header_lang = (bool) Filter::init('POST/header_lang', 'numbers');
        $header_currency = (bool) Filter::init('POST/header_currency', 'numbers');
        $header_ticket = (bool) Filter::init('POST/header_ticket', 'numbers');
        $header_seperated_sign = (bool) Filter::init('POST/header_seperated_sign', 'numbers');
        $show_whatsapp = (bool) Filter::init('POST/show_whatsapp', 'numbers');
        $whatsapp_number = Filter::init('POST/whatsapp_number', 'hclear');
        $show_phone = (bool) Filter::init('POST/show_phone', 'numbers');
        $seo_gsd_show = (bool) Filter::init('POST/seo_gsd_show', 'numbers');
        $seo_site_name = Filter::init('POST/seo_site_name', 'array');
        $seo_organisation_name = Filter::init('POST/seo_organisation_name', 'array');
        $seo_organisation_country = Filter::init('POST/seo_organisation_country', 'hclear');
        $seo_organisation_city = Filter::init('POST/seo_organisation_city', 'hclear');
        $seo_organisation_region = Filter::init('POST/seo_organisation_region', 'hclear');
        $seo_organisation_address = Filter::init('POST/seo_organisation_address', 'hclear');
        $seo_organisation_postal_code = Filter::init('POST/seo_organisation_postal_code', 'hclear');
        $seo_organisation_price_min = (int) Filter::init('POST/seo_organisation_price_min', 'numbers');
        $seo_organisation_price_max = (int) Filter::init('POST/seo_organisation_price_max', 'numbers');
        $seo_organisation_price_currency = (int) Filter::init('POST/seo_organisation_price_currency', 'numbers');
        $seo_organisation_rating_value = Filter::init('POST/seo_organisation_rating_value', 'hclear');
        $seo_organisation_rating_count = (int) Filter::init('POST/seo_organisation_rating_count', 'numbers');
        $fonts = Filter::init('POST/fonts', 'array');
        $external_login = (bool) Filter::init('POST/external_login', 'numbers');
        $use_cdn = (bool) Filter::init('POST/use_cdn', 'numbers');
        $package_style = (int) Filter::init('POST/package_style', 'numbers');
        $order_steps_monthly_price = (int) Filter::init('POST/order_steps_monthly_price', 'numbers');
        $footer_bg_image = Filter::init('POST/footer_bg_image', 'hclear');
        $show_footer_home_newsletter = (bool) Filter::init('POST/show_footer_home_newsletter', 'numbers');
        $show_footer_social = (bool) Filter::init('POST/show_footer_social', 'numbers');
        $show_secure_and_payment_icons = (bool) Filter::init('POST/show_secure_and_payment_icons', 'numbers');
        $footer_copyright_text = Filter::init('POST/footer_copyright_text', 'array');
        $enable_lazy_loading = (bool) Filter::init('POST/enable_lazy_loading', 'numbers');
        $google_analytics_id = Filter::init('POST/google_analytics_id', 'hclear');
        $google_ads_id = Filter::init('POST/google_ads_id', 'hclear');
        $google_conversion_id = Filter::init('POST/google_conversion_id', 'hclear');
        $facebook_pixel_id = Filter::init('POST/facebook_pixel_id', 'hclear');
        $google_tm_id = Filter::init('POST/google_tm_id', 'hclear');
        $fb_pixel_via_gtm = (bool) Filter::init('POST/fb_pixel_via_gtm', 'numbers');

        if ($header_type != $settings['header-type']) {
            $settings['header-type'] = $header_type;
        }

        if ($header_search != $settings['header_search']) {
            $settings['header_search'] = $header_search;
        }

        if ($header_phone != $settings['header_phone']) {
            $settings['header_phone'] = $header_phone;
        }

        if ($header_email != $settings['header_email']) {
            $settings['header_email'] = $header_email;
        }

        if ($header_social != $settings['header_social']) {
            $settings['header_social'] = $header_social;
        }

        if ($header_lang != $settings['header_lang']) {
            $settings['header_lang'] = $header_lang;
        }

        if ($header_currency != $settings['header_currency']) {
            $settings['header_currency'] = $header_currency;
        }

        if ($header_ticket != $settings['header_ticket']) {
            $settings['header_ticket'] = $header_ticket;
        }

        if ($header_seperated_sign != $settings['header_seperated_sign']) {
            $settings['header_seperated_sign'] = $header_seperated_sign;
        }

        if ($footer_bg_image != $settings['footer_bg_image']) {
            $settings['footer_bg_image'] = $footer_bg_image;
        }

        if ($show_footer_home_newsletter != $settings['show_footer_home_newsletter']) {
            $settings['show_footer_home_newsletter'] = $show_footer_home_newsletter;
        }

        if ($show_footer_social != $settings['show_footer_social']) {
            $settings['show_footer_social'] = $show_footer_social;
        }

        if ($show_secure_and_payment_icons != $settings['show_secure_and_payment_icons']) {
            $settings['show_secure_and_payment_icons'] = $show_secure_and_payment_icons;
        }

        if ($clientArea_type != $settings['clientArea-type']) {
            $settings['clientArea-type'] = $clientArea_type;
        }

        if ($color1 != $settings['color1']) {
            $settings['color1'] = $color1;
            $settings['meta-color'] = '#' . $color1;
        }

        if ($color2 != $settings['color2']) {
            $settings['color2'] = $color2;
        }

        if ($text_color != $settings['text-color']) {
            $settings['text-color'] = $text_color;
        }

        if ($link_color != $settings['link_color']) {
            $settings['link_color'] = $link_color;
        }

        if ($link_color_hover != $settings['link_color_hover']) {
            $settings['link_color_hover'] = $link_color_hover;
        }

        if ($link_color_active != $settings['link_color_active']) {
            $settings['link_color_active'] = $link_color_active;
        }

        if ($articles_style != $settings['articles_style']) {
            $settings['articles_style'] = $articles_style;
        }

        if ($news_style != $settings['news_style']) {
            $settings['news_style'] = $news_style;
        }

        if ($references_style != $settings['references_style']) {
            $settings['references_style'] = $references_style;
        }

        if ($software_style != $settings['software_style']) {
            $settings['software_style'] = $software_style;
        }

        if ($sticky_header != $settings['sticky_header']) {
            $settings['sticky_header'] = $sticky_header;
        }

        if ($cache_pages != $settings['cache_pages']) {
            $settings['cache_pages'] = $cache_pages;
        }

        if ($show_preloader != $settings['show_preloader']) {
            $settings['show_preloader'] = $show_preloader;
        }

        if ($preloader != $settings['site_preloader']) {
            $settings['site_preloader'] = $preloader;
        }

        if ($preloader_bg != $settings['site_preloader_bg']) {
            $settings['site_preloader_bg'] = $preloader_bg;
        }

        if ($show_totop != $settings['show_totop']) {
            $settings['show_totop'] = $show_totop;
        }

        if ($show_contact_info != $settings['show_contact_info']) {
            $settings['show_contact_info'] = $show_contact_info;
        }

        if ($external_login != $settings['external_login']) {
            $settings['external_login'] = $external_login;
        }

        if ($use_cdn != $settings['use_cdn']) {
            $settings['use_cdn'] = $use_cdn;
        }

        if ($package_style != $settings['package_style']) {
            $settings['package_style'] = $package_style;
        }

        if ($enable_lazy_loading != $settings['enable_lazy_loading']) {
            $settings['enable_lazy_loading'] = $enable_lazy_loading;
        }

        if ($top_notify_show != $settings['top_notify_show']) {
            $settings['top_notify_show'] = $top_notify_show;
        }

        if ($top_notify_show_link != $settings['top_notify_show_link']) {
            $settings['top_notify_show_link'] = $top_notify_show_link;
        }

        if ($top_notify_show_countdown != $settings['top_notify_show_countdown']) {
            $settings['top_notify_show_countdown'] = $top_notify_show_countdown;
        }

        if ($top_notify_countdown_date != $settings['top_notify_countdown_date']) {
            $settings['top_notify_countdown_date'] = $top_notify_countdown_date;
        }

        if ($top_notify_countdown_time != $settings['top_notify_countdown_time']) {
            $settings['top_notify_countdown_time'] = $top_notify_countdown_time;
        }

        if ($top_notify_show_close != $settings['top_notify_show_close']) {
            $settings['top_notify_show_close'] = $top_notify_show_close;
        }

        if ($popup_notify_show != $settings['popup_notify_show']) {
            $settings['popup_notify_show'] = $popup_notify_show;
        }

        if ($popup_notify_show_link != $settings['popup_notify_show_link']) {
            $settings['popup_notify_show_link'] = $popup_notify_show_link;
        }

        if ($popup_notify_show_countdown != $settings['popup_notify_show_countdown']) {
            $settings['popup_notify_show_countdown'] = $popup_notify_show_countdown;
        }

        if ($popup_notify_countdown_date != $settings['popup_notify_countdown_date']) {
            $settings['popup_notify_countdown_date'] = $popup_notify_countdown_date;
        }

        if ($popup_notify_countdown_time != $settings['popup_notify_countdown_time']) {
            $settings['popup_notify_countdown_time'] = $popup_notify_countdown_time;
        }

        if ($popup_notify_display != $settings['popup_notify_display']) {
            $settings['popup_notify_display'] = $popup_notify_display;
        }

        if ($popup_notify_display_when != $settings['popup_notify_display_when']) {
            $settings['popup_notify_display_when'] = $popup_notify_display_when;
        }

        if ($right_click != $settings['right_click']) {
            $settings['right_click'] = $right_click;
        }

        if ($header_style != $settings['header_style']) {
            $settings['header_style'] = $header_style;
        }

        if ($header_style_align != $settings['header_style_align']) {
            $settings['header_style_align'] = $header_style_align;
        }

        if ($show_whatsapp != $settings['show_whatsapp']) {
            $settings['show_whatsapp'] = $show_whatsapp;
        }

        if ($whatsapp_number != $settings['whatsapp_number']) {
            $settings['whatsapp_number'] = $whatsapp_number;
        }

        if ($show_phone != $settings['show_phone']) {
            $settings['show_phone'] = $show_phone;
        }

        if ($seo_gsd_show != $settings['seo_gsd_show']) {
            $settings['seo_gsd_show'] = $seo_gsd_show;
        }

        if ($seo_organisation_country != $settings['seo_organisation_country']) {
            $settings['seo_organisation_country'] = $seo_organisation_country;
        }

        if ($seo_organisation_city != $settings['seo_organisation_city']) {
            $settings['seo_organisation_city'] = $seo_organisation_city;
        }

        if ($seo_organisation_region != $settings['seo_organisation_region']) {
            $settings['seo_organisation_region'] = $seo_organisation_region;
        }

        if ($seo_organisation_address != $settings['seo_organisation_address']) {
            $settings['seo_organisation_address'] = $seo_organisation_address;
        }

        if ($seo_organisation_postal_code != $settings['seo_organisation_postal_code']) {
            $settings['seo_organisation_postal_code'] = $seo_organisation_postal_code;
        }

        if ($seo_organisation_price_min != $settings['seo_organisation_price_min']) {
            $settings['seo_organisation_price_min'] = $seo_organisation_price_min;
        }

        if ($seo_organisation_price_max != $settings['seo_organisation_price_max']) {
            $settings['seo_organisation_price_max'] = $seo_organisation_price_max;
        }

        if ($seo_organisation_price_currency != $settings['seo_organisation_price_currency']) {
            $settings['seo_organisation_price_currency'] = $seo_organisation_price_currency;
        }

        if ($seo_organisation_rating_value != $settings['seo_organisation_rating_value']) {
            $settings['seo_organisation_rating_value'] = $seo_organisation_rating_value;
        }

        if ($seo_organisation_rating_count != $settings['seo_organisation_rating_count']) {
            $settings['seo_organisation_rating_count'] = $seo_organisation_rating_count;
        }

        if ($order_steps_monthly_price != $settings['order_steps_monthly_price']) {
            $settings['order_steps_monthly_price'] = $order_steps_monthly_price;
        }

        if ($google_analytics_id != $settings['google_analytics_id']) {
            $settings['google_analytics_id'] = $google_analytics_id;
        }

        if ($google_ads_id != $settings['google_ads_id']) {
            $settings['google_ads_id'] = $google_ads_id;
        }

        if ($google_conversion_id != $settings['google_conversion_id']) {
            $settings['google_conversion_id'] = $google_conversion_id;
        }

        if ($facebook_pixel_id != $settings['facebook_pixel_id']) {
            $settings['facebook_pixel_id'] = $facebook_pixel_id;
        }

        if ($google_tm_id != $settings['google_tm_id']) {
            $settings['google_tm_id'] = $google_tm_id;
        }

        if ($fb_pixel_via_gtm != $settings['fb_pixel_via_gtm']) {
            $settings['fb_pixel_via_gtm'] = $fb_pixel_via_gtm;
        }

        foreach ($languages as $language) {
            if ($top_notify_text[$language['key']] != $settings['top_notify_text'][$language['key']]) {
                $settings['top_notify_text'][$language['key']] = $top_notify_text[$language['key']];
            }

            if ($top_notify_link[$language['key']] != $settings['top_notify_link'][$language['key']]) {
                $settings['top_notify_link'][$language['key']] = $top_notify_link[$language['key']];
            }

            if ($top_notify_link_text[$language['key']] != $settings['top_notify_link_text'][$language['key']]) {
                $settings['top_notify_link_text'][$language['key']] = $top_notify_link_text[$language['key']];
            }

            if ($popup_notify_image[$language['key']] != $settings['popup_notify_image'][$language['key']]) {
                $settings['popup_notify_image'][$language['key']] = $popup_notify_image[$language['key']];
            }

            if ($popup_notify_link[$language['key']] != $settings['popup_notify_link'][$language['key']]) {
                $settings['popup_notify_link'][$language['key']] = $popup_notify_link[$language['key']];
            }

            if ($popup_notify_link_text[$language['key']] != $settings['popup_notify_link_text'][$language['key']]) {
                $settings['popup_notify_link_text'][$language['key']] = $popup_notify_link_text[$language['key']];
            }

            if ($seo_site_name[$language['key']] != $settings['seo_site_name'][$language['key']]) {
                $settings['seo_site_name'][$language['key']] = $seo_site_name[$language['key']];
            }

            if ($seo_organisation_name[$language['key']] != $settings['seo_organisation_name'][$language['key']]) {
                $settings['seo_organisation_name'][$language['key']] = $seo_organisation_name[$language['key']];
            }

            if ($footer_copyright_text[$language['key']] != $settings['footer_copyright_text'][$language['key']]) {
                $settings['footer_copyright_text'][$language['key']] = $footer_copyright_text[$language['key']];
            }
        }

        if (!isset($settings['fonts'])) {
            $settings['fonts'] = [];
        }

        foreach ($fonts as $key => $value) {
            if (!isset($settings['fonts'][$key])) {
                $settings['fonts'][$key] = $value;
            }
            else if (!is_array($value)) {
                if ($value != $settings['fonts'][$key]) {
                    $settings['fonts'][$key] = $value;
                }
            }
            else {
                foreach ($value as $subKey => $subValue) {
                    if (!isset($settings['fonts'][$key][$subKey]) || $subValue !== $settings['fonts'][$key][$subKey]) {
                        $settings['fonts'][$key][$subKey] = $subValue;
                    }
                }
            }
        }

        $options = [];
        if ($image_sizes && is_array($image_sizes)) {
            foreach ($image_sizes as $page => $image_size) {
                if ($page == 'page-news') {
                    $pageSettings = Config::get('pictures/page-news');
                }
                else if ($page == 'page-articles') {
                    $pageSettings = Config::get('pictures/page-articles');
                }
                else if ($page == 'page-references') {
                    $pageSettings = Config::get('pictures/page-references');
                    $pageSettings['mockup']['sizing']['width'] = $image_size['sizing'];
                    $pageSettings['mockup']['sizing']['height'] = false;
                    $pageSettings['mockup']['thumb']['width'] = $image_size['thumb'];
                    $pageSettings['mockup']['thumb']['height'] = false;
                }
                else if ($page == 'software') {
                    $pageSettings = Config::get('pictures/software');
                    $pageSettings['mockup']['sizing']['width'] = $image_size['sizing'];
                    $pageSettings['mockup']['sizing']['height'] = false;
                }

                $pageSettings['list']['sizing']['width'] = ($page == 'software' ? $image_size['thumb'] : $image_size['sizing']);
                $pageSettings['list']['sizing']['height'] = false;

                if ($page != 'software') {
                    $pageSettings['list']['thumb']['width'] = $image_size['thumb'];
                    $pageSettings['list']['thumb']['height'] = false;
                }

                $options[$page] = $pageSettings;
            }
        }

        $export = Utility::array_export(Config::set('pictures', $options), ['pwith' => true]);
        FileManager::file_write(CONFIG_DIR . 'pictures.php', $export);
        return $settings;
    }

    private function _fonFastCache(string $key, mixed $data = NULL, int $finalMtime = 0, string $filePrefix = ''): mixed
    {
        $baseDir = (defined('CACHE_DIR') ? CACHE_DIR : (defined('ROOT_DIR') ? ROOT_DIR . 'cache/' : $_SERVER['DOCUMENT_ROOT'] . '/cache/'));
        $dir = $baseDir . 'fonbuilder/';

        if (!is_dir($dir)) {
            @mkdir($dir, 493, true);
            @file_put_contents($dir . 'index.php', '<?php // Silence is golden');
        }

        $prefixPart = ($filePrefix ? $filePrefix . '_' : '');
        $file = $dir . $prefixPart . md5($key) . '.json';

        if ($data !== null) {
            if (isset($data['html']) && !empty($data['html'])) {
                $data['html'] = $this->sanitizeOutputUrls($data['html']);
            }

            $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            return @file_put_contents($file, $json, LOCK_EX) !== false;
        }
        else {
            if (!file_exists($file)) {
                return false;
            }
            if ((0 < $finalMtime) && filemtime($file) < $finalMtime) {
                return false;
            }

            $content = @file_get_contents($file);

            if (!$content) {
                return false;
            }

            $decoded = json_decode($content, true);
            return (is_null($decoded) ? false : $decoded);
        }
    }

    private function _injectFreshData(string $html): string
    {
        $currentTime = Crypt::encode(time(), Config::get('crypt/system'));
        $html = preg_replace('/(<input[^>]+name="form_loaded_at"[^>]+value=["\'])([^"\']*)(["\'])/i', '${1}' . $currentTime . '${3}', $html);
        $html = preg_replace('/(<input[^>]+name="g-recaptcha-response"[^>]+value=["\'])([^"\']*)(["\'])/i', '${1}${3}', $html);

        if (preg_match('/name="(formbuilder_[a-f0-9]{32})"/i', $html, $matches)) {
            $honeypotName = $matches[1];

            if (class_exists('Session')) {
                Session::set('formbuilder_honeypot_name', $honeypotName, true);
            }
        }

        if (preg_match('/name="(formbuilder_[a-f0-9]{32})"/i', $html, $matches)) {
            $honeypotName = $matches[1];

            if (class_exists('Session')) {
                Session::set('formbuilder_honeypot_name', $honeypotName, true);
            }
        }

        if (class_exists('Validation')) {
            $targetForms = [
                'domain-check'     => ['selector' => 'id=["\']checkForm["\']'],
                'cfeedback'        => ['selector' => 'class=["\'][^"\']*cFeedBackForm[^"\']*["\']'],
                'formbuilder_form' => ['selector' => 'class=["\'][^"\']*fon-formbuilder-form[^"\']*["\']']
            ];

            foreach ($targetForms as $tokenKey => $rule) {
                $freshTokenTag = Validation::get_csrf_token($tokenKey);
                $freshTokenValue = '';

                if (preg_match('/value=["\'](.*?)["\']/', $freshTokenTag, $matches)) {
                    $freshTokenValue = $matches[1];
                }

                if ($freshTokenValue) {
                    $pattern = '/(' . $rule['selector'] . '.*?<input[^>]+name=["\'](?:token|csrf_token|_token)["\'][^>]+value=["\'])([^"\']*)(["\'])/is';
                    $html = preg_replace_callback($pattern, function($m) use($freshTokenValue) {
                        return $m[1] . $freshTokenValue . $m[3];
                    }, $html);
                }
            }
        }

        return $html;
    }

    private function _clearFonBuilderCache(): void
    {
        $baseDir = (defined('CACHE_DIR') ? CACHE_DIR : (defined('ROOT_DIR') ? ROOT_DIR . 'cache/' : $_SERVER['DOCUMENT_ROOT'] . '/cache/'));
        $dir = $baseDir . 'fonbuilder/';

        if (is_dir($dir)) {
            $files = glob($dir . '*.json');

            foreach ($files as $file) {
                if (is_file($file)) {
                    @unlink($file);
                }
            }
        }
    }

    private function sanitizeOutputUrls(string $html_content): string
    {
        $currentHost = $_SERVER['HTTP_HOST'] ?? '';

        if (empty($currentHost)) {
            return $html_content;
        }

        $nakedHost = preg_replace('/^www\\./i', '', $currentHost);
        $domains_to_remove = ['https://' . $nakedHost, 'https://www.' . $nakedHost, 'http://' . $nakedHost, 'http://www.' . $nakedHost];

        if (defined('APP_URI')) {
            $domains_to_remove[] = rtrim(APP_URI, '/');
        }

        $domains_to_remove = array_unique($domains_to_remove);
        $clean_html = str_replace($domains_to_remove, '', $html_content);
        return $clean_html;
    }

    public function builderRow(array $pageContent = [], array $pageData = []): string
    {
        $currentCurrency = $pageData['selected_currency'] ?? Config::get('general/currency');
        $currentLang = Language::selected();
        $cacheEnabled = Config::get('theme/cache_pages');
        $pageID = (isset($pageData['builder_id']) ? $pageData['builder_id'] : md5(json_encode($pageContent)));
        $cacheKey = $pageData['page'] . '_' . $pageID . '_' . $currentLang . '_' . $currentCurrency;
        $dbMtime = 0;

        if (isset($pageData['builder_mtime'])) {
            $dbMtime = (is_numeric($pageData['builder_mtime']) ? $pageData['builder_mtime'] : strtotime($pageData['builder_mtime']));
        }

        $currencyMtime = Config::get('cronjobs/tasks/auto-currency-rates/last-run-time');
        $currencyMtime = strtotime($currencyMtime);
        $finalMtime = max($dbMtime, $currencyMtime);
        $filePrefix = 'page_' . $pageID;
        $cachedData = $this->_fonFastCache($cacheKey, NULL, $finalMtime, $filePrefix);
        if ($cachedData !== false && $cacheEnabled) {
            if (isset($cachedData['headerCodes']) && !empty($cachedData['headerCodes'])) {
                foreach ($cachedData['headerCodes'] as $pPage => $pCode) {
                    $this->headerCodes = array_merge($this->headerCodes, $cachedData['headerCodes']);
                }
            }
            if (isset($cachedData['styles']) && !empty($cachedData['styles'])) {
                $this->styles = array_merge($this->styles, $cachedData['styles']);
            }
            if (isset($cachedData['scripts']) && !empty($cachedData['scripts'])) {
                $this->scripts = array_merge($this->scripts, $cachedData['scripts']);
            }
            if (isset($cachedData['assets']) && !empty($cachedData['assets'])) {
                $this->assets = array_unique(array_merge($this->assets, $cachedData['assets']));
            }

            $finalHtml = $cachedData['html'];
            $finalHtml = $this->_injectFreshData($finalHtml);
            return $finalHtml;
        }

        $output = '';
        self::$lcpHandled = false;

        if ($pageContent) {
            foreach ($pageContent as $row_key => $row) {
                if (isset($row->row_hide) && $row->row_hide == '1') {
                    continue;
                }
                $rowBg = (isset($row->background_type) && $row->background_type == 2 && isset($row->bg_image) ? $row->bg_image : '');
                $rowBgPattern = '';
                $rowPatternStyle = '';
                $colPatternStyle = [];
                $rowClasses = ($row->row_section ? $row->row_section_class . ' ' . $row->text_class_id : $row->text_class);
                $rowPatternStyle = $this->handlePatternImages($rowClasses, $pageData['page'], $pageData['tadress'], self::$lcpHandled === false);

                if (self::$lcpHandled === false) {
                    if (!empty($rowBg)) {
                        $this->addPreloadLink($rowBg, $pageData['page']);
                    }
                }

                if ($rowBg) {
                    $rowBgPattern = 'background-image: url(' . self::assetLinkDetermine($rowBg) . ');';
                }
                if (isset($row->cols) && is_array($row->cols)) {
                    foreach ($row->cols as $col_key => $col) {
                        $colClasses = $col->text_class;
                        $colPatternStyle[$col->text_class_id] = $this->handlePatternImages($colClasses, $pageData['page'], $pageData['tadress'], self::$lcpHandled === false);

                        if (self::$lcpHandled === false) {
                            $colBg = (isset($col->background_type) && $col->background_type == 2 && isset($col->bg_image) ? $col->bg_image : '');

                            if (!empty($colBg)) {
                                $this->addPreloadLink($colBg, $pageData['page']);
                            }
                        }
                    }
                }
                $output .= '<section id="' . ($row->row_section && $row->row_section_id ? $row->row_section_id : $row->text_class_id) . '" class="fon-main-section clearfix ' . ($row->row_section ? $row->row_section_class . ' ' . $row->text_class_id : $row->text_class) . ' ' . ((($row->background_type == 2) || $row->background_type == 3) && $row->overlay_type != '' ? 'overflow-hidden' : '') . ' ' . (($row->background_type == 3) && $row->video_type == 'youtube' ? 'fon-external-video-bg' : '') . '" style="' . $rowPatternStyle . ' ' . $rowBgPattern . '">';

                if ($row->background_type == 3) {
                    if ($row->video_type == 'youtube') {
                        $output .= '<div class="fon-background-youtube d-none">' . "\n" . '                            <iframe class="fon-bg-youtube" src="//www.youtube-nocookie.com/embed/' . $row->video_youtube . '?playlist=' . $row->video_youtube . '&iv_load_policy=3&enablejsapi=1&disablekb=1&autoplay=1&controls=0&showinfo=0&rel=0&loop=1&wmode=transparent&widgetid=1&mute=1" frameborder="0" allowfullscreen></iframe>' . "\n" . '                         </div>';
                    }
                    else {
                        $output .= '<div class="fon-background-video">' . "\n" . '                            <video class="fon-bg-video" autoplay muted playsinline loop ' . ($row->video_poster ? 'poster="' . static::assetLinkDetermine($row->video_poster) . '"' : '') . '>' . "\n" . '                                <source src="' . static::assetLinkDetermine($row->video_local) . '" type="video/mp4">' . "\n" . '                            </video>' . "\n" . '                         </div>';
                    }
                }
                if (($row->background_type == 2) || $row->background_type == 3) {
                    if ($row->overlay_type != '') {
                        $output .= '<div class="fon-background-overlay"></div>';
                    }
                }

                $output .= '<div class="' . ($row->row_container_fluid == 1 ? 'container-fluid' : 'container') . ' ' . ($row->row_remove_gutter ? ' g-0' : '') . '">';
                $rowSectionTitle = (isset($row->row_section_title->{$this->lang}) && $row->row_section_title->{$this->lang} ? $row->row_section_title->{$this->lang} : array_values((array) $row->row_section_title)[0] ?? '');
                $rowSectionDesc = (isset($row->row_section_desc->{$this->lang}) && $row->row_section_desc->{$this->lang} ? $row->row_section_desc->{$this->lang} : array_values((array) $row->row_section_desc)[0] ?? '');
                if (isset($row->row_section_title_show) && $row->row_section_title_show && $rowSectionTitle || $rowSectionDesc) {
                    $output .= '<div class="fon-section-title">';

                    if ($rowSectionTitle) {
                        $output .= '<h2 class="fon-section-title-heading">' . self::getPriceHolders($rowSectionTitle) . '</h2>';
                    }

                    if ($rowSectionDesc) {
                        $output .= '<p class="fon-section-title-subheading">' . strip_tags(self::getPriceHolders($rowSectionDesc)) . '</p>';
                    }

                    $output .= '</div>';
                }

                $row_animation = '';

                if ($row->row_animation_effect) {
                    $row_animation .= 'data-aos="' . $row->row_animation_effect . '" ';

                    if ($row->row_animation_offset) {
                        $row_animation .= 'data-aos-offset="' . $row->row_animation_offset . '" ';
                    }

                    if ($row->row_animation_delay) {
                        $row_animation .= 'data-aos-delay="' . $row->row_animation_delay . '" ';
                    }

                    if ($row->row_animation_duration) {
                        $row_animation .= 'data-aos-duration="' . $row->row_animation_duration . '" ';
                    }

                    if ($row->row_animation_transition) {
                        $row_animation .= 'data-aos-easing="' . $row->row_animation_transition . '" ';
                    }

                    if ($row->row_animation_position) {
                        $row_animation .= 'data-aos-anchor-placement="' . $row->row_animation_position . '" ';
                    }
                }
                $output .= '<div class="row ' . $row->text_class . ($row->row_remove_gutter ? ' g-0' : '') . ' ' . (isset($row->row_column_align) && $row->row_column_align ? 'align-items-' . $row->row_column_align : '') . '" ' . $row_animation . '>';

                foreach ($row->cols as $col_key => $col) {
                    $col_animation = '';

                    if ($col->col_animation_effect) {
                        $col_animation .= 'data-aos="' . $col->col_animation_effect . '" ';

                        if ($col->col_animation_offset) {
                            $col_animation .= 'data-aos-offset="' . $col->col_animation_offset . '" ';
                        }

                        if ($col->col_animation_delay) {
                            $col_animation .= 'data-aos-delay="' . $col->col_animation_delay . '" ';
                        }

                        if ($col->col_animation_duration) {
                            $col_animation .= 'data-aos-duration="' . $col->col_animation_duration . '" ';
                        }

                        if ($col->col_animation_transition) {
                            $col_animation .= 'data-aos-easing="' . $col->col_animation_transition . '" ';
                        }

                        if ($col->col_animation_position) {
                            $col_animation .= 'data-aos-anchor-placement="' . $col->col_animation_position . '" ';
                        }
                    }

                    $columnDisplayClasses = self::generateColumnDisplayClassess($col);
                    $thisColStyle = (isset($colPatternStyle[$col->text_class_id]) ? $colPatternStyle[$col->text_class_id] : '');
                    $output .= '<div id="' . $col->text_class_id . '" class="col-' . $col->xs_col . ' col-sm-' . $col->sm_col . ' col-md-' . $col->md_col . ' col-lg-' . $col->lg_col . ' col-xl-' . $col->xl_col . ' ' . ($col->text_class != '' ? $col->text_class : '') . ' ' . (($col->background_type == 2) || $col->background_type == 3 ? 'position-relative' : '') . ' ' . (($col->background_type == 3) && $col->video_type == 'youtube' ? 'fon-external-video-bg' : '') . ' ' . $columnDisplayClasses . '" ' . $col_animation . ' style="' . $thisColStyle . '">';

                    if ($col->background_type == 3) {
                        if ($col->video_type == 'youtube') {
                            $output .= '<div class="fon-background-youtube d-none">' . "\n" . '                                <iframe class="fon-bg-youtube" src="//www.youtube-nocookie.com/embed/' . $col->video_youtube . '?playlist=' . $col->video_youtube . '&iv_load_policy=3&enablejsapi=1&disablekb=1&autoplay=1&controls=0&showinfo=0&rel=0&loop=1&wmode=transparent&widgetid=1&mute=1" frameborder="0" allowfullscreen></iframe>' . "\n" . '                             </div>';
                        }
                        else {
                            $output .= '<div class="fon-background-video">' . "\n" . '                                <video class="fon-bg-video" autoplay muted playsinline loop ' . ($col->video_poster ? 'poster="' . static::assetLinkDetermine($col->video_poster) . '"' : '') . '>' . "\n" . '                                    <source src="' . static::assetLinkDetermine($col->video_local) . '" type="video/mp4">' . "\n" . '                                </video>' . "\n" . '                             </div>';
                        }
                    }
                    if (($col->background_type == 2) || $col->background_type == 3) {
                        if ($col->overlay_type != '') {
                            $output .= '<div class="fon-background-overlay"></div>';
                        }
                    }
                    $colSectionTitle = (isset($col->col_section_title->{$this->lang}) && $col->col_section_title->{$this->lang} ? $col->col_section_title->{$this->lang} : array_values((array) $col->col_section_title)[0] ?? '');
                    $colSectionDesc = (isset($col->col_section_desc->{$this->lang}) && $col->col_section_desc->{$this->lang} ? $col->col_section_desc->{$this->lang} : array_values((array) $col->col_section_desc)[0] ?? '');
                    if (isset($col->col_section_title_show) && $col->col_section_title_show && $colSectionTitle || $colSectionDesc) {
                        $output .= '<div class="fon-column-title">';

                        if ($colSectionTitle) {
                            $output .= '<h3 class="fon-column-title-heading">' . $colSectionTitle . '</h3>';
                        }

                        if ($colSectionDesc) {
                            $output .= '<p class="fon-column-title-subheading">' . strip_tags($colSectionDesc) . '</p>';
                        }

                        $output .= '</div>';
                    }

                    if ($col->widgets) {
                        foreach ($col->widgets as $widget) {
                            if ($widget->content) {
                                $isWidgetLCP = self::$lcpHandled === false;
                                $output .= $this->callWidget($pageData, $widget, $row, $isWidgetLCP);
                            }
                        }
                    }
                    if (isset($col->rows) && $col->rows) {
                        $row_childs = $col->rows;
                        $output .= $this->builderChildRow($row_childs, $pageData);
                    }

                    $output .= '</div>';
                }

                $output .= '</div>';
                $output .= '</div>';
                $output .= '</section>';
                self::$lcpHandled = true;
            }
        }
        if (!empty($output) && $cacheEnabled) {
            $dataToStore = ['html' => $output, 'headerCodes' => $this->headerCodes, 'styles' => $this->styles, 'assets' => $this->assets, 'scripts' => $this->scripts];
            $this->_fonFastCache($cacheKey, $dataToStore, $finalMtime, $filePrefix);
        }
        else if (!empty($output)) {
            $output = $this->sanitizeOutputUrls($output);
        }

        return $output;
    }

    public function builderChildRow(mixed $row_childs, array $pageData = []): string
    {
        $output = '';

        if ($row_childs) {
            foreach ($row_childs as $rc_row_key => $row_child) {
                if (isset($row_child->row_hide) && $row_child->row_hide == '1') {
                    continue;
                }

                $row_child_animation = '';

                if ($row_child->row_animation_effect) {
                    $row_child_animation .= 'data-aos="' . $row_child->row_animation_effect . '" ';

                    if ($row_child->row_animation_offset) {
                        $row_child_animation .= 'data-aos-offset="' . $row_child->row_animation_offset . '" ';
                    }

                    if ($row_child->row_animation_delay) {
                        $row_child_animation .= 'data-aos-delay="' . $row_child->row_animation_delay . '" ';
                    }

                    if ($row_child->row_animation_duration) {
                        $row_child_animation .= 'data-aos-duration="' . $row_child->row_animation_duration . '" ';
                    }

                    if ($row_child->row_animation_transition) {
                        $row_child_animation .= 'data-aos-easing="' . $row_child->row_animation_transition . '" ';
                    }

                    if ($row_child->row_animation_position) {
                        $row_child_animation .= 'data-aos-anchor-placement="' . $row_child->row_animation_position . '" ';
                    }
                }
                $output .= '<div id="' . $row_child->text_class_id . '" class="row ' . ($row_child->row_remove_gutter ? 'g-0' : '') . ' ' . ($row_child->text_class ?? $row_child->text_class) . ' ' . (($row_child->background_type == 2) || $row_child->background_type == 3 ? 'position-relative' : '') . ' ' . (($row_child->background_type == 3) && $row_child->video_type == 'youtube' ? 'fon-external-video-bg' : '') . ' ' . (isset($row_child->row_column_align) && $row_child->row_column_align ? 'align-items-' . $row_child->row_column_align : '') . '" ' . $row_child_animation . '>';

                if ($row_child->background_type == 3) {
                    if ($row_child->video_type == 'youtube') {
                        $output .= '<div class="fon-background-youtube d-none">' . "\n" . '                            <iframe class="fon-bg-youtube" src="//www.youtube-nocookie.com/embed/' . $row_child->video_youtube . '?playlist=' . $row_child->video_youtube . '&iv_load_policy=3&enablejsapi=1&disablekb=1&autoplay=1&controls=0&showinfo=0&rel=0&loop=1&wmode=transparent&widgetid=1&mute=1" frameborder="0" allowfullscreen></iframe>' . "\n" . '                         </div>';
                    }
                    else {
                        $output .= '<div class="fon-background-video">' . "\n" . '                            <video class="fon-bg-video" autoplay muted playsinline loop ' . ($row_child->video_poster ? 'poster="' . static::assetLinkDetermine($row_child->video_poster) . '"' : '') . '>' . "\n" . '                                <source src="' . static::assetLinkDetermine($row_child->video_local) . '" type="video/mp4">' . "\n" . '                            </video>' . "\n" . '                         </div>';
                    }
                }
                if (($row_child->background_type == 2) || $row_child->background_type == 3) {
                    if ($row_child->overlay_type != '') {
                        $output .= '<div class="fon-background-overlay"></div>';
                    }
                }

                foreach ($row_child->cols as $rc_col_key => $col_child) {
                    $col_child_animation = '';

                    if ($col_child->col_animation_effect) {
                        $col_child_animation .= 'data-aos="' . $col_child->col_animation_effect . '" ';

                        if ($col_child->col_animation_offset) {
                            $col_child_animation .= 'data-aos-offset="' . $col_child->col_animation_offset . '" ';
                        }

                        if ($col_child->col_animation_delay) {
                            $col_child_animation .= 'data-aos-delay="' . $col_child->col_animation_delay . '" ';
                        }

                        if ($col_child->col_animation_duration) {
                            $col_child_animation .= 'data-aos-duration="' . $col_child->col_animation_duration . '" ';
                        }

                        if ($col_child->col_animation_transition) {
                            $col_child_animation .= 'data-aos-easing="' . $col_child->col_animation_transition . '" ';
                        }

                        if ($col_child->col_animation_position) {
                            $col_child_animation .= 'data-aos-anchor-placement="' . $col_child->col_animation_position . '" ';
                        }
                    }

                    $colChildDisplayClasses = self::generateColumnDisplayClassess($col_child);
                    $output .= '<div id="' . $col_child->text_class_id . '" class="col-' . $col_child->xs_col . ' col-sm-' . $col_child->sm_col . ' col-md-' . $col_child->md_col . ' col-lg-' . $col_child->lg_col . ' col-xl-' . $col_child->xl_col . ' ' . ($col_child->text_class != '' ? $col_child->text_class : '') . ' ' . (($col_child->background_type == 2) || $col_child->background_type == 3 ? 'position-relative' : '') . ' ' . (($col_child->background_type == 3) && $col_child->video_type == 'youtube' ? 'fon-external-video-bg' : '') . ' ' . $colChildDisplayClasses . '" ' . $col_child_animation . '>';

                    if ($col_child->background_type == 3) {
                        if ($col_child->video_type == 'youtube') {
                            $output .= '<div class="fon-background-youtube d-none">' . "\n" . '                                <iframe class="fon-bg-youtube" src="//www.youtube-nocookie.com/embed/' . $col_child->video_youtube . '?playlist=' . $col_child->video_youtube . '&iv_load_policy=3&enablejsapi=1&disablekb=1&autoplay=1&controls=0&showinfo=0&rel=0&loop=1&wmode=transparent&widgetid=1&mute=1" frameborder="0" allowfullscreen></iframe>' . "\n" . '                             </div>';
                        }
                        else {
                            $output .= '<div class="fon-background-video">' . "\n" . '                                <video class="fon-bg-video" autoplay muted playsinline loop ' . ($col_child->video_poster ? 'poster="' . static::assetLinkDetermine($col_child->video_poster) . '"' : '') . '>' . "\n" . '                                    <source src="' . static::assetLinkDetermine($col_child->video_local) . '" type="video/mp4">' . "\n" . '                                </video>' . "\n" . '                             </div>';
                        }
                    }
                    if (($col_child->background_type == 2) || $col_child->background_type == 3) {
                        if ($col_child->overlay_type != '') {
                            $output .= '<div class="fon-background-overlay"></div>';
                        }
                    }
                    $colChildSectionTitle = (isset($col_child->col_section_title->{$this->lang}) && $col_child->col_section_title->{$this->lang} ? $col_child->col_section_title->{$this->lang} : array_values((array) $col_child->col_section_title)[0] ?? '');
                    $colChildSectionDesc = (isset($col_child->col_section_desc->{$this->lang}) && $col_child->col_section_desc->{$this->lang} ? $col_child->col_section_desc->{$this->lang} : array_values((array) $col_child->col_section_desc)[0] ?? '');
                    if (isset($col_child->col_section_title_show) && $col_child->col_section_title_show && $colChildSectionTitle || $colChildSectionDesc) {
                        $output .= '<div class="fon-column-title">';

                        if ($colChildSectionTitle) {
                            $output .= '<h3 class="fon-column-title-heading">' . $colChildSectionTitle . '</h3>';
                        }

                        if ($colChildSectionDesc) {
                            $output .= '<p class="fon-column-title-subheading">' . strip_tags($colChildSectionDesc) . '</p>';
                        }

                        $output .= '</div>';
                    }

                    if ($col_child->widgets) {
                        foreach ($col_child->widgets as $child_widget) {
                            if ($child_widget->content) {
                                $output .= $this->callWidget($pageData, $child_widget, $row_child);
                            }
                        }
                    }
                    if (isset($col_child->rows) && $col_child->rows) {
                        $row_childs = $col_child->rows;
                        $output .= $this->builderChildRow($row_childs, $pageData);
                    }

                    $output .= '</div>';
                }

                $output .= '</div>';
            }
        }

        return $output;
    }

    public function callWidget(array $pageData, object $widget, object $row, bool $isLCPCandidate = false): string
    {
        $content = $widget->content;
        $funcWidget = $widget->widget . '_widget';

        if (method_exists($this, $funcWidget)) {
            return $this->{$funcWidget}($content, $widget->module, $pageData, $row, $isLCPCandidate);
        }

        return $this->callCustomWidgetRenderer($widget, $content, $pageData);
    }

    private function callCustomWidgetRenderer(object $widget, mixed $content, array $pageData): string
    {
        $moduleId = (string) ($widget->module ?? '');
        $page = (is_array($pageData) && isset($pageData['page']) && is_string($pageData['page']) ? trim($pageData['page']) : '');
        if (!isset($widget->widget) || !is_string($widget->widget) || $widget->widget === '') {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => '', 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'widget_name_empty'], '');
            return '';
        }

        $safeWidget = $this->sanitizeCustomWidgetName($widget->widget);

        if ($safeWidget === '') {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $widget->widget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'widget_name_invalid'], '');
            return '';
        }

        $rendererFile = $this->resolveCustomWidgetRendererFile($safeWidget);

        if ($rendererFile === '') {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_file_not_found'], '');
            return '';
        }

        if (!$this->isCustomWidgetRendererSafe($rendererFile)) {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_security_check_failed'], '');
            return '';
        }

        require_once $rendererFile;
        $rendererClass = 'FonCustomWidgetRenderer_' . $safeWidget;

        if (!class_exists($rendererClass)) {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_class_not_found'], '');
            return '';
        }

        try {
            $renderMethod = new ReflectionMethod($rendererClass, 'render');
            if (!$renderMethod->isPublic() || !$renderMethod->isStatic()) {
                Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_method_invalid'], '');
                return '';
            }
        }
        catch (ReflectionException $e) {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_reflection_exception'], ['error_message' => $e->getMessage(), 'error_type' => get_class($e)]);
            return '';
        }

        try {
            $html = (string) $rendererClass::render($this, $content, $moduleId, (is_array($pageData) ? $pageData : []));
            return $html;
        }
        catch (Throwable $e) {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_exception'], ['renderer_class' => $rendererClass, 'error_message' => $e->getMessage(), 'error_code' => $e->getCode(), 'error_type' => get_class($e), 'error_file' => $e->getFile(), 'error_line' => $e->getLine()]);
            return '';
        }
    }

    private function resolveCustomWidgetRendererFile(string $safeWidget): string
    {
        $basePath = realpath(__DIR__ . DS . 'builder' . DS . 'custom-widgets');

        if ($basePath === false) {
            return '';
        }

        $rendererPath = $basePath . DS . $safeWidget . DS . 'renderer.php';

        if (!is_file($rendererPath)) {
            return '';
        }

        $rendererRealPath = realpath($rendererPath);

        if ($rendererRealPath === false) {
            return '';
        }

        return ($this->isPathInsideDirectory($basePath, $rendererRealPath) ? $rendererRealPath : '');
    }

    private function isPathInsideDirectory(string $baseDir, string $path): bool
    {
        $normalizedBase = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $baseDir), DIRECTORY_SEPARATOR);
        $normalizedPath = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR);
        if (($normalizedBase === '') || $normalizedPath === '') {
            return false;
        }

        if ($normalizedPath === $normalizedBase) {
            return true;
        }

        return strpos($normalizedPath, $normalizedBase . DIRECTORY_SEPARATOR) === 0;
    }

    private function isCustomWidgetRendererSafe(string $rendererFile): bool
    {
        static $securityCheckCache = [];

        if (isset($securityCheckCache[$rendererFile])) {
            return $securityCheckCache[$rendererFile];
        }

        $code = @file_get_contents($rendererFile);

        if ($code === false) {
            $securityCheckCache[$rendererFile] = false;
            return false;
        }

        $securityCheckCache[$rendererFile] = !$this->hasForbiddenRendererTokens($code);
        return $securityCheckCache[$rendererFile];
    }

    private function hasForbiddenRendererTokens(string $phpCode): bool
    {
        $tokens = token_get_all($phpCode);
        $forbiddenFunctions = ['eval', 'assert', 'shell_exec', 'exec', 'system', 'passthru', 'proc_open', 'popen'];
        $tokenCount = count($tokens);

        for ($i = 0; $i < $tokenCount; ++$i) {
            $token = $tokens[$i];

            if ($token === '`') {
                return true;
            }

            if (!is_array($token)) {
            }
            else {
                if ($token[0] === T_EVAL) {
                    return true;
                }
                if (($token[0] === T_STRING) && $this->isForbiddenFunctionCall($tokens, $i, $forbiddenFunctions)) {
                    return true;
                }
            }
        }

        return false;
    }

    private function isForbiddenFunctionCall(array $tokens, int $index, array $forbiddenFunctions): bool
    {
        if (!isset($tokens[$index]) || !is_array($tokens[$index])) {
            return false;
        }

        $tokenName = strtolower((string) $tokens[$index][1]);

        if (!in_array($tokenName, $forbiddenFunctions, true)) {
            return false;
        }

        $tokenCount = count($tokens);

        for ($i = $index + 1; $i < $tokenCount; ++$i) {
            $nextToken = $tokens[$i];
            if (is_array($nextToken) && in_array($nextToken[0], [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT], true)) {
            }
            else {
                return $nextToken === '(';
            }
        }

        return false;
    }

    private function sanitizeCustomWidgetName(mixed $widgetName): string
    {
        if (!is_string($widgetName)) {
            return '';
        }

        $name = strtolower(trim($widgetName));

        if ($name === '') {
            return '';
        }

        return (preg_match('/^[a-z][a-z0-9_]*$/', $name) ? $name : '');
    }

    private function accordion_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-accordion-widget ' . ($content->dark_container == 'yes' ? 'dark-container' : '') . ' style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        if (isset($content->items) && is_array($content->items)) {
            $output .= '<div class="accordion" id="accordion-' . $widgetId . '">';

            foreach ($content->items as $key => $item) {
                $output .= '<div class="accordion-item ' . (($content->show_icon == 'yes') && $item->accordion_icon ? 'with-icon' : 'no-icon') . '">';
                $output .= '<div class="accordion-header">';
                $output .= '<a class="accordion-button ' . (($key == 0) && $content->first_open == 'yes' ? '' : 'collapsed') . '" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-' . $widgetId . '-' . $key . '" aria-expanded="' . ($key == 0 ? 'true' : 'false') . '" aria-controls="collapse-' . $widgetId . '-' . $key . '">';
                if (($content->show_icon == 'yes') && $item->accordion_icon) {
                    $output .= '<span class="accordion-icon me-1"><i class="' . $item->accordion_icon . '"></i></span>';
                }

                $accordionTitle = self::getFieldMultilingualText($item->accordion_title ?? NULL, $this->lang, '');
                $output .= $accordionTitle;
                $output .= '</a>';
                $output .= '</div>';
                $output .= '<div id="collapse-' . $widgetId . '-' . $key . '" class="accordion-collapse collapse ' . (($key == 0) && $content->first_open == 'yes' ? 'show' : '') . '" data-bs-parent="#accordion-' . $widgetId . '">';
                $output .= '<div class="accordion-body">';
                $accordionContent = self::getFieldMultilingualText($item->accordion_content ?? NULL, $this->lang, '');
                $output .= $accordionContent;
                $output .= '</div>';
                $output .= '</div>';
                $output .= '</div>';
            }

            $output .= '</div>';
        }

        $output .= '</div>';
        return $output;
    }

    private function alert_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (($content->name_widget_status == 'yes') && isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang}) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';
            if ($content->title_color && $content->alert_type == 'light') {
                $style .= 'color: ' . $content->title_color . ';';
            }

            if ($content->title_margin->top) {
                $style .= 'margin-top: ' . $content->title_margin->top . 'px;';
            }

            if ($content->title_margin->bottom) {
                $style .= 'margin-bottom: ' . $content->title_margin->bottom . 'px;';
            }

            if ($content->title_font) {
                $style .= self::parseFontProperties($content->title_font);
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-alert-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<div class="alert alert-' . $content->alert_type . ' ' . ($content->show_close ? 'alert-dismissible fade show' : '') . ' ' . ($content->show_icon == 'yes' ? 'd-flex align-items-center' : '') . '" role="alert">';
        if (isset($content->show_icon) && $content->show_icon == 'yes') {
            $output .= '<div class="alert-icon me-3"><i class="' . $content->icon . ' fa-2x"></i></div>';
            $output .= '<div class="alert-content">';
        }
        if (isset($content->name_widget_status) && $content->name_widget_status == 'yes' && isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang}) {
            $output .= '<' . $content->heading_selector . ' class="fon-widget-title alert-heading">';
            $output .= $content->name_widget->{$this->lang};
            $output .= '</' . $content->heading_selector . '>';
        }
        if (isset($content->content->{$this->lang}) && $content->content->{$this->lang}) {
            $output .= $content->content->{$this->lang};
        }
        if (isset($content->show_close) && $content->show_close == 'yes') {
            $output .= '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="' . $this->language['text_close'] . '"></button>';
        }
        if (isset($content->show_icon) && $content->show_icon == 'yes') {
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function animated_heading_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $heading_type = (isset($content->heading_type) && $content->heading_type ? $content->heading_type : 'animation');
        $heading_layout = (isset($content->heading_layout) && $content->heading_layout ? $content->heading_layout : 'inline');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $heading_font = (isset($content->heading_font) && $content->heading_font ? $content->heading_font : '');
        $heading_color = (isset($content->heading_color) && $content->heading_color ? $content->heading_color : '#000000');
        $heading_margin = (isset($content->heading_margin) && $content->heading_margin ? $content->heading_margin : '');
        $heading_padding = (isset($content->heading_padding) && $content->heading_padding ? $content->heading_padding : '');
        $heading_align = (isset($content->heading_align) && $content->heading_align ? $content->heading_align : (object) ['xl' => 'left', 'lg' => 'left', 'md' => 'left', 'sm' => 'left', 'xs' => 'left']);
        $heading_align_class = $this->_parseResponsiveBootstrapFlexAligns($heading_align);
        $animated_text_color = (isset($content->animated_text_color) && $content->animated_text_color ? $content->animated_text_color : '#3366FF');
        $animated_text_font = (isset($content->animated_text_font) && $content->animated_text_font ? $content->animated_text_font : '');
        $animation_effect = (isset($content->animation_effect) && $content->animation_effect ? $content->animation_effect : 'blinds');
        $highlight_shape = (isset($content->highlight_shape) && $content->highlight_shape ? $content->highlight_shape : 'circle');
        $shape_color = (isset($content->shape_color) && $content->shape_color ? $content->shape_color : '#3366FF');
        $shape_width = (isset($content->shape_width) && $content->shape_width ? $content->shape_width : '');
        $shape_rounded_edge = (isset($content->shape_rounded_edge) && $content->shape_rounded_edge == 'yes' ? true : false);
        $animation_duration = (isset($content->animation_duration) && $content->animation_duration ? (string) $content->animation_duration : '10');
        $iteration_count = (isset($content->iteration_count) && $content->iteration_count ? (string) $content->iteration_count : '2');
        $heading_before = '';

        if (is_object($content->heading_before)) {
            $heading_before = (isset($content->heading_before->{$this->lang}) && $content->heading_before->{$this->lang} ? $content->heading_before->{$this->lang} : array_values((array) $content->heading_before)[0] ?? '');
        }
        else if (is_string($content->heading_before)) {
            $heading_before = $content->heading_before;
        }

        $name_widget = '';

        if (is_object($content->name_widget)) {
            $name_widget = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        }
        else if (is_string($content->name_widget)) {
            $name_widget = $content->name_widget;
        }

        $heading_after = '';

        if (is_object($content->heading_after)) {
            $heading_after = (isset($content->heading_after->{$this->lang}) && $content->heading_after->{$this->lang} ? $content->heading_after->{$this->lang} : array_values((array) $content->heading_after)[0] ?? '');
        }
        else if (is_string($content->heading_after)) {
            $heading_after = $content->heading_after;
        }

        $animated_text = '';

        if (is_object($content->animated_text)) {
            $animated_text = (isset($content->animated_text->{$this->lang}) && $content->animated_text->{$this->lang} ? $content->animated_text->{$this->lang} : array_values((array) $content->animated_text)[0] ?? '');
        }
        else if (is_string($content->animated_text)) {
            $animated_text = $content->animated_text;
        }

        if ($animated_text) {
            if (str_contains($animated_text, ',')) {
                $animated_text = explode(',', $animated_text);
            }
            else {
                $animated_text = [$animated_text];
            }
        }
        else {
            $animated_text = [];
        }

        $highlight_text = '';

        if (is_object($content->highlight_text)) {
            $highlight_text = (isset($content->highlight_text->{$this->lang}) && $content->highlight_text->{$this->lang} ? $content->highlight_text->{$this->lang} : array_values((array) $content->highlight_text)[0] ?? '');
        }
        else if (is_string($content->highlight_text)) {
            $highlight_text = $content->highlight_text;
        }

        $style = '';
        if ($heading_color || $heading_font) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';

            if ($heading_font) {
                $style .= self::parseFontProperties($heading_font);
            }

            if ($heading_color) {
                $style .= 'color: ' . $heading_color . ';';
            }

            $style .= '}';
        }

        if ($heading_margin) {
            $responsiveItems = [
                '.fon-widget-title' => [
                ['type' => 'margin', 'unit' => '', 'value' => $heading_margin]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }

        if ($heading_padding) {
            $responsiveItems = [
                '.fon-widget-title' => [
                ['type' => 'padding', 'unit' => '', 'value' => $heading_padding]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        if ($animated_text_color || $animated_text_font) {
            $style .= '#' . $widgetId . ' .animated-text, #' . $widgetId . ' .animated-head-highlighted-text{';

            if ($animated_text_font) {
                $style .= self::parseFontProperties($animated_text_font);
            }

            if ($animated_text_color) {
                $style .= 'color: ' . $animated_text_color . ';';
            }

            $style .= '}';
        }
        if (($heading_type == 'highlight') && $shape_color || $shape_width || $shape_rounded_edge) {
            $style .= '#' . $widgetId . ' .animated-head-highlighted-wrap svg path{';

            if ($shape_width) {
                $style .= 'stroke-width: ' . $shape_width . 'px;';
            }

            if ($shape_rounded_edge) {
                $style .= 'stroke-linecap: round;';
                $style .= 'stroke-linejoin: round;';
            }

            if ($shape_color) {
                $style .= 'stroke: ' . $shape_color . ';';
            }

            if ($animation_duration) {
                $style .= '-webkit-animation-duration: ' . $animation_duration . 's;';
                $style .= 'animation-duration: ' . $animation_duration . 's;';
            }

            if ($iteration_count) {
                $style .= '-webkit-animation-iteration-count: ' . $iteration_count . ';';
                $style .= 'animation-iteration-count: ' . $iteration_count . ';';
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isHaveAnimatedText = ($heading_type == 'animation') && $animated_text;

        if ($isHaveAnimatedText) {
            $animated_text_class = 'animated-head-text ';

            if ($animation_effect) {
                switch ($animation_effect) {
                case 'blinds':
                    $animated_text_class .= 'letters animation-blinds';
                    break;
                case 'typing':
                    $animated_text_class .= 'letters type';
                    break;
                case 'flip':
                    $animated_text_class .= 'text-animation-flip';
                    break;
                case 'fade':
                    $animated_text_class .= 'zoom';
                    break;
                case 'loading':
                    $animated_text_class .= 'loading-bar';
                    break;
                case 'scale':
                    $animated_text_class .= 'letters scale';
                    break;
                case 'slide':
                    $animated_text_class .= 'slide';
                    break;
                case 'push':
                    $animated_text_class .= 'push';
                    break;
                case 'wave':
                    $animated_text_class .= 'letters animation-wave';
                    break;
                case 'clip':
                    $animated_text_class .= 'text-clip is-full-width';
                    break;
                default:
                    $animated_text_class .= 'letters type';
                    break;
                }
            }
        }
        $isHaveHighlightText = ($heading_type == 'highlight') && $highlight_text;

        if ($isHaveHighlightText) {
            $highlight_shape_content = '';

            if ($highlight_shape) {
                switch ($highlight_shape) {
                case 'cross':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none" style="z-index: 2">' . "\n" . '                            <path d="M497.4,23.9C301.6,40,155.9,80.6,4,144.4"></path>' . "\n" . '                            <path d="M14.1,27.6c204.5,20.3,393.8,74,467.3,111.7"></path>' . "\n" . '                        </svg>';
                    break;
                case 'circle':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M325,18C228.7-8.3,118.5,8.3,78,21C22.4,38.4,4.6,54.6,5.6,77.6c1.4,32.4,52.2,54,142.6,63.7 c66.2,7.1,212.2,7.5,273.5-8.3c64.4-16.6,104.3-57.6,33.8-98.2C386.7-4.9,179.4-1.4,126.3,20.7">' . "\n\t\t\t\t\t\t" . '</path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'bg-fill':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n" . '                        <path fill="none" stroke="#020202" stroke-width="150" stroke-miterlimit="10" d="M0 75h500"/>' . "\n" . '                        </svg>';
                    break;
                case 'square':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t" . '<path d="M44.22 0c2.46 51.77-2.05 99.72-13.51 143.84 50.37-7.64 316.96-30.55 469.29-5.09-16.41-40.58-21.99-71.11-23.34-127.29C378.38 22.92 97.06 34.37 0 22.92"/>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'scribble-underline':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M9.3,127.3c49.3-3,150.7-7.6,199.7-7.4c121.9,0.4,189.9,0.4,282.3,7.2C380.1,129.6,181.2,130.6,70,139 c82.6-2.9,254.2-1,335.9,1.3c-56,1.4-137.2-0.3-197.1,9"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'diagonal':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none"  style="z-index: 2">' . "\n\t\t\t\t\t\t" . '<path d="M13.5,15.5c131,13.7,289.3,55.5,475,125.5"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'top-bottom-line':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M8.4,143.1c14.2-8,97.6-8.8,200.6-9.2c122.3-0.4,287.5,7.2,287.5,7.2"></path>' . "\n\t\t\t\t\t\t" . '<path d="M8,19.4c72.3-5.3,162-7.8,216-7.8c54,0,136.2,0,267,7.8"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'strikethrough':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none" style="z-index: 2">' . "\n\t\t\t\t\t\t" . '<path d="M3,75h493.5"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'underline':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M7.7,145.6C109,125,299.9,116.2,401,121.3c42.1,2.2,87.6,11.8,87.3,25.7"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'duble-underline':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M5,125.4c30.5-3.8,137.9-7.6,177.3-7.6c117.2,0,252.2,4.7,312.7,7.6"></path>' . "\n\t\t\t\t\t\t" . '<path d="M26.9,143.8c55.1-6.1,126-6.3,162.2-6.1c46.5,0.2,203.9,3.2,268.9,6.4"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'zigzag-underline':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t" . '<path d="M.23 139.83l28.27-19.78 25.43 19.79 28.27-19.77 22.6 19.79 29.68-19.78 25.44 19.79 25.44-19.78 28.27 19.79 26.85-19.77 26.84 19.8 24.04-19.79 24.01 19.8 22.62-19.78 22.61 19.8 22.61-19.78 24.02 19.79 24.03-19.78 24.02 19.8 22.62-19.79 21.19 19.79"/>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'wave':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M3,146.1c17.1-8.8,33.5-17.8,51.4-17.8c15.6,0,17.1,18.1,30.2,18.1c22.9,0,36-18.6,53.9-18.6 c17.1,0,21.3,18.5,37.5,18.5c21.3,0,31.8-18.6,49-18.6c22.1,0,18.8,18.8,36.8,18.8c18.8,0,37.5-18.6,49-18.6c20.4,0,17.1,19,36.8,19 c22.9,0,36.8-20.6,54.7-18.6c17.7,1.4,7.1,19.5,33.5,18.8c17.1,0,47.2-6.5,61.1-15.6"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                default:
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M325,18C228.7-8.3,118.5,8.3,78,21C22.4,38.4,4.6,54.6,5.6,77.6c1.4,32.4,52.2,54,142.6,63.7 c66.2,7.1,212.2,7.5,273.5-8.3c64.4-16.6,104.3-57.6,33.8-98.2C386.7-4.9,179.4-1.4,126.3,20.7">' . "\n\t\t\t\t\t\t" . '</path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                }
            }
        }

        $this->addAsset('fon-animated-head');
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-animated-heading-widget ' . ($content->fon_class ?? '') . '">';

        if (DEMO_MODE) {
            $output .= '<h3 class="fs-6 border-bottom py-3 mb-3">' . $name_widget . '</h3>';
        }

        $output .= '<div class="fon-widget-animated-head">';
        $output .= '<' . $heading_selector . ' class="fon-widget-title layout-' . $heading_layout . ' align-items-start align-items-md-center ' . ($isHaveAnimatedText ? $animated_text_class : 'highlighted-text') . ' ' . $heading_align_class . '">';
        $output .= '<span class="animated-head-before-part">' . $heading_before . '</span>';

        if ($isHaveAnimatedText) {
            $output .= '<span class="animated-text-words-wrapper">';

            foreach ($animated_text as $key => $text) {
                $output .= '<span class="animated-text ' . ($key == 0 ? 'is-visible' : '') . '">' . $text . '</span>';
            }

            $output .= '</span>';
        }

        if ($isHaveHighlightText) {
            $output .= '<span class="animated-head-highlighted-wrap">';
            $output .= '<span class="animated-head-highlighted-text shape-' . $highlight_shape . '">' . $highlight_text . '</span>';
            $output .= $highlight_shape_content;
            $output .= '</span>';
        }

        $output .= '<span class="animated-head-after-part">' . $heading_after . '</span>';
        $output .= '</' . $heading_selector . '>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function animated_number_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $desc = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');
        $style = '';
        $style .= '#' . $widgetId . ' .animated-number .number{';
        if (isset($content->number_size) && $content->number_size) {
            $style .= 'font-size:' . $content->number_size . 'px;';
        }
        if (isset($content->number_weight) && $content->number_weight) {
            $style .= 'font-weight:' . $content->number_weight . ';';
        }
        if (isset($content->number_color) && $content->number_color) {
            $style .= 'color:' . $content->number_color . ';';
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .animated-number .number:' . $content->number_prefix_position . '{';
        $style .= 'content: "' . $content->number_prefix . '";';
        $style .= '}';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = '';
        $counterClass = '';
        $counterData = '';
        $counterContent = '';
        $icon_class = (isset($content->icon_class) && $content->icon_class ? $content->icon_class : '');

        if ($content->number_counter_type == 'counter') {
            $counterClass = 'counter counter-number';
            $counterData = 'data-speed="' . ($content->number_animation_speed ?? '7000') . '" data-to="' . $content->number . '"';
            $counterData .= (is_float($content->number) ? ' data-decimal="1"' : '');
        }
        else if ($content->number_counter_type == 'vertical') {
            $counterClass = 'vertical-counter appear ';
            $counterData = 'data-to="' . $content->number . '"';
            $counterNumbers = str_split($content->number);

            foreach ($counterNumbers as $number) {
                $counterContent .= '<span class="vertical-counter-number" data-to="' . $number . '" ><ul class="list-unstyled"><li class="vcn">0</li><li class="vcn">1</li><li class="vcn">2</li><li class="vcn">3</li><li class="vcn">4</li><li class="vcn">5</li><li class="vcn">6</li><li class="vcn">7</li><li class="vcn">8</li><li class="vcn">9</li></ul></span>';
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-animated-number-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'animated_number' . DS . 'style_' . $content->widget_style . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function articles_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetPages($content, $moduleId, $pageData, 'articles');
    }

    private function banner_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : '1');
        $image = '';

        if (is_object($content->image)) {
            $image = (isset($content->image->{$this->lang}) && $content->image->{$this->lang} ? $content->image->{$this->lang} : array_values((array) $content->image)[0] ?? '');
        }
        else if (is_string($content->image)) {
            $image = $content->image;
        }

        $image_src = ($image ? static::assetLinkDetermine($image) : $lazyPlaceholder);
        $imageDimensions = static::getImageDimensions($image_src, $pageData['badress']);
        $overlay_type = (isset($content->overlay_type) && $content->overlay_type ? $content->overlay_type : 'none');
        $image_overlay = ($overlay_type != 'none' ? true : false);
        $title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $description = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');
        $tag = (isset($content->tag->{$this->lang}) && $content->tag->{$this->lang} ? $content->tag->{$this->lang} : array_values((array) $content->tag)[0] ?? '');
        $icon = (isset($content->icon) && $content->icon ? $content->icon : '');
        $link = (isset($content->link) && $content->link ? $content->link : '');
        $link_target = (isset($content->link_target) && $content->link_target ? $content->link_target : '_blank');
        $link_rel = (isset($content->link_rel) && $content->link_rel ? $content->link_rel : []);
        $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');
        $show_button = (isset($content->show_button) && $content->show_button == 'yes' ? true : false);
        $button_text = (isset($content->button_text->{$this->lang}) && $content->button_text->{$this->lang} ? $content->button_text->{$this->lang} : array_values((array) $content->button_text)[0] ?? '');
        $show_button_icon = (isset($content->show_button_icon) && $content->show_button_icon == 'yes' ? true : false);
        $button_icon = (isset($content->button_icon) && $content->button_icon ? $content->button_icon : '');
        $button_icon_position = (isset($content->button_icon_position) && $content->button_icon_position ? $content->button_icon_position : 'right');
        $image_alt = (isset($content->image_alt->{$this->lang}) && $content->image_alt->{$this->lang} ? $content->image_alt->{$this->lang} : (isset($content->image_alt) ? array_values((array) $content->image_alt)[0] ?? '' : ''));
        $image_title = (isset($content->image_title->{$this->lang}) && $content->image_title->{$this->lang} ? $content->image_title->{$this->lang} : (isset($content->image_title) ? array_values((array) $content->image_title)[0] ?? '' : ''));

        if (empty($image_alt)) {
            if (!empty($title)) {
                $image_alt = $title;
            }
            else if (!empty($image_title)) {
                $image_alt = $image_title;
            }
            else {
                $image_alt = basename($image_src);
            }
        }

        if (empty($image_title)) {
            if (!empty($title)) {
                $image_title = $title;
            }
            else if (!empty($image_alt)) {
                $image_title = $image_alt;
            }
            else {
                $image_title = basename($image_src);
            }
        }

        $style = '';

        if ($image_overlay) {
            $style .= '#' . $widgetId . '.fon-banner-widget{';

            if ($overlay_type == 'color') {
                $style .= (isset($content->color_overlay->normal) && $content->color_overlay->normal ? '--bs-bg-overlay-color:' . $content->color_overlay->normal . ';' : '');
                $style .= (isset($content->color_overlay->hover) && $content->color_overlay->hover ? '--bs-bg-overlay-hover-color:' . $content->color_overlay->hover . ';' : '');
            }

            if ($overlay_type == 'gradient') {
                $style .= (isset($content->gradient_overlay->normal) && $content->gradient_overlay->normal ? self::parseGradient($content->gradient_overlay->normal, 'bg-overlay') : '');
                $style .= (isset($content->gradient_overlay->hover) && $content->gradient_overlay->hover ? self::parseGradient($content->gradient_overlay->hover, 'bg-overlay-hover') : '');
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-banner-widget style-' . $widget_style . ' overlay-' . $overlay_type . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'banner' . DS . 'style_' . $content->widget_style . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function bank_account_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $class = (isset($content->fon_class) && $content->fon_class ? $content->fon_class : '');
        $show_title = (isset($content->show_name) && $content->show_name == 'yes' ? true : false);
        $show_logo = (isset($content->show_logo) && $content->show_logo == 'yes' ? true : false);
        $title = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        $owner = (isset($content->owner) && $content->owner ? $content->owner : '');
        $iban = (isset($content->iban) && $content->iban ? $content->iban : '');
        $swift = (isset($content->swift) && $content->swift ? $content->swift : '');
        $number = (isset($content->number) && $content->number ? $content->number : '');
        $branch = (isset($content->branch) && $content->branch ? $content->branch : '');
        $widget_style = (isset($content->style) && $content->style ? $content->style : 'horizontal');
        $logo = (isset($content->logo) && $content->logo ? $content->logo : '');
        $logo_src = ($logo ? static::assetLinkDetermine($logo) : $lazyPlaceholder);
        $imageDimensions = static::getImageDimensions($logo_src, $pageData['badress']);
        $moduleLang = Modules::Lang('Payment', 'BankTransfer', Language::selected());
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="card fon-bank-account rounded-4 bg-theme-light border-0 mb-4 ' . $class . '">';
        $output .= '<div class="row g-0 align-items-center justify-content-center">';
        if ($show_logo && $logo) {
            $output .= '<div class="col-md-' . ($widget_style == 'horizontal' ? '4' : '12') . '">';
            $output .= '<div class="h-100 rounded-4 d-flex flex-column justify-content-center align-items-center">';

            if ($enableLazyLoading) {
                $output .= '<img class="card-image img-fluid" loading="lazy" decoding="async" src="' . $logo_src . '" alt="' . $title . '" style="' . ($widget_style == 'horizontal' ? 'max-width:80%' : 'max-height:150px') . '" ' . $imageDimensions . '/>';
            }
            else {
                $output .= '<img class="card-image img-fluid" src="' . $logo_src . '" alt="' . $title . '" style="' . ($widget_style == 'horizontal' ? 'max-width:80%' : 'max-height:150px') . '" ' . $imageDimensions . '/>';
            }

            $output .= '</div>';
            $output .= '</div>';
        }
        $output .= '<div class="col-md-' . (($widget_style == 'horizontal') && $show_logo && $logo ? '8' : '12') . '">';
        $output .= '<div class="card-body">';
        if ($show_title && $title) {
            $output .= '<h5 class="card-title">' . $title . '</h5>';
        }

        $output .= '<ul class="list-group rounded-4 list-group-flush">';
        $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
        $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-buyer-name'] . ' :</strong>';
        $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $owner . ' <button type="button" data-text="' . $owner . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
        $output .= '</li>';
        $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
        $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-iban'] . ' :</strong>';
        $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $iban . ' <button type="button" data-text="' . $iban . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
        $output .= '</li>';

        if ($swift) {
            $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
            $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-swift'] . ' :</strong>';
            $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $swift . ' <button type="button" data-text="' . $swift . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
            $output .= '</li>';
        }

        if ($number) {
            $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
            $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-number'] . ' :</strong>';
            $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $number . ' <button type="button" data-text="' . $number . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
            $output .= '</li>';
        }

        if ($branch) {
            $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
            $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-branch-nc'] . ' :</strong>';
            $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $branch . ' <button type="button" data-text="' . $branch . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
            $output .= '</li>';
        }

        $output .= '</ul>';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function button_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        $aligns = (isset($content->align) && $content->align ? $content->align : NULL);

        foreach ($aligns as $k => $v) {
            if ($v == 'left') {
                $aligns->{$k} = 'start';
            }
            else if ($v == 'right') {
                $aligns->{$k} = 'end';
            }
        }

        $output = '';
        if (isset($content->items) && is_array($content->items)) {
            $buttonCount = count($content->items);

            if (1 < $buttonCount) {
                if (isset($content->gap) && $content->gap) {
                    $style .= '#' . $widgetId . ' .fon-widget-button-group .btn{';
                    $style .= 'margin: ' . $content->gap . 'px';
                    $style .= '}';
                }
            }

            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-button-widget ' . $content->fon_class . '">';
            $output .= $this->parseButtons($content->items, $moduleId, $pageData, $aligns);
            $output .= '</div>';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        return $output;
    }

    private function calltoaction_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceHolder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $bg_type = (isset($content->bg_type) && $content->bg_type ? $content->bg_type : 'none');
        $bg_image = '';

        if (is_object($content->bg_image)) {
            $bg_image = (isset($content->bg_image->{$this->lang}) && $content->bg_image->{$this->lang} ? $content->bg_image->{$this->lang} : array_values((array) $content->bg_image)[0] ?? '');
        }
        else if (is_string($content->bg_image)) {
            $bg_image = $content->bg_image;
        }

        $bg_image_src = ($bg_image ? static::assetLinkDetermine($bg_image) : $lazyPlaceHolder);
        $overlay_type = (isset($content->overlay_type) && $content->overlay_type ? $content->overlay_type : 'none');
        $bg_overlay = ($overlay_type != 'none' ? true : false);
        $bg_color = (isset($content->bg_color) && $content->bg_color ? $content->bg_color : '');
        $bg_color_overlay = (isset($content->color_overlay) && $content->color_overlay ? $content->color_overlay : '');
        $bg_gradient = (isset($content->bg_gradient) && $content->bg_gradient ? $content->bg_gradient : '');
        $bg_gradient_overlay = (isset($content->gradient_overlay) && $content->gradient_overlay ? $content->gradient_overlay : '');
        $button_position = (isset($content->button_position) && $content->button_position ? $content->button_position : 'right');
        $align = (isset($content->align) && $content->align ? $content->align : '');
        $padding = (isset($content->padding) && $content->padding ? $content->padding : '');
        $use_border = (isset($content->use_border) && $content->use_border == 'yes' ? true : false);
        $border = (isset($content->border) && $content->border ? $content->border : '');
        $border_radius = (isset($content->border_radius) && $content->border_radius ? $content->border_radius : '');
        $shadow = (isset($content->shadow) && $content->shadow ? $content->shadow : '');
        $title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : '');
        $title_color = (isset($content->title_color) && $content->title_color ? $content->title_color : '');
        $description = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');
        $description_font = (isset($content->content_font) && $content->content_font ? $content->content_font : '');
        $description_color = (isset($content->content_color) && $content->content_color ? $content->content_color : '');
        $show_icon = (isset($content->show_icon) && $content->show_icon == 'yes' ? true : false);
        $icon = (isset($content->icon) && $content->icon ? $content->icon : '');
        $icon_size = (isset($content->icon_size) && $content->icon_size ? $content->icon_size : '');
        $icon_color = (isset($content->icon_color) && $content->icon_color ? $content->icon_color : '');
        $style = '';
        $style .= '#' . $widgetId . '{';

        if ($bg_type != 'none') {
            if (($bg_type == 'color') && $bg_color) {
                $style .= 'background-color: ' . $bg_color . ';';
            }
            else if (($bg_type == 'gradient') && $bg_gradient) {
                $style .= 'background-image: ' . self::parseGradient($bg_gradient) . ';';
            }
            else if (($bg_type == 'image') && $bg_image) {
                $style .= 'background-image: url(' . $bg_image_src . ');';
            }
        }

        if ($padding) {
            $style .= 'padding: ' . $padding . 'px;';
        }
        if ($use_border && $border) {
            $style .= 'border: ' . $border . ';';
        }

        if ($border_radius) {
            $style .= 'border-radius: ' . $border_radius . 'px;';
        }

        if ($shadow) {
            $style .= 'box-shadow: ' . $shadow . ';';
        }

        $style .= '}';
        if (($button_position == 'bottom') && $align != 'center') {
            $responsiveItems = [
                '.fon-widget-content' => [
                ['type' => 'width', 'unit' => '%', 'value' => $content->width]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        if (($bg_type == 'image') && $bg_overlay && $bg_color_overlay || $bg_gradient_overlay) {
            $style .= '#' . $widgetId . ' .fon-calltoaction-overlay{';
            $style .= (($overlay_type == 'color') && $bg_color_overlay ? 'background-color:' . $bg_color_overlay . ';' : '');
            $style .= (($overlay_type == 'gradient') && $bg_gradient_overlay ? self::parseGradient($bg_gradient_overlay) : '');

            if ($border_radius) {
                $style .= 'border-radius: ' . $border_radius . 'px;';
            }

            $style .= '}';
        }

        $style .= '#' . $widgetId . ' .fon-calltoaction-title{';
        $style .= ($title_font ? self::parseFontProperties($title_font) : '');
        $style .= ($title_color ? 'color: ' . $title_color . ';' : '');
        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-calltoaction-description{';
        $style .= ($description_font ? self::parseFontProperties($description_font) : '');
        $style .= ($description_color ? 'color: ' . $description_color . ';' : '');
        $style .= '}';
        if ($show_icon && $icon) {
            $style .= '#' . $widgetId . ' .fon-calltoaction-icon i{';
            $style .= ($icon_color ? 'color: ' . $icon_color . ';' : '');
            $style .= ($icon_size ? 'font-size: ' . $icon_size . 'px;' : '');
            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        if (!is_object($align) && $align != '') {
            $align = new stdClass();
            $textAlign = '';

            switch ($align) {
            case 'left':
                $textAlign = 'start';
                break;
            case 'center':
                $textAlign = 'center';
                break;
            case 'right':
                $textAlign = 'end';
                break;
            }

            $align->xs = $align->sm = $align->md = $align->lg = $align->xl = $textAlign;
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-calltoaction-widget bg-cover buttons-' . $button_position . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-calltoaction-overlay position-absolute w-100 h-100 top-0 start-0"></div>';
        $output .= '<div class="fon-widget-content position-relative ' . ($button_position == 'right' ? 'row g-0 align-items-center ' : '') . '">';
        if ($show_icon && $icon) {
            $output .= '<div class="fon-calltoaction-icon ' . ($button_position == 'right' ? 'col-12 col-md-1 text-center align-self-start' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">';
            $output .= '<i class="' . $icon . '  ' . ($button_position == 'right' ? 'm-2 ' : 'my-2') . '"></i>';
            $output .= '</div>';
        }
        if ($title || $description) {
            $output .= '<div class="fon-calltoaction-inner-content ' . ($button_position == 'right' ? 'col-12 col-md-8' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">';

            if ($title) {
                $output .= '<' . $heading_selector . ' class="fon-calltoaction-title ' . ($button_position == 'right' ? 'text-center text-md-start' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">' . strip_tags($title) . '</' . $heading_selector . '>';
            }

            if ($description) {
                $output .= '<p class="fon-calltoaction-description ' . ($button_position == 'right' ? 'text-center text-md-start' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">' . strip_tags($description) . '</p>';
            }

            $output .= '</div>';
        }
        if (isset($content->buttons) && is_array($content->buttons) && $content->buttons) {
            $output .= '<div class="fon-calltoaction-buttons ' . ($button_position == 'right' ? 'col-12 col-md-' . ($show_icon && $icon ? '3' : '4') . ' text-center text-md-end' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">';
            $output .= $this->parseButtons($content->buttons, $moduleId, $pageData, $align);
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function campaign_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $mediaType = (isset($content->media_type) && $content->media_type ? $content->media_type : 'icon');
        $useCoupon = (isset($content->use_coupon) && $content->use_coupon == 'yes' ? true : false);
        $useCountdown = (isset($content->use_countdown) && $content->use_countdown == 'yes' ? true : false);

        if (isset($content->campaign_message)) {
            $campaign_message = (isset($content->campaign_message->{$this->lang}) && $content->campaign_message->{$this->lang} ? $content->campaign_message->{$this->lang} : array_values((array) $content->campaign_message)[0] ?? '');
        }
        else {
            $campaign_message = '';
        }

        $dateLangs = ['day' => ___('date/day'), 'hour' => ___('date/hour'), 'minute' => ___('date/minute'), 'second' => ___('date/second')];
        $carouselData = '';
        $columns = [];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel campaign-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl . ' g-3' : '');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-campaign-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content ' . $containerClass . '" ' . $carouselData . '>';
        if (isset($content->items) && is_array($content->items)) {
            foreach ($content->items as $ikey => $item) {
                if ($mediaType == 'image') {
                    if ($item->campaign_image) {
                        $item->campaign_image = static::assetLinkDetermine($item->campaign_image);
                    }
                    else {
                        $item->campaign_image = $lazyPlaceholder;
                    }

                    $imageDimensions = static::getImageDimensions($item->campaign_image, $pageData['badress']);
                }
                $campaign_name = (isset($item->campaign_name->{$this->lang}) && $item->campaign_name->{$this->lang} ? $item->campaign_name->{$this->lang} : array_values((array) $item->campaign_name)[0] ?? '');
                $campaign_link = (isset($item->campaign_link->{$this->lang}) && $item->campaign_link->{$this->lang} ? $item->campaign_link->{$this->lang} : array_values((array) $item->campaign_link)[0] ?? '');
                $campaign_tag = (isset($item->campaign_tag->{$this->lang}) && $item->campaign_tag->{$this->lang} ? $item->campaign_tag->{$this->lang} : array_values((array) $item->campaign_tag)[0] ?? '');

                if (isset($item->campaign_desc)) {
                    $campaign_desc = (isset($item->campaign_desc->{$this->lang}) && $item->campaign_desc->{$this->lang} ? $item->campaign_desc->{$this->lang} : array_values((array) $item->campaign_desc)[0] ?? '');
                }
                else {
                    $campaign_desc = '';
                }

                $campaignRate = '';
                if (($content->show_campaign_rate == 'yes') && $item->campaign_amount_old_price && $item->campaign_amount_new_price) {
                    $campaignRate = round((($item->campaign_amount_old_price - $item->campaign_amount_new_price) / $item->campaign_amount_old_price) * 100);
                    $campaignRate = sprintf(__('theme/package_discount_save'), $campaignRate);
                }
                $dateString = (isset($item->campaign_date) && $item->campaign_date ? $item->campaign_date : date('Y-m-d H:i:s', strtotime('+1 month')));
                $isExpired = $dateString <= date('Y-m-d H:i:s');
                $dateString = date('Y/m/d H:i:s', strtotime($dateString));

                if (!$isCarousel) {
                    $output .= '<div class="col">';
                }
                $isFeatured = isset($item->campaign_featured) && $item->campaign_featured == 'yes';
                include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'campaign' . DS . 'style_' . $content->widget_style . '.php';

                if (!$isCarousel) {
                    $output .= '</div>';
                }
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function carouselslider_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $content_vertical_center = (isset($content->content_vertical_center) && $content->content_vertical_center == 'yes' ? true : false);
        $height = (isset($content->height) && $content->height ? $content->height : 'auto');
        $custom_height = (isset($content->custom_height) && $content->custom_height ? $content->custom_height : (object) ['xl' => 900, 'lg' => 700, 'md' => 600, 'sm' => 500, 'xs' => 400]);
        $animation_style = (isset($content->animation_style) && $content->animation_style ? $content->animation_style : 'slide');
        $autoplay = (isset($content->autoplay) && $content->autoplay == 'yes' ? true : false);
        $interval = (isset($content->interval) && $content->interval ? $content->interval : 3000);
        $disable_touch_swipe = (isset($content->disable_touch_swipe) && $content->disable_touch_swipe == 'yes' ? true : false);
        $arrow_controllers = (isset($content->arrow_controllers) && $content->arrow_controllers == 'yes' ? true : false);
        $dot_controllers = (isset($content->dot_controllers) && $content->dot_controllers == 'yes' ? true : false);
        $dot_controllers_thumb = (isset($content->dot_controllers_thumb) && $content->dot_controllers_thumb == 'yes' ? true : false);
        $slide_items = (isset($content->items) && $content->items ? $content->items : []);
        if (!$arrow_controllers && !$dot_controllers) {
            $autoplay = true;
        }

        $carouselAttributes = '';
        $carouselAttributes .= ($autoplay ? ' data-bs-ride="carousel" ' : '');
        $carouselAttributes .= ($disable_touch_swipe ? ' data-bs-touch="false" ' : '');
        $style = '';

        if ($height != 'auto') {
            $responsiveItems = [
                '.carousel-item' => [
                ['type' => 'height', 'unit' => 'px', 'value' => $custom_height]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-carouselslider-widget ' . ($content_vertical_center ? 'vertical-center' : '') . ' ' . $content->fon_class . '">';
        $output .= '<div id="carousel_' . $moduleId . '" class="carousel slide ' . ($animation_style == 'fade' ? 'carousel-fade' : '') . '" ' . $carouselAttributes . '>';

        if ($slide_items) {
            if ($dot_controllers) {
                $output .= '<div class="carousel-indicators ' . ($dot_controllers_thumb ? 'carousel-thumb' : '') . '">';

                foreach ($slide_items as $sk => $si) {
                    $thumb_image = '';

                    if (is_object($si->image)) {
                        $thumb_image = (isset($si->slide_image->{$this->lang}) && $si->slide_image->{$this->lang} ? $si->slide_image->{$this->lang} : array_values((array) $si->slide_image)[0] ?? '');
                    }
                    else if (is_string($si->slide_image)) {
                        $thumb_image = $si->slide_image;
                    }

                    $output .= '<button' . "\n" . '                        type="button"' . "\n" . '                        data-bs-target="#carousel_' . $moduleId . '"' . "\n" . '                        data-bs-slide-to="' . $sk . '"' . "\n" . '                        class="' . ($sk == 0 ? 'active' : '') . '" ' . ($sk == 0 ? 'aria-current="true"' : '') . "\n" . '                        aria-label="Slide ' . ($sk + 1) . '"' . "\n" . '                        style="' . ($dot_controllers_thumb ? 'background-image:url(' . $thumb_image . ');' : '') . '"></button>';
                }

                $output .= '</div>';
            }

            $output .= '<div class="carousel-inner">';

            foreach ($slide_items as $slide_key => $slide_item) {
                $image = '';

                if (is_object($slide_item->slide_image)) {
                    $image = (isset($slide_item->slide_image->{$this->lang}) && $slide_item->slide_image->{$this->lang} ? $slide_item->slide_image->{$this->lang} : array_values((array) $slide_item->slide_image)[0] ?? '');
                }
                else if (is_string($slide_item->slide_image)) {
                    $image = $slide_item->slide_image;
                }

                $image_src = ($image ? static::assetLinkDetermine($image) : $lazyPlaceholder);
                $imageDimensions = static::getImageDimensions($image_src, $pageData['badress']);
                $mobile_image = '';

                if (is_object($slide_item->slide_mobile_image)) {
                    $mobile_image = (isset($slide_item->slide_mobile_image->{$this->lang}) && $slide_item->slide_mobile_image->{$this->lang} ? $slide_item->slide_mobile_image->{$this->lang} : array_values((array) $slide_item->slide_mobile_image)[0] ?? '');
                }
                else if (is_string($slide_item->slide_mobile_image)) {
                    $mobile_image = $slide_item->slide_mobile_image;
                }

                $mobile_image_src = ($mobile_image ? static::assetLinkDetermine($mobile_image) : $lazyPlaceholder);
                $mobileDimensions = static::getImageDimensions($mobile_image_src, $pageData['badress']);
                $show_info = (isset($slide_item->slide_show_info) && $slide_item->slide_show_info == 'yes' ? true : false);
                $link = (isset($slide_item->button_link->{$this->lang}) && $slide_item->button_link->{$this->lang} ? $slide_item->button_link->{$this->lang} : array_values((array) $slide_item->button_link)[0] ?? '');
                $target = (isset($slide_item->button_target) && $slide_item->button_target ? $slide_item->button_target : '_self');

                if ($show_info) {
                    $title = (isset($slide_item->slide_title->{$this->lang}) && $slide_item->slide_title->{$this->lang} ? $slide_item->slide_title->{$this->lang} : array_values((array) $slide_item->slide_title)[0] ?? '');
                    $title_color = (isset($slide_item->slide_title_color) && $slide_item->slide_title_color ? $slide_item->slide_title_color : '#ffffff');
                    $description = (isset($slide_item->slide_description->{$this->lang}) && $slide_item->slide_description->{$this->lang} ? $slide_item->slide_description->{$this->lang} : array_values((array) $slide_item->slide_description)[0] ?? '');
                    $description_color = (isset($slide_item->slide_description_color) && $slide_item->slide_description_color ? $slide_item->slide_description_color : '#ffffff');
                    $content_bg = (isset($slide_item->slide_content_bg) && $slide_item->slide_content_bg ? $slide_item->slide_content_bg : 'rgba(0,0,0,0.1)');
                    $content_align = (isset($slide_item->slide_content_align) && $slide_item->slide_content_align ? (array) $slide_item->slide_content_align : ['xl' => 'center', 'lg' => 'center', 'md' => 'center', 'sm' => 'center', 'xs' => 'center']);
                    $content_align = (object) array_map(function($val) {
                        return ($val === 'left' ? 'start' : ($val === 'right' ? 'end' : $val));
                    }, $content_align);
                    $alignClass = 'text-' . $content_align->xs . ' text-sm-' . $content_align->sm . ' text-md-' . $content_align->md . ' text-lg-' . $content_align->lg . ' text-xl-' . $content_align->xl;
                }

                $output .= '<div class="carousel-item ' . ($slide_key == 0 ? 'active' : '') . ' ' . ($height != 'auto' ? 'custom-height' : '') . '" data-bs-interval="' . $interval . '">';
                if (!$show_info && $link) {
                    $output .= '<a href="' . $link . '" target="' . $target . '" class="d-block h-100">';
                }
                if ($mobile_image && $mobile_image != $image && $height == 'auto') {
                    if ($enableLazyLoading) {
                        $output .= '<img loading="lazy" decoding="async" src="' . $image_src . '" class="d-none d-lg-block w-100 h-auto" alt="' . ($title ?? ('Slide ' . $slide_key)) . '" ' . $imageDimensions . '>';
                        $output .= '<img loading="lazy" decoding="async" src="' . $mobile_image_src . '" class="d-block d-lg-none w-100 h-auto" alt="' . ($title ?? ('Slide ' . $slide_key)) . '" ' . $imageDimensions . '>';
                    }
                    else {
                        $output .= '<img src="' . $image_src . '" class="d-none d-lg-block w-100 h-auto" alt="' . ($title ?? ('Slide ' . $slide_key)) . '"  ' . $mobileDimensions . '>';
                        $output .= '<img src="' . $mobile_image_src . '" class="d-block d-lg-none w-100 h-auto" alt="' . ($title ?? ('Slide ' . $slide_key)) . '"  ' . $imageDimensions . '>';
                    }
                }
                else if ($enableLazyLoading) {
                    $output .= '<img loading="lazy" decoding="async" src="' . $image_src . '" class="d-block w-100" alt="' . ($title ?? ('Slide ' . $slide_key)) . '">';
                }
                else {
                    $output .= '<img src="' . $image_src . '" class="d-block w-100" alt="' . ($title ?? ('Slide ' . $slide_key)) . '">';
                }
                if (!$show_info && $link) {
                    $output .= '</a>';
                }
                if ($show_info && $title || $description || $link) {
                    $output .= '<div class="carousel-caption d-none d-md-block ' . $alignClass . '">';
                    $output .= '<div class="carousel-caption-inner p-3 rounded" style="background-color:' . $content_bg . ';">';

                    if ($title) {
                        $output .= '<h2 ' . ($title_color ? 'style="color:' . $title_color . '"' : '') . '>' . $title . '</h2>';
                    }

                    if ($description) {
                        $output .= '<p ' . ($description_color ? 'style="color:' . $description_color . '"' : '') . '>' . $description . '</p>';
                    }

                    if ($link) {
                        $output .= self::parseButton($slide_item, $moduleId, $pageData);
                    }

                    $output .= '</div>';
                    $output .= '</div>';
                }

                $output .= '</div>';
            }

            $output .= '</div>';

            if ($arrow_controllers) {
                $output .= '<button class="carousel-control-prev" type="button" data-bs-target="#carousel_' . $moduleId . '" data-bs-slide="prev">';
                $output .= '<span class="fa-solid fa-circle-chevron-left fs-2" aria-hidden="true"></span>';
                $output .= '<span class="visually-hidden">Previous</span>';
                $output .= '</button>';
                $output .= '<button class="carousel-control-next" type="button" data-bs-target="#carousel_' . $moduleId . '" data-bs-slide="next">';
                $output .= '<span class="fa-solid fa-circle-chevron-right fs-2" aria-hidden="true"></span>';
                $output .= '<span class="visually-hidden">Next</span>';
                $output .= '</button>';
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function client_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $use_border = (isset($content->use_border) && $content->use_border == 'yes' ? true : false);
        $show_title = (isset($content->show_title) && $content->show_title == 'yes' ? true : false);
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $center = (isset($content->center) && $content->center == 'yes' ? true : false);
        $remove_hover = (isset($content->remove_hover) && $content->remove_hover == 'yes' ? true : false);
        $background = (isset($content->background) && $content->background ? $content->background : (object) ['normal' => '#ffffff', 'hover' => '#ffffff']);
        $image_filter = (isset($content->image_filter) && $content->image_filter ? $content->image_filter : 'none');
        $border = (isset($content->border) && $content->border ? $content->border : '');
        $radius = (isset($content->radius) && $content->radius ? $content->radius : '');
        $shadow = (isset($content->shadow) && $content->shadow ? $content->shadow : '');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : []);
        $blur_value = (isset($content->blur_value) && $content->blur_value ? $content->blur_value : 0);
        $grayscale_value = (isset($content->grayscale_value) && $content->grayscale_value ? $content->grayscale_value : 0);
        $opacity_value = (isset($content->opacity_value) && $content->opacity_value ? $content->opacity_value : 1);
        $scale_value = (isset($content->scale_value) && $content->scale_value ? $content->scale_value : 1);
        $hover_effect = (isset($content->hover_effect) && $content->hover_effect ? $content->hover_effect : 'none');
        $max_height = (isset($content->max_height) && $content->max_height ? $content->max_height : '');
        $padding = (isset($content->padding) && $content->padding ? $content->padding : '');
        $link_target = (isset($content->link_target) && $content->link_target ? $content->link_target : '_self');
        $style = '';
        $style .= '#' . $widgetId . ' .client{';
        if ($use_border && $border) {
            $style .= 'border: ' . $border . ';';

            if ($radius) {
                $style .= 'border-radius: ' . $radius . 'px;';
            }

            if ($padding) {
                $style .= 'padding: ' . $padding . ';';
            }
        }
        if (isset($background->normal) && $background->normal) {
            $style .= 'background-color: ' . $background->normal . ';';
        }

        if ($shadow) {
            $style .= 'box-shadow: ' . $shadow . ';';
        }

        $style .= '}';
        if (isset($background->hover) && $background->hover) {
            $style .= '#' . $widgetId . ' .client:hover{';
            $style .= 'background-color: ' . $background->hover . ';';
            $style .= '}';
        }
        if ($show_title && $title_font) {
            $style .= '#' . $widgetId . ' .client .client-title{';
            $style .= self::parseFontProperties($title_font);
            $style .= '}';
        }

        if ($image_filter == 'blur') {
            $style .= '#' . $widgetId . '.filter-blur .fon-widget-content:hover .client{';
            $style .= 'filter: blur(' . $blur_value . 'px);';
            $style .= 'opacity:0.6;';
            $style .= '}';
            $style .= '#' . $widgetId . '.filter-blur .fon-widget-content:hover .client:hover{';
            $style .= 'filter: blur(0);';
            $style .= 'opacity:1;';
            $style .= '}';
        }
        else {
            $style .= '#' . $widgetId . ' .client .client-image{';

            if ($max_height) {
                $style .= 'max-height: ' . $max_height . 'px;';
            }

            if ($image_filter != 'none') {
                if ($image_filter == 'grayscale') {
                    $style .= 'filter: grayscale(' . $grayscale_value . '%);';
                }
                else if ($image_filter == 'opacity') {
                    $style .= 'filter: opacity(' . $opacity_value . '%);';
                }
            }

            if ($hover_effect != 'none') {
                if ($hover_effect == 'scale') {
                    $style .= 'transform: scale(1);';
                }
                else if ($hover_effect == 'move') {
                    $style .= 'transform: translateY(0);';
                }
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .client:hover .client-image{';
            if (($image_filter != 'none') && $remove_hover) {
                if ($image_filter == 'grayscale') {
                    $style .= 'filter: grayscale(0);';
                }
                else if ($image_filter == 'opacity') {
                    $style .= 'filter: opacity(100);';
                }
            }

            if ($hover_effect != 'none') {
                if ($hover_effect == 'scale') {
                    $style .= 'transform: scale(' . $scale_value . ');';
                }
                else if ($content->hover_effect == 'move') {
                    $style .= 'transform: translateY(-' . $scale_value . 'px);';
                }
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $carouselData = '';
        $columns = (object) ['xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => ''];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel client-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl . ' g-3' : '');

            if ($center) {
                $containerClass .= ' justify-content-center';
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-client-widget ' . ($content->use_border == 'yes' ? 'with-border' : '') . ' filter-' . $content->image_filter . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content ' . $containerClass . '" ' . $carouselData . '>';
        if (isset($content->items) && is_array($content->items)) {
            $i = 1;

            foreach ($content->items as $item) {
                $client_title = (isset($item->client_title) && $item->client_title ? $item->client_title : '');
                $client_alt = (isset($item->client_alt) && $item->client_alt ? $item->client_alt : '');
                $client_link = (isset($item->client_link) && $item->client_link ? $item->client_link : '');
                $link_target = (isset($item->link_target) && $item->link_target ? $item->link_target : '_self');
                $link_rel = (isset($item->link_rel) && $item->link_rel ? $item->link_rel : []);
                $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');

                if ($item->client_image) {
                    $item->client_image = static::assetLinkDetermine($item->client_image);
                }
                else {
                    $item->client_image = $lazyPlaceholder;
                }

                if (empty($client_alt)) {
                    if (!empty($client_title)) {
                        $client_alt = $client_title;
                    }
                    else {
                        $client_alt = basename($item->client_image);
                    }
                }

                if (empty($client_title)) {
                    if (!empty($client_alt)) {
                        $client_title = $client_alt;
                    }
                    else {
                        $client_title = basename($item->client_image);
                    }
                }

                $imageDimensions = static::getImageDimensions($item->client_image, $pageData['badress']);
                $lastClass = [];

                if (6 < $i) {
                    $i = 1;
                }

                if ($i == $columns->xs) {
                    $lastClass[] = 'last-xs';
                }
                else if ($i == $columns->sm) {
                    $lastClass[] = 'last-sm';
                }
                else if ($i == $columns->md) {
                    $lastClass[] = 'last-md';
                }
                else if ($i == $columns->lg) {
                    $lastClass[] = 'last-lg';
                }
                else if ($i == $columns->xl) {
                    $lastClass[] = 'last-xl';
                }

                if (!$isCarousel) {
                    $output .= '<div class="col ' . implode(' ', $lastClass) . ' ">';
                }

                $output .= '<div class="client transition-default">';

                if ($client_link) {
                    $output .= '<a class="d-block" href="' . $client_link . '" target="' . $link_target . '" ' . $link_rel . ' title="' . $client_title . '">';
                }

                if ($enableLazyLoading) {
                    $output .= '<img class="client-image h-auto" loading="lazy" decoding="async" src="' . $item->client_image . '" alt="' . $client_alt . '"  title="' . $client_title . '" ' . $imageDimensions . '/>';
                }
                else {
                    $output .= '<img class="client-image h-auto" src="' . $item->client_image . '" alt="' . $client_alt . '" title="' . $client_title . '" ' . $imageDimensions . '/>';
                }

                if ($show_title) {
                    $output .= '<h5 class="client-title">' . $client_title . '</h5>';
                }

                if ($client_link) {
                    $output .= '</a>';
                }

                $output .= '</div>';

                if (!$isCarousel) {
                    $output .= '</div>';
                }

                ++$i;
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function comparison_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $pageType = $pageData['page'] ?? ($content['page_type'] ?? 'custom');
        $show_free_label = !isset($content->show_free_label) || $content->show_free_label == 'yes';
        $free_label_text = self::getFieldMultilingualText($content->free_label_text ?? NULL, $this->lang, __('theme/is_free'));
        if ($show_free_label && empty($free_label_text)) {
            $free_label_text = __('theme/is_free');
        }
        $card_button_action_on_free = (isset($content->card_button_action_on_free) && $content->card_button_action_on_free ? $content->card_button_action_on_free : 'default');
        $enable_custom_card_button_label = isset($content->enable_custom_card_button_label) && $content->enable_custom_card_button_label == 'yes';
        $custom_card_button_label = self::getFieldMultilingualText($content->custom_card_button_label ?? NULL, $this->lang, __('website/index/add-basket-button'));
        $isProductPage = in_array($pageType, ['hosting' => true, 'server' => true, 'sms' => true, 'special' => true]);
        $show_price_type = (isset($content->show_price_type) && $content->show_price_type ? $content->show_price_type : 'default');

        if ($show_price_type == 'yes') {
            $show_price_type = 'month_year';
        }
        $price_calc = (isset($content->price_calc) && $content->price_calc ? $content->price_calc : 'default');
        $source = (isset($content->source) && $content->source ? $content->source : 'category');
        $source_category = (isset($content->category) && $content->category ? $content->category : '');
        $source_package = (isset($content->package) && $content->package ? $content->package : '');
        $name_widget = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        $desc_widget = (isset($content->desc_widget->{$this->lang}) && $content->desc_widget->{$this->lang} ? $content->desc_widget->{$this->lang} : array_values((array) $content->desc_widget)[0] ?? '');
        $catType = '';
        $currency_symbols = self::getCurrencySymbols();
        if ($isProductPage && isset($pageData['items'])) {
            $category = $pageData['items']['showCategory'] ?? [];
            $catType = $category['kind'] ?? '';

            if (!$category) {
                return '';
            }

            $list = $pageData['functions']['get_list']($category['id'], $category['kind']);

            if (!$list) {
                $categories = $pageData['functions']['get_categories']($category['id'], $category['kind']);

                if ($categories) {
                    $list = $pageData['functions']['get_list']($categories[0]['id'], $category['kind']);
                }
            }
        }
        else if (($source == 'category') && $source_category) {
            list($categoryType, $categoryId) = explode(':', $source_category);
            $catType = $categoryType ?? '';

            if ($categoryId == 'none') {
                $result = $this->getWidgetItems('products', $categoryId, $categoryType);

                if ($result) {
                    $category = ['kind' => $categoryType, 'title' => $name_widget];
                    $list = $result['items'];
                }
                else {
                    $category = [];
                    $list = [];
                }

                if (!$category) {
                    return '';
                }
            }
            else {
                $result = $this->getWidgetItems('products', 'cats: ' . $categoryId, $categoryType);

                if ($result) {
                    $category = $result['cats'][$categoryId];
                    $list = $result['items'][$categoryId];
                }
                else {
                    $category = [];
                    $list = [];
                }

                if (!$category) {
                    return '';
                }
            }
        }
        else if (($source == 'package') && $source_package) {
            list($packageType, $packageIds) = explode(':', $source_package);
            $catType = $packageType ?? '';
            $result = $this->getWidgetItems('products', 'items: ' . $packageIds, $packageType);

            if ($result) {
                $category = ['kind' => $packageType, 'title' => $name_widget];
                $list = $result['items'];
            }
            else {
                $category = [];
                $list = [];
            }

            if (!$category) {
                return '';
            }
        }
        else {
            return '';
        }
        $widgetStyle = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'default');
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $showCoupon = (isset($content->show_coupon) && $content->show_coupon == 'yes' ? true : false);
        $carouselDataBody = '';
        $carouselDataHeader = '';

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="no" data-autoplay="no" data-pause="yes" data-loop="no" data-row="no" data-rows="' . htmlspecialchars(Utility::jencode(['xl' => 1, 'lg' => 1, 'md' => 1, 'sm' => 1, 'xs' => 1]), ENT_QUOTES, 'UTF-8') . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-asnavfor="#ctHeaderSlide' . $widgetId . ',#ctBodySlide' . $widgetId . '"';
            $carouselDataBody = $carouselData . ' data-arrows="no"';
            $carouselDataHeader = $carouselData . ' data-arrows="' . $content->arrows . '"';
        }
        if (isset($category['kind']) && $category['kind'] == 'special') {
            $categortKind = $this->getCategory($category['id'], 'products', 'special');
            $categoryKindId = $categortKind['kind_id'] ?? ($categortKind['kind_id'] ?? 0);

            if ($categoryKindId) {
                $categoryCoupon = $this->couponCheck('category', $category['kind'], [$categoryKindId . '/' . $category['id']]);
            }
            else {
                $categoryCoupon = $this->couponCheck('category', $category['kind'], [$category['id']]);
            }
        }
        else {
            $categoryCoupon = $this->couponCheck('category', $category['kind'], [$category['id']]);
        }

        $productCoupons = [];
        $output = '';
        if (isset($list) && $list) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-comparison-widget  ' . $content->fon_class . '">';
            $output .= '<div class="fon-widget-content">';
            $allFeatures = [];
            $features = [];
            $periods = [];

            foreach ($list as $key => $product) {
                foreach ($product['prices'] as $spkey => $spprice) {
                    $periods[$spkey] = $spprice['time'] . ' ' . ___('date/period-' . $spprice['period']);
                }

                $featuresJson = true;
                if (isset($category['kind']) && $category['kind'] == 'special') {
                    $productCoupon = $this->couponCheck('product', $product['type'], [$categoryKindId, $product['id']]);
                }
                else {
                    $productCoupon = $this->couponCheck('product', $product['type'], [$category['id'], $product['id']]);
                }

                if ($productCoupon) {
                    $productCoupons[$product['id']] = $productCoupon;
                }

                $productFeatures = (self::isJSON($product['features']) ? Utility::jdecode($product['features'], true) : $product['features']);
                if (!is_array($productFeatures) && $productFeatures) {
                    $featuresJson = false;
                    $productFeatures = preg_split('/\\r\\n|\\r|\\n/', $productFeatures);
                }

                if (isset($productFeatures['features'])) {
                    if (count($features) < count($productFeatures['features'])) {
                        $features = $productFeatures['features'];
                    }

                    $allFeatures[$product['id']] = $productFeatures;
                    if (($catType == 'server') && $product['options']) {
                        $arrayFeature = [];

                        foreach (['processor', 'ram', 'disk-space', 'bandwidth', 'raid'] as $key) {
                            if (isset($product['options'][$key])) {

                                $arrayFeature[$key] = ['name' => match ($key) {
                                    processor => __('website/products/server-list-processor'),
                                    ram => __('website/products/server-list-ram'),
                                    disk-space => __('website/products/server-list-disk'),
                                    bandwidth => __('website/products/server-list-bandwidth'),
                                    raid => __('website/products/server-list-raid')
                                }, 'desc' => '', 'icon' => match ($key) {
                                    processor => 'fa-solid fa-microchip',
                                    ram => 'fa-solid fa-memory',
                                    disk-space => 'fa-solid fa-hard-drive',
                                    bandwidth => 'fa-solid fa-gauge-high',
                                    raid => 'fa-solid fa-server'
                                }, 'type' => 'text', 'text' => $product['options'][$key], 'exist' => true];
                            }
                        }

                        if (isset($product['options_lang']['location'])) {
                            $country = '-';
                            $code = NULL;

                            if ($product['options_lang']['location'] != '') {
                                if (strpos($product['options_lang']['location'], '-') !== false) {
                                    $parts = explode('-', $product['options_lang']['location']);
                                    $country = $parts[0];
                                    $code = end($parts);
                                }
                                else {
                                    $country = $product['options_lang']['location'];
                                    $code = NULL;
                                }
                            }

                            $arrayFeature['location'] = ['name' => __('website/products/server-list-location'), 'desc' => '', 'icon' => 'fa-solid fa-location-dot', 'type' => 'text', 'text' => ($code ? '<i class="flag flag-xs rounded-1 flag-country-' . strtolower($code) . ' me-1"></i>' . $country : $country), 'exist' => true];
                        }

                        if ($arrayFeature) {
                            $allFeatures[$product['id']]['features'] = array_merge($arrayFeature, $allFeatures[$product['id']]['features']);
                            $features = array_merge($arrayFeature, $features);
                        }
                    }
                }
                else if (is_array($productFeatures) && $catType == 'special' && isset($category['options_lang']['columns']) && $category['options_lang']['columns']) {
                    $features = [];

                    foreach ($category['options_lang']['columns'] as $column) {
                        $columnVal = $productFeatures[$column['id']] ?? NULL;
                        $columnFeature = ['name' => $column['name'], 'desc' => '', 'icon' => '', 'type' => 'text', 'text' => $columnVal];
                        $features[] = $columnFeature;
                        $allFeatures[$product['id']]['features'][] = $columnFeature;
                    }
                }
                else if (is_array($productFeatures) && $productFeatures) {
                    $features = [];

                    foreach ($productFeatures as $pf) {
                        $arrayFeature = ['name' => $pf, 'desc' => '', 'icon' => '', 'type' => 'select', 'text' => '', 'exist' => true];
                        $features[] = $arrayFeature;
                        $allFeatures[$product['id']]['features'][] = $arrayFeature;
                    }
                }
                else if (($catType == 'server') && $product['options']) {
                    $arrayFeature = [];

                    foreach (['processor', 'ram', 'disk-space', 'bandwidth', 'raid'] as $key) {
                        if (isset($product['options'][$key])) {

                            $arrayFeature[$key] = ['name' => match ($key) {
                                processor => __('website/products/server-list-processor'),
                                ram => __('website/products/server-list-ram'),
                                disk-space => __('website/products/server-list-disk'),
                                bandwidth => __('website/products/server-list-bandwidth'),
                                raid => __('website/products/server-list-raid')
                            }, 'desc' => '', 'icon' => match ($key) {
                                processor => 'fa-solid fa-microchip',
                                ram => 'fa-solid fa-memory',
                                disk-space => 'fa-solid fa-hard-drive',
                                bandwidth => 'fa-solid fa-gauge-high',
                                raid => 'fa-solid fa-server'
                            }, 'type' => 'text', 'text' => $product['options'][$key], 'exist' => true];
                        }
                    }

                    if (isset($product['options_lang']['location'])) {
                        $arrayFeature['location'] = ['name' => __('website/products/server-list-location'), 'desc' => '', 'icon' => 'fa-solid fa-location-dot', 'type' => 'text', 'text' => $product['options_lang']['location'], 'exist' => true];
                    }

                    $allFeatures[$product['id']] = ['features' => $arrayFeature];

                    if (empty($features)) {
                        $features = $arrayFeature;
                    }
                }
            }

            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'comparison' . DS . 'style_' . $widgetStyle . '.php';
            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function content_box_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $title_color = (isset($content->title_color) && $content->title_color ? $content->title_color : '');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : '');
        $desc_color = (isset($content->description_color) && $content->description_color ? $content->description_color : '');
        $desc_font = (isset($content->desc_font) && $content->desc_font ? $content->desc_font : '');
        $icon_color = (isset($content->icon_color) && $content->icon_color ? $content->icon_color : '');
        $icon_bg_color = (isset($content->icon_bg_color) && $content->icon_bg_color ? $content->icon_bg_color : '');
        $icon_class = (isset($content->icon_class) && $content->icon_class ? $content->icon_class : '');
        $item_class = (isset($content->item_class) && $content->item_class ? $content->item_class : '');
        $image_width = (isset($content->image_width) && $content->image_width ? $content->image_width : '');
        $style = '';
        if ($title_color || $desc_color || $icon_color || $icon_bg_color) {
            $style .= '#' . $widgetId . '.fon-content-box-widget{';

            if ($title_color) {
                $style .= '--title-color: ' . $title_color . ';';
            }

            if ($desc_color) {
                $style .= '--desc-color: ' . $desc_color . ';';
            }

            if ($icon_color) {
                $style .= '--icon-color: ' . $icon_color . ';';
            }

            if ($icon_bg_color) {
                $style .= '--icon-bg-color: ' . $icon_bg_color . ';';
            }

            $style .= '}';
        }
        if ($title_font || $desc_font) {
            if ($title_font) {
                $style .= '#' . $widgetId . ' .fon-contentbox-title{';
                $style .= self::parseFontProperties($title_font);
                $style .= '}';
            }

            if ($desc_font) {
                $style .= '#' . $widgetId . ' .fon-contentbox-content{';
                $style .= self::parseFontProperties($desc_font);
                $style .= '}';
            }
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = 'd-flex ';

        if ($content->media_position == 'top') {
            $attributes .= 'flex-column justify-content-center ';

            switch ($content->align) {
            case 'left':
                $attributes .= 'align-items-start text-start';
                break;
            case 'right':
                $attributes .= 'align-items-end text-end';
                break;
            case 'center':
                $attributes .= 'align-items-center text-center';
                break;
            }
        }
        else {
            if ($content->media_position == 'left') {
                $attributes .= 'justify-content-start text-start ';
            }
            else if ($content->media_position == 'right') {
                $attributes .= 'justify-content-end text-end ';
            }
            if (isset($content->vertical_align) && $content->vertical_align) {
                switch ($content->vertical_align) {
                case 'top':
                    $attributes .= 'align-items-start';
                    break;
                case 'bottom':
                    $attributes .= 'align-items-end';
                    break;
                case 'center':
                    $attributes .= 'align-items-center';
                    break;
                }
            }
        }

        $carouselData = '';
        $isCarousel = false;

        if ($content->use_carousel == 'yes') {
            $isCarousel = true;
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel contentbox-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl : '');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-content-box-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<div class="' . $containerClass . '" ' . $carouselData . '>';

        if ($content->items) {
            $cicount = 1;

            foreach ($content->items as $contentBox) {
                $show_icon = isset($contentBox->show_button_icon) && $contentBox->show_button_icon = ('yes' ? true : false);
                $link_icon = (isset($contentBox->button_icon) && $contentBox->button_icon ? $contentBox->button_icon : '');
                $link_target = (isset($contentBox->link_target) && $contentBox->link_target ? $contentBox->link_target : '_self');
                $link_icon_position = (isset($contentBox->button_icon_position) && $contentBox->button_icon_position ? $contentBox->button_icon_position : 'right');
                $contentBoxImage = '';

                if (is_object($contentBox->image)) {
                    $contentBoxImage = (isset($contentBox->image->{$this->lang}) && $contentBox->image->{$this->lang} ? $contentBox->image->{$this->lang} : array_values((array) $contentBox->image)[0] ?? '');
                }
                else if (is_string($contentBox->image)) {
                    $contentBoxImage = $contentBox->image;
                }

                $contentBox->image = ($contentBoxImage ? static::assetLinkDetermine($contentBoxImage) : $lazyPlaceholder);
                $imageDimensions = static::getImageDimensions($contentBox->image, $pageData['badress']);
                $content_box_title = (isset($contentBox->content_box_title->{$this->lang}) && $contentBox->content_box_title->{$this->lang} ? $contentBox->content_box_title->{$this->lang} : array_values((array) $contentBox->content_box_title)[0] ?? '');
                $content_box_title = self::getPriceHolders($content_box_title);
                $content_box_content = (isset($contentBox->content_box_content->{$this->lang}) && $contentBox->content_box_content->{$this->lang} ? $contentBox->content_box_content->{$this->lang} : array_values((array) $contentBox->content_box_content)[0] ?? '');
                $content_box_content = self::getPriceHolders($content_box_content);
                $content_box_link_text = (isset($contentBox->link_text->{$this->lang}) && $contentBox->link_text->{$this->lang} ? $contentBox->link_text->{$this->lang} : array_values((array) $contentBox->link_text)[0] ?? '');
                $image_alt = (isset($contentBox->image_alt->{$this->lang}) && $contentBox->image_alt->{$this->lang} ? $contentBox->image_alt->{$this->lang} : (isset($contentBox->image_alt) ? array_values((array) $contentBox->image_alt)[0] ?? '' : ''));
                $image_title = (isset($contentBox->image_title->{$this->lang}) && $contentBox->image_title->{$this->lang} ? $contentBox->image_title->{$this->lang} : (isset($contentBox->image_title) ? array_values((array) $contentBox->image_title)[0] ?? '' : ''));

                if (empty($image_alt)) {
                    if (!empty($content_box_title)) {
                        $image_alt = $content_box_title;
                    }
                    else if (!empty($image_title)) {
                        $image_alt = $image_title;
                    }
                    else {
                        $image_alt = basename($contentBox->image);
                    }
                }

                if (empty($image_title)) {
                    if (!empty($content_box_title)) {
                        $image_title = $content_box_title;
                    }
                    else if (!empty($image_alt)) {
                        $image_title = $image_alt;
                    }
                    else {
                        $image_title = basename($contentBox->image);
                    }
                }
                $link_rel = (isset($contentBox->link_rel) && $contentBox->link_rel ? $contentBox->link_rel : []);
                $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');

                if (!$isCarousel) {
                    $output .= '<div class="col">';
                }

                include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'content_box' . DS . 'style_' . $content->widget_style . '.php';

                if (!$isCarousel) {
                    $output .= '</div>';
                }

                ++$cicount;
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function countdown_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        $style .= '#' . $widgetId . ' .fon-countdown-timer {';
        if (isset($content->background) && $content->background) {
            $style .= '--fon-countdown-background: ' . $content->background . ';';
        }
        if (isset($content->number_size) && $content->number_size) {
            $style .= '--fon-countdown-number-size: ' . $content->number_size . 'px;';
        }
        if (isset($content->number_color) && $content->number_color) {
            $style .= '--fon-countdown-number-color: ' . $content->number_color . ';';
        }
        if (isset($content->text_size) && $content->text_size) {
            $style .= '--fon-countdown-text-size: ' . $content->text_size . 'px;';
        }
        if (isset($content->text_color) && $content->text_color) {
            $style .= '--fon-countdown-text-color: ' . $content->text_color . ';';
        }
        if (isset($content->padding) && $content->padding) {
            $style .= '--fon-countdown-padding: ' . $content->padding . 'px;';
        }
        if (isset($content->margin) && $content->margin) {
            $style .= '--fon-countdown-margin: ' . $content->padding . 'px;';
        }
        if (isset($content->border) && $content->border) {
            $style .= '--fon-countdown-border: ' . $content->border . ';';
        }
        if (isset($content->radius) && $content->radius) {
            $style .= '--fon-countdown-radius: ' . $content->radius . 'px;';
        }
        if (isset($content->shadow) && $content->shadow) {
            $style .= '--fon-countdown-shadow: ' . $content->shadow . ';';
        }
        if (isset($content->gap) && $content->gap) {
            $style .= '--fon-countdown-gap: ' . $content->gap . 'px;';
        }
        if (isset($content->divider_color) && $content->divider_color) {
            $style .= '--fon-countdown-divider-color: ' . $content->divider_color . ';';
        }
        if (isset($content->divider) && $content->divider != 'none') {
            $style .= '--fon-countdown-divider-right: -' . ($content->gap / 2) . 'px;';
        }

        $style .= '}';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = '';

        switch ($content->align) {
        case 'left':
            $attributes = 'justify-content-start text-start';
            break;
        case 'right':
            $attributes = 'justify-content-end text-end';
            break;
        case 'center':
            $attributes = 'justify-content-center text-center';
            break;
        }

        $output = '';
        $dateLangs = ['day' => ___('date/day'), 'hour' => ___('date/hour'), 'minute' => ___('date/minute'), 'second' => ___('date/second')];
        $dateString = $content->date . ' ' . $content->time . ':00';
        $dateString = date('Y/m/d H:i:s', strtotime($dateString));
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-countdown ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<div class="fon-countdown-timer ' . $attributes . ' divider-' . $content->divider . '  text-position-' . $content->text_position . '" data-enddate="' . $dateString . '" data-lang="' . htmlentities(json_encode($dateLangs), ENT_QUOTES, 'UTF-8') . '" data-message="' . strip_tags($content->message) . '"></div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function cost_calculator_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $class = (isset($content->fon_class) && $content->fon_class ? $content->fon_class : '');
        $show_title = (isset($content->show_name) && $content->show_name == 'yes' ? true : false);
        $title = __('website/account_sms/introduction-calculate-title');

        if ($show_title) {
            $title = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : $title);
        }

        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="card fon-cost-calculator rounded-4 text-center international-sms-calculate ' . $class . '">';
        $output .= '<div class="card-header bg-white py-3">';
        $output .= '<h3 class="card-title fs-5 fw-semibold text-theme-secondary mb-0">' . $title . '</h3>';
        $output .= '</div>';
        $output .= '<div class="card-body" style="background: url(' . $pageData['tadress'] . 'images/map.svg) no-repeat scroll center;">';
        $output .= '<select id="countries" class="form-select">';
        $output .= '<option value="">' . __('website/account_sms/introduction-calculate-select-country') . '</option>';

        foreach ($pageData['country_prices'] as $country) {
            $cc = $country['cc'];
            $prices = $country['prices'];
            $output .= '<option ' . ($cc == $pageData['default_country'] ? 'selected' : '') . "\n" . '                                value="' . $cc . '"' . "\n" . '                                data-prices=\'' . Utility::jencode($prices) . '\'' . "\n" . '                                data-pre-register="' . ($country['pre-register'] ? 'true' : 'false') . '"' . "\n" . '                                data-image="' . $pageData['sadress'] . 'assets/images/flags/' . $cc . '.svg' . '">' . $country['name'] . ' </option>';
        }

        $output .= '</select>';
        $output .= '<div id="calculateResult" style="display: none;">';
        $output .= '<p class="my-4">' . __('website/account_sms/introduction-calculate-note') . ' </p>';
        $currs = [];
        $defCurr = '';
        $currencies = [];

        foreach (Money::getCurrencies() as $row) {
            if ($row['id'] == $pageData['ucid']) {
                array_unshift($currencies, $row);
            }
            else {
                array_push($currencies, $row);
            }
        }

        $output .= '<div class="d-flex justify-content-center flex-wrap gap-2 mb-3">';

        foreach ($currencies as $curr) {
            $currs[] = $curr['code'];

            if ($curr['id'] == $pageData['ucid']) {
                $defCurr = $curr['code'];
            }

            $output .= '<a id="currency-button-' . $curr['code'] . ' " class="' . ($curr['id'] == $pageData['ucid'] ? 'active ' : '') . '  btn btn-outline-primary currency-button" href="javascript:setCurrency(\'' . $curr['code'] . '\');void(0);">' . $curr['code'] . ' </a>';
        }

        $output .= '</div>';
        $output .= '<h3 id="country-name">?</h3>';
        $output .= '<h4 class="fs-5">';

        foreach ($currs as $curr) {
            $output .= '<span id="currency-' . $curr . '" ' . ($defCurr == $curr ? '' : 'style="display: none;"') . '  class="currency-content">' . "\n" . '                            1 SMS = <span id="calculate-' . $curr . '-amount">0</span> <span style="font-size:20px;">' . $curr . '</span><br>' . "\n" . '                            <span class="amount-thousands">(1000 SMS = <span id="calculate-' . $curr . '-amount-thousands">0</span> ' . $curr . ' )</span>' . "\n" . '                            </span>';
        }

        $output .= '</h2>';
        $output .= '<div class="fs-12" id="country_pre_register">' . __('website/account_sms/introduction-calculate-pre-register-note') . ' </div>';
        $output .= '<input type="hidden" id="defCurrency" value="' . $defCurr . ' ">';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '<div class="card-footer bg-white d-grid">';
        $output .= '<a class="btn btn-secondary btn-lg" href="' . $pageData['download_prices'] . ' /' . $defCurr . ' " id="download_prices" target="_blank">' . __('website/account_sms/introduction-download-prices') . ' </a>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'default');
        $slogan = (isset($content->slogan) && $content->slogan ? (array) $content->slogan : [$this->lang => __('website/domain/slogan', ['{price}' => '{{domain:com:register}}'])]);
        $show_ai = (isset($content->show_ai) && $content->show_ai == 'yes' ? true : false);
        $ai_button_title = self::getFieldMultilingualText($content->ai_button_title, $this->lang, __('theme/domain/ai_button_title'));
        $classic_button_title = self::getFieldMultilingualText($content->classic_button_title, $this->lang, __('theme/domain/classic_button_title'));
        $contentTitle = self::getFieldMultilingualText($content->title, $this->lang, '');
        $button_text = self::getFieldMultilingualText($content->button_text, $this->lang, __('website/index/domain-check-query-button'));
        $tld_title = self::getFieldMultilingualText($content->tld_title, $this->lang, __('website/domain/meta/title'));
        $tld_register = self::getFieldMultilingualText($content->tld_register, $this->lang, __('admin/orders/create-domain-transaction-register'));
        $input_placeholders = self::getFieldMultilingualText($content->input_placeholders, $this->lang, __('theme/domain/input_placeholders'));

        if ($input_placeholders) {
            $input_placeholders = (!is_array($input_placeholders) ? explode(PHP_EOL, $input_placeholders) : $input_placeholders);
        }
        else {
            $input_placeholders = __('theme/domain/input_placeholders');
        }

        $input_placeholders = htmlspecialchars(json_encode($input_placeholders, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $assets = ['type-placeholder'];

        if ($show_ai) {
            $assets[] = 'fon-ai-domain-suggest';
            $aiConfig = Modules::Config('Addons', 'FonPageBuilder');
            if (isset($aiConfig['ai']['tlds']) && $aiConfig['ai']['tlds']) {
                $aiTlds = (is_string($aiConfig['ai']['tlds']) ? explode(',', $aiConfig['ai']['tlds']) : $aiConfig['ai']['tlds']);
                $aiTlds = array_map('trim', $aiTlds);
            }
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' && $content->show_tlds == 'yes' ? true : false);
        $carouselData = '';

        if ($isCarousel) {
            $assets[] = 'slick';
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
        }

        $this->addAsset($assets);
        $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
        $form_action = (isset($pageData['domain']) && $pageData['domain']['tlds'] ? $pageData['domain']['form_action'] : Controllers::$init->CRLink('domain'));

        if ($content->show_tlds == 'yes') {
            $spotlights = ($pageData['page'] == 'index' ? ___('blocks/home-domain-check/items', false, $this->lang) : __('website/domain/spotlight-tlds', false, $this->lang));
            if (is_array($spotlights) && !empty($spotlights)) {
                $wherein = implode('\',\'', $spotlights);
                $tlds = self::getTldList($wherein);
            }
            else {
                $tlds = [];
            }

            if ($tlds) {
                $firstPrice = self::getPriceHolders($slogan[$this->lang]);
            }
        }
        else if ($content->show_slogan) {
            $firstPrice = self::getPriceHolders($slogan[$this->lang]);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-widget ' . $content->fon_class . ' ' . ($show_ai ? 'domain-ai-enabled' : '') . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain' . DS . 'style_' . $widget_style . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_form_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $firstPrice = (isset($pageData['domain']['firstPrice']) ? $pageData['domain']['firstPrice'] : '');
        $box_tldList = (isset($pageData['domain']['tlds']) ? $pageData['domain']['tlds'] : false);
        $tldList = (isset($pageData['domain']['tldList']) ? $pageData['domain']['tldList'] : false);
        $tldList = ($tldList ? $tldList : self::getTldList());
        $captcha = (isset($pageData['domain']['captcha']) ? $pageData['domain']['captcha'] : false);
        $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
        $formAction = (isset($pageData['domain']['form_action']) ? $pageData['domain']['form_action'] : Controllers::$init->CRLink('domain'));
        $register_link = Controllers::$init->CRLink('domain');
        $transfer_link = Controllers::$init->CRLink('domain-transfer');
        $whois_link = Controllers::$init->CRLink('domain-whois');
        $show_ai = (isset($content->show_ai) && $content->show_ai == 'yes' ? true : false);
        $ai_button_title = self::getFieldMultilingualText($content->ai_button_title, $this->lang, __('theme/domain/ai_button_title'));
        $classic_button_title = self::getFieldMultilingualText($content->classic_button_title, $this->lang, __('theme/domain/classic_button_title'));
        $form_type = (isset($content->form_type) && $content->form_type ? $content->form_type : 'domain');
        $form_title = self::getFieldMultilingualText($content->form_title, $this->lang, '');
        $form_description = (isset($content->form_description->{$this->lang}) && $content->form_description->{$this->lang} ? self::getPriceHolders($content->form_description->{$this->lang}) : __('website/domain/slogan', ['{price}' => $firstPrice]));
        $form_align = (isset($content->form_align) && $content->form_align ? $content->form_align : (object) ['xl' => 'center', 'lg' => 'center', 'md' => 'center', 'sm' => 'center', 'xs' => 'center']);
        $show_tlds = (isset($content->show_tlds) && $content->show_tlds == 'yes' ? true : false);
        $widgetTlds = (isset($content->tld_list) && $content->tld_list != 'none' ? explode(',', trim(str_replace('items:', '', $content->tld_list))) : false);
        $show_register = (isset($content->show_register) && $content->show_register == 'yes' ? true : false);
        $register_title = self::getFieldMultilingualText($content->register_title, $this->lang, __('theme/domain/register-title'));
        $show_transfer = (isset($content->show_transfer) && $content->show_transfer == 'yes' ? true : false);
        $transfer_title = self::getFieldMultilingualText($content->transfer_title, $this->lang, __('theme/domain/transfer-title'));
        $show_whois = (isset($content->show_whois) && $content->show_whois == 'yes' ? true : false);
        $whois_title = self::getFieldMultilingualText($content->whois_title, $this->lang, __('theme/domain/whois-title'));
        $show_captcha = (isset($content->show_captcha) && $content->show_captcha == 'yes' ? true : false);
        $input_placeholders = self::getFieldMultilingualText($content->input_placeholders, $this->lang, __('theme/domain/input_placeholders'));

        if ($input_placeholders) {
            $input_placeholders = (!is_array($input_placeholders) ? explode(PHP_EOL, $input_placeholders) : $input_placeholders);
        }
        else {
            $input_placeholders = __('theme/domain/input_placeholders');
        }

        $input_placeholders = htmlspecialchars(json_encode($input_placeholders, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8');
        $alignClass = '';
        $justifyClass = '';

        foreach ($form_align as $key => $align) {
            $alignClass .= ($key == 'xs' ? 'text-' : 'text-' . $key . '-');
            $justifyClass .= ($key == 'xs' ? 'justify-content-' : 'justify-content-' . $key . '-');

            if ($align == 'left') {
                $alignClass .= 'start ';
                $justifyClass .= 'start ';
            }
            else if ($align == 'right') {
                $alignClass .= 'end ';
                $justifyClass .= 'end ';
            }
            else {
                $alignClass .= 'center ';
                $justifyClass .= 'center ';
            }
        }

        $style = '';
        $style .= '#' . $widgetId . ' .fon-domain-form-title{';
        if (isset($content->form_title_color) && $content->form_title_color) {
            $style .= 'color: ' . $content->form_title_color . ';';
        }
        if (isset($content->form_title_font) && $content->form_title_font) {
            $style .= self::parseFontProperties($content->form_title_font);
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-domain-form-description{';
        if (isset($content->form_description_color) && $content->form_description_color) {
            $style .= 'color: ' . $content->form_description_color . ';';
        }
        if (isset($content->form_description_font) && $content->form_description_font) {
            $style .= self::parseFontProperties($content->form_description_font);
        }

        $style .= '}';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        if ($show_ai) {
            $this->addAsset(['type-placeholder', 'fon-ai-domain-suggest']);
            $aiConfig = Modules::Config('Addons', 'FonPageBuilder');
            if (isset($aiConfig['ai']['tlds']) && $aiConfig['ai']['tlds']) {
                $aiTlds = (is_string($aiConfig['ai']['tlds']) ? explode(',', $aiConfig['ai']['tlds']) : $aiConfig['ai']['tlds']);
                $aiTlds = array_map('trim', $aiTlds);
            }
        }
        else {
            $this->addAsset('type-placeholder');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-form-widget ' . $form_type . ' ' . $content->fon_class . ' ' . ($show_ai ? 'domain-ai-enabled' : '') . '">';
        $output .= '<div class="fon-widget-content ' . $alignClass . '">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain_form' . DS . $form_type . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_tlds_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $currency_symbols = (isset($pageData['currency_symbols']) ? $pageData['currency_symbols'] : self::getCurrencySymbols());
        $tldList = (isset($pageData['domain']['tldList']) ? $pageData['domain']['tldList'] : false);
        $tldList = ($tldList ? $tldList : self::getTldList());
        $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'default');
        $widgetTlds = (isset($content->tld_list) && $content->tld_list != 'none' ? explode(',', trim(str_replace('items:', '', $content->tld_list))) : false);
        $tld_limit = (isset($content->tld_limit) && $content->tld_limit ? $content->tld_limit : 10);
        $tld_price_type = (isset($content->tld_price_type) && $content->tld_price_type ? $content->tld_price_type : 'register');
        $show_images = (isset($content->tld_images) && $content->tld_images == 'yes' ? true : false);
        $show_register = (isset($content->show_register) && $content->show_register == 'yes' ? true : false);
        $register_link = (isset($content->register_link) && $content->register_link ? $content->register_link : Controllers::$init->CRLink('domain'));
        $register_title = (isset($content->register_title->{$this->lang}) && $content->register_title->{$this->lang} ? $content->register_title->{$this->lang} : __('theme/domain/register-title'));
        $inline_register = false;
        if (strpos($register_link, 'http://') === false || strpos($register_link, 'https://') === false) {
            $inline_register = true;
        }
        $show_transfer = (isset($content->show_transfer) && $content->show_transfer == 'yes' ? true : false);
        $transfer_link = Controllers::$init->CRLink('domain-transfer');
        $transfer_title = (isset($content->transfer_title->{$this->lang}) && $content->transfer_title->{$this->lang} ? $content->transfer_title->{$this->lang} : __('theme/domain/transfer-title'));
        $show_slogan = (isset($content->show_slogan) && $content->show_slogan == 'yes' ? true : false);
        $tld_slogan = (isset($content->tld_slogan->{$this->lang}) && $content->tld_slogan->{$this->lang} ? $content->tld_slogan->{$this->lang} : __('website/domain/slogan'));
        $column = (isset($content->column) && $content->column ? $content->column : (object) ['xl' => 5, 'lg' => 4, 'md' => 3, 'sm' => 2, 'xs' => 1]);
        $row = (isset($content->row) && $content->row ? $content->row : (object) ['xl' => 1, 'lg' => 1, 'md' => 1, 'sm' => 1, 'xs' => 1]);
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $carouselData = '';
        $columns = [];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-row="' . $content->use_row . '" data-rows="' . htmlspecialchars(Utility::jencode($row, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel spotlight-tld-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl;
        }

        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-tlds-widget ' . $content->fon_class . '">';
        $output .= '<div class="spot-tld-list tld-image ' . $containerClass . '" ' . $carouselData . '  id="spot-tld-lists">';
        $count = 1;

        foreach ($tldList as $tld) {
            if ($widgetTlds && !in_array($tld['id'], $widgetTlds)) {
                continue;
            }
            if (!$widgetTlds && $tld_limit < $count) {
                break;
            }

            $tld_image = false;

            if ($show_images) {
                foreach (['svg', 'png', 'jpg'] as $ext) {
                    $img_path = 'images' . DS . 'tldlogos' . DS . $tld['name'] . '.' . $ext;

                    if (file_exists(View::$init->get_template_dir() . $img_path)) {
                        $tld_image = $img_path;
                        $imageDimensions = static::getImageDimensions($pageData['tadress'] . $img_path, $pageData['badress']);
                    }
                }
            }
            if ($tld['promo_status'] && (substr($tld['promo_duedate'], 0, 4) == '1881') || DateManager::strtotime() < DateManager::strtotime($tld['promo_duedate'] . ' 23:59:59')) {
                if (0 < $tld['promo_register_price']) {
                    if (0 < $tld['reg_price']['amount']) {
                        $tld['reg_price']['discount'] = round((($tld['reg_price']['amount'] - $tld['promo_register_price']) / $tld['reg_price']['amount']) * 100, 2);
                    }
                    else {
                        $tld['reg_price']['discount'] = 0;
                    }

                    $tld['reg_price']['amount'] = $tld['promo_register_price'];
                }

                if (0 < $tld['promo_transfer_price']) {
                    if (0 < $tld['tra_price']['amount']) {
                        $tld['tra_price']['discount'] = round((($tld['tra_price']['amount'] - $tld['promo_transfer_price']) / $tld['tra_price']['amount']) * 100, 2);
                    }
                    else {
                        $tld['tra_price']['discount'] = 0;
                    }

                    $tld['tra_price']['amount'] = $tld['promo_transfer_price'];
                }
            }

            $registerPrice = self::calculatePrices([$tld['reg_price']], $currency_symbols, $domain_override_uscurrency, 'domain');
            $transferPrice = self::calculatePrices([$tld['tra_price']], $currency_symbols, $domain_override_uscurrency, 'domain');
            $renewPrice = self::calculatePrices([$tld['ren_price']], $currency_symbols, $domain_override_uscurrency, 'domain');

            if ($tld_price_type == 'transfer') {
                $registerPrice = $transferPrice;
            }
            else if ($tld_price_type == 'renew') {
                $registerPrice = $renewPrice;
            }

            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain_tlds' . DS . 'style_' . $widget_style . '.php';
            ++$count;
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_prices_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $currency_symbols = (isset($pageData['currency_symbols']) ? $pageData['currency_symbols'] : self::getCurrencySymbols());
        $tldList = (isset($pageData['domain']['tldList']) ? $pageData['domain']['tldList'] : false);
        $tldList = ($tldList ? $tldList : self::getTldList());
        $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
        $show_search = (isset($content->show_search) && $content->show_search == 'yes' ? true : false);
        $use_pagination = (isset($content->use_pagination) && $content->use_pagination == 'yes' ? true : false);
        $pagination_type = (isset($content->pagination_type) && $content->pagination_type ? $content->pagination_type : 'pagination');
        $pagination_limit = (isset($content->pagination_limit) && $content->pagination_limit ? $content->pagination_limit : 10);
        $page_type = (isset($pageData['page']) ? $pageData['page'] : 'domain');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-prices-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain_prices' . DS . $page_type . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_faqs_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $page_type = (isset($pageData['page']) ? $pageData['page'] : 'domain');
        $faqs = (isset($pageData['domain']['faqs']) ? $pageData['domain']['faqs'] : false);
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'default');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        if ($faqs && is_array($faqs) && count($faqs)) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-faqs-widget ' . $content->fon_class . '">';
            $output .= '<div class="fon-widget-content">';
            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain_faqs' . DS . 'style_' . $widget_style . '.php';
            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function faqs_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $widget_style = 'default';
        $category = (isset($content->category) && $content->category ? $content->category : 'hosting:none');
        list($categoryType, $categoryId) = explode(':', $category);
        $faqs = ___('constants/category-' . $categoryType . '/faq');
        if ($categoryType && $categoryId) {
            if ($categoryId != 'none') {
                $categoryInfo = $this->getCategory($categoryId, 'products', $categoryType);
                if (isset($categoryInfo['faqs']) && !empty($categoryInfo['faqs'])) {
                    $faqs = Utility::jdecode($categoryInfo['faqs'], true);
                }
            }
        }

        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        if ($faqs && is_array($faqs) && count($faqs)) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-' . $categoryType . '-faqs-widget ' . $content->fon_class . '">';
            $output .= '<div class="fon-widget-content">';
            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'faqs' . DS . 'style_' . $widget_style . '.php';
            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function feature_box_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';

        if ($content->widget_style == 'custom') {
            if (($content->media_type != 'icon') && $content->image_width && $content->image_height) {
                $style .= '#' . $widgetId . ' .feature-image{';
                $style .= 'width:' . ($content->image_width && $content->image_width ? $content->image_width . 'px' : '100%') . ';';
                $style .= 'height:' . ($content->image_height && $content->image_height ? $content->image_height . 'px' : 'auto') . ';';
                $style .= '}';
            }

            if ($content->media_type != 'image') {
                $style .= '#' . $widgetId . ' .feature-icon{';
                if (isset($content->icon_size) && $content->icon_size) {
                    $style .= 'font-size:' . $content->icon_size . 'px;';
                    $style .= 'width:' . $content->icon_size . 'px;';
                    $style .= 'height:' . $content->icon_size . 'px;';
                    $style .= 'line-height:' . $content->icon_size . 'px;';
                }
                if (isset($content->icon_color_type) && $content->icon_color_type == 'flat') {
                    $style .= '--bs-normal-color:' . $content->icon_color->normal . ';';
                    $style .= '--bs-hover-color:' . $content->icon_color->hover . ';';
                }
                else if (isset($content->icon_color_type) && $content->icon_color_type == 'gradient') {
                    $style .= self::parseGradient($content->icon_gradient->normal, 'normal-color');
                    $style .= self::parseGradient($content->icon_gradient->hover, 'hover-color');
                }

                $style .= '}';
            }

            $style .= '#' . $widgetId . ' .feature-box-media-container{';
            if (isset($content->media_border->normal) && $content->media_border->normal) {
                $style .= '--bs-normal-border:' . $content->media_border->normal . ';';
            }
            if (isset($content->media_border->hover) && $content->media_border->hover) {
                $style .= '--bs-hover-border:' . $content->media_border->hover . ';';
            }
            if (isset($content->media_radius->normal) && $content->media_radius->normal) {
                $style .= '--bs-normal-radius:' . $content->media_radius->normal . 'px;';
            }
            if (isset($content->media_radius->hover) && $content->media_radius->hover) {
                $style .= '--bs-hover-radius:' . $content->media_radius->hover . 'px;';
            }
            if (isset($content->media_shadow->normal) && $content->media_shadow->normal) {
                $style .= '--bs-normal-shadow:' . $content->media_shadow->normal . ';';
            }
            if (isset($content->media_shadow->hover) && $content->media_shadow->hover) {
                $style .= '--bs-hover-shadow:' . $content->media_shadow->hover . ';';
            }
            if (isset($content->media_background_type) && $content->media_background_type == 'flat') {
                $style .= '--bs-normal-bg:' . $content->media_background->normal . ';';
                $style .= '--bs-hover-bg:' . $content->media_background->hover . ';';
            }
            else if (isset($content->media_background_type) && $content->media_background_type == 'gradient') {
                $style .= self::parseGradient($content->media_gradient->normal, 'normal-bg');
                $style .= self::parseGradient($content->media_gradient->hover, 'hover-bg');
            }
            if (isset($content->media_padding) && $content->media_padding) {
                $style .= 'padding:' . $content->media_padding . ';';
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .feature-box-title, #' . $widgetId . ' .feature-box-title a{';
            if (isset($content->title_color->normal) && $content->title_color->normal) {
                $style .= '--bs-normal-color:' . $content->title_color->normal . ';';
            }
            if (isset($content->title_color->hover) && $content->title_color->hover) {
                $style .= '--bs-hover-color:' . $content->title_color->hover . ';';
            }

            if (isset($content->title_font)) {
                $style .= self::parseFontProperties($content->title_font);
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .feature-box-desc{';
            if (isset($content->content_color->normal) && $content->content_color->normal) {
                $style .= '--bs-normal-color:' . $content->content_color->normal . ';';
            }
            if (isset($content->content_color->hover) && $content->content_color->hover) {
                $style .= '--bs-hover-color:' . $content->content_color->hover . ';';
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .feature-box{';
            if (isset($content->background_type) && $content->background_type == 'flat') {
                $style .= '--bs-normal-bg:' . $content->background->normal . ';';
                $style .= '--bs-hover-bg:' . $content->background->hover . ';';
            }
            else if (isset($content->background_type) && $content->background_type == 'gradient') {
                $style .= self::parseGradient($content->background_gradient->normal, 'normal-bg');
                $style .= self::parseGradient($content->background_gradient->hover, 'hover-bg');
            }
            else if (isset($content->background_type) && $content->background_type == 'image') {
                $style .= 'background:url(' . self::assetLinkDetermine($content->background_image) . ') no-repeat scroll center center / cover;';
            }
            if (isset($content->shadow->normal) && $content->shadow->normal) {
                $style .= '--bs-normal-shadow:' . $content->shadow->normal . ';';
            }
            if (isset($content->shadow->hover) && $content->shadow->hover) {
                $style .= '--bs-hover-shadow:' . $content->shadow->hover . ';';
            }
            if (isset($content->border_radius->normal) && $content->border_radius->normal) {
                $style .= '--bs-normal-radius:' . $content->border_radius->normal . 'px;';
            }
            if (isset($content->border_radius->hover) && $content->border_radius->hover) {
                $style .= '--bs-hover-radius:' . $content->border_radius->hover . 'px;';
            }
            if (isset($content->use_border) && $content->use_border == 'yes') {
                if (isset($content->border->normal) && $content->border->normal) {
                    $style .= '--bs-normal-border:' . $content->border->normal . ';';
                }
                if (isset($content->border->hover) && $content->border->hover) {
                    $style .= '--bs-hover-border:' . $content->border->hover . ';';
                }
            }
            if (isset($content->padding) && $content->padding) {
                $style .= 'padding:' . $content->padding . 'px;';
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = '';

        if ($content->media_position == 'top') {
            $attributes .= 'justify-content-center ';

            switch ($content->align) {
            case 'left':
                $attributes .= 'align-items-start ';
                break;
            case 'right':
                $attributes .= 'align-items-end ';
                break;
            case 'center':
                $attributes .= 'align-items-center ';
                break;
            }
        }
        else {
            if ($content->media_position == 'left') {
                $attributes .= 'justify-content-start ';
            }
            else if ($content->media_position == 'right') {
                $attributes .= 'justify-content-end ';
            }
            if (isset($content->vertical_align) && $content->vertical_align) {
                switch ($content->vertical_align) {
                case 'top':
                    $attributes .= 'align-items-start ';
                    break;
                case 'bottom':
                    $attributes .= 'align-items-end ';
                    break;
                case 'center':
                    $attributes .= 'align-items-center ';
                    break;
                }
            }
        }

        switch ($content->align) {
        case 'left':
            $attributes .= 'text-start';
            break;
        case 'right':
            $attributes .= 'text-end';
            break;
        case 'center':
            $attributes .= 'text-center';
            break;
        }

        if ($content->widget_style != 'custom') {
            if (isset($content->use_shadow) && $content->use_shadow == 'yes') {
                $attributes .= ' with-shadow';
            }
        }

        $image = '';

        if (is_object($content->image)) {
            $image = (isset($content->image->{$this->lang}) && $content->image->{$this->lang} ? $content->image->{$this->lang} : array_values((array) $content->image)[0] ?? '');
        }
        else if (is_string($content->image)) {
            $image = $content->image;
        }

        $content->image = ($image ? static::assetLinkDetermine($image) : $lazyPlaceholder);
        $imageDimensions = static::getImageDimensions($image, $pageData['badress']);
        $content_title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $content_title = self::getPriceHolders($content_title);
        $content_content = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');
        $content_content = self::getPriceHolders($content_content);
        $content_link = (isset($content->link->{$this->lang}) && $content->link->{$this->lang} ? $content->link->{$this->lang} : array_values((array) $content->link)[0] ?? '');
        $content_button_text = (isset($content->button_text->{$this->lang}) && $content->button_text->{$this->lang} ? $content->button_text->{$this->lang} : array_values((array) $content->button_text)[0] ?? '');
        $image_alt = (isset($content->image_alt->{$this->lang}) && $content->image_alt->{$this->lang} ? $content->image_alt->{$this->lang} : (isset($content->image_alt) ? array_values((array) $content->image_alt)[0] ?? '' : ''));
        $image_title = (isset($content->image_title->{$this->lang}) && $content->image_title->{$this->lang} ? $content->image_title->{$this->lang} : (isset($content->image_title) ? array_values((array) $content->image_title)[0] ?? '' : ''));
        $link_rel = (isset($content->link_rel) && $content->link_rel ? $content->link_rel : []);
        $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');

        if (empty($image_alt)) {
            if (!empty($content_title)) {
                $image_alt = $content_title;
            }
            else if (!empty($image_title)) {
                $image_alt = $image_title;
            }
            else {
                $image_alt = basename($content->image);
            }
        }

        if (empty($image_title)) {
            if (!empty($title)) {
                $image_title = $title;
            }
            else if (!empty($image_alt)) {
                $image_title = $image_alt;
            }
            else {
                $image_title = basename($content->image);
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-feature-box-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'feature_box' . DS . 'style_' . $content->widget_style . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function flipbox_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $front_text = (isset($content->front_text) && isset($content->front_text->{$this->lang}) && $content->front_text->{$this->lang} ? $content->front_text->{$this->lang} : (isset($content->front_text) ? array_values((array) $content->front_text)[0] ?? '' : ''));
        $front_align = (isset($content->front_align) && $content->front_align ? $content->front_align : 'center_center');
        $front_text_color = (isset($content->front_text_color) && $content->front_text_color ? $content->front_text_color : '');
        $front_bg_type = (isset($content->front_bg_type) && $content->front_bg_type ? $content->front_bg_type : 'color');
        $front_bg_color = (isset($content->front_bg_color) && $content->front_bg_color ? $content->front_bg_color : '');
        $front_bg_image = (isset($content->front_bg_image) && isset($content->front_bg_image->{$this->lang}) && $content->front_bg_image->{$this->lang} ? $content->front_bg_image->{$this->lang} : (isset($content->front_bg_image) ? array_values((array) $content->front_bg_image)[0] ?? '' : ''));
        $front_bg_image = ($front_bg_image ? static::assetLinkDetermine($front_bg_image) : $lazyPlaceholder);
        $front_bg_gradient = (isset($content->front_bg_gradient) && $content->front_bg_gradient ? $content->front_bg_gradient : '');
        $front_border = (isset($content->front_border) && $content->front_border ? $content->front_border : '');
        $front_radius = (isset($content->front_radius) && $content->front_radius ? $content->front_radius : 0);
        $front_shadow = (isset($content->front_shadow) && $content->front_shadow ? $content->front_shadow : '');
        $back_text = (isset($content->back_text) && isset($content->back_text->{$this->lang}) && $content->back_text->{$this->lang} ? $content->back_text->{$this->lang} : (isset($content->back_text) ? array_values((array) $content->back_text)[0] ?? '' : ''));
        $back_align = (isset($content->back_align) && $content->back_align ? $content->back_align : 'center_center');
        $back_text_color = (isset($content->back_text_color) && $content->back_text_color ? $content->back_text_color : '');
        $back_bg_type = (isset($content->back_bg_type) && $content->back_bg_type ? $content->back_bg_type : 'color');
        $back_bg_color = (isset($content->back_bg_color) && $content->back_bg_color ? $content->back_bg_color : '');
        $back_bg_image = (isset($content->back_bg_image) && isset($content->back_bg_image->{$this->lang}) && $content->back_bg_image->{$this->lang} ? $content->back_bg_image->{$this->lang} : (isset($content->back_bg_image) ? array_values((array) $content->back_bg_image)[0] ?? '' : ''));
        $back_bg_image = ($back_bg_image ? static::assetLinkDetermine($back_bg_image) : $lazyPlaceholder);
        $back_bg_gradient = (isset($content->back_bg_gradient) && $content->back_bg_gradient ? $content->back_bg_gradient : '');
        $back_border = (isset($content->back_border) && $content->back_border ? $content->back_border : '');
        $back_radius = (isset($content->back_radius) && $content->back_radius ? $content->back_radius : 0);
        $back_shadow = (isset($content->back_shadow) && $content->back_shadow ? $content->back_shadow : '');
        $flip_behavior = (isset($content->flip_behavior) && $content->flip_behavior ? $content->flip_behavior : 'hover');
        $flip_style = (isset($content->flip_style) && $content->flip_style ? $content->flip_style : 'rotate');
        $flip_direction = (isset($content->flip_direction) && $content->flip_direction ? $content->flip_direction : 'left');
        $height = (isset($content->height) && $content->height ? $content->height : '280');
        $fon_class = (isset($content->fon_class) && $content->fon_class ? $content->fon_class : '');
        $style = '';

        if (is_object($height)) {
            $responsiveItems = [
                '.fon-flipbox-panel' . ($flip_style == '3d' ? '-3d' : '') => [
                ['type' => 'height', 'unit' => 'px', 'value' => $height]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        else {
            $style .= '#' . $widgetId . ' .fon-flipbox-panel' . ($flip_style == '3d' ? '-3d' : '') . '{';
            $style .= 'height:' . $height . 'px;';
            $style .= '}';
        }

        $style .= '#' . $widgetId . ' .fon-flipbox-front' . ($flip_style == '3d' ? '-3d' : '') . '{';

        if ($front_text_color) {
            $style .= 'color: ' . $front_text_color . ';';
        }

        if ($front_border) {
            $style .= 'border: ' . $front_border . ';';
        }

        if ($front_radius) {
            $style .= 'border-radius: ' . $front_radius . 'px;';
        }

        if ($front_shadow) {
            $style .= 'box-shadow: ' . $front_shadow . ';';
        }

        if ($front_bg_type == 'color') {
            $style .= 'background-color: ' . $front_bg_color . ';';
        }
        else if ($front_bg_type == 'image') {
            $style .= 'background-color: ' . $front_bg_color . ';';
            $style .= 'background-image: url(' . $front_bg_image . ');';
        }
        else if ($front_bg_type == 'gradient') {
            $style .= 'background-color: ' . $front_bg_color . ';';
            $style .= self::parseGradient($front_bg_gradient) . ';';
        }

        switch ($front_align) {
        case 'top_left':
            $style .= 'justify-content: start;';
            $style .= 'text-align: start;';
            break;
        case 'top_center':
            $style .= 'justify-content: start;';
            $style .= 'text-align: center;';
            break;
        case 'top_right':
            $style .= 'justify-content: start;';
            $style .= 'text-align: end;';
            break;
        case 'center_left':
            $style .= 'justify-content: center;';
            $style .= 'text-align: start;';
            break;
        case 'center_center':
            $style .= 'justify-content: center;';
            $style .= 'text-align: center;';
            break;
        case 'center_right':
            $style .= 'justify-content: center;';
            $style .= 'text-align: end;';
            break;
        case 'bottom_left':
            $style .= 'justify-content: end;';
            $style .= 'text-align: start;';
            break;
        case 'bottom_center':
            $style .= 'justify-content: end;';
            $style .= 'text-align: center;';
            break;
        case 'bottom_right':
            $style .= 'justify-content: end;';
            $style .= 'text-align: end;';
            break;
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-flipbox-back' . ($flip_style == '3d' ? '-3d' : '') . '{';

        if ($back_text_color) {
            $style .= 'color: ' . $back_text_color . ';';
        }

        if ($back_border) {
            $style .= 'border: ' . $back_border . ';';
        }

        if ($back_radius) {
            $style .= 'border-radius: ' . $back_radius . 'px;';
        }

        if ($back_shadow) {
            $style .= 'box-shadow: ' . $back_shadow . ';';
        }

        if ($back_bg_type == 'color') {
            $style .= 'background-color: ' . $back_bg_color . ';';
        }
        else if ($back_bg_type == 'image') {
            $style .= 'background-color: ' . $back_bg_color . ';';
            $style .= 'background-image: url(' . $back_bg_image . ');';
        }
        else if ($back_bg_type == 'gradient') {
            $style .= 'background-color: ' . $back_bg_color . ';';
            $style .= self::parseGradient($back_bg_gradient) . ';';
        }

        switch ($back_align) {
        case 'top_left':
            $style .= 'justify-content: start;';
            $style .= 'text-align: start;';
            break;
        case 'top_center':
            $style .= 'justify-content: start;';
            $style .= 'text-align: center;';
            break;
        case 'top_right':
            $style .= 'justify-content: start;';
            $style .= 'text-align: end;';
            break;
        case 'center_left':
            $style .= 'justify-content: center;';
            $style .= 'text-align: start;';
            break;
        case 'center_center':
            $style .= 'justify-content: center;';
            $style .= 'text-align: center;';
            break;
        case 'center_right':
            $style .= 'justify-content: center;';
            $style .= 'text-align: end;';
            break;
        case 'bottom_left':
            $style .= 'justify-content: end;';
            $style .= 'text-align: start;';
            break;
        case 'bottom_center':
            $style .= 'justify-content: end;';
            $style .= 'text-align: center;';
            break;
        case 'bottom_right':
            $style .= 'justify-content: end;';
            $style .= 'text-align: end;';
            break;
        }

        $style .= '}';

        if ($flip_style == '3d') {
            $style .= '#' . $widgetId . ' .fon-flipbox-front-3d .fon-flipbox-inner-3d{';

            switch ($front_align) {
            case 'top_left':
            case 'top_center':
            case 'top_right':
                $style .= 'top: 25px;';
                break;
            case 'center_left':
            case 'center_center':
            case 'center_right':
                $style .= 'top: 50%;';
                $style .= 'transform: translateY(-50%) translateZ(60px)';
                break;
            case 'bottom_left':
            case 'bottom_center':
            case 'bottom_right':
                $style .= 'bottom: 25px;';
                break;
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-flipbox-back-3d .fon-flipbox-inner-3d{';

            switch ($back_align) {
            case 'top_left':
            case 'top_center':
            case 'top_right':
                $style .= 'top: 25px;';
                break;
            case 'center_left':
            case 'center_center':
            case 'center_right':
                $style .= 'top: 50%;';
                $style .= 'transform: translateY(-50%) translateZ(60px)';
                break;
            case 'bottom_left':
            case 'bottom_center':
            case 'bottom_right':
                $style .= 'bottom: 25px;';
                break;
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-flipbox flip-style-' . $flip_style . ' flip-direction-' . $flip_direction . ' flip-on-' . $flip_behavior . ' ' . $fon_class . '">';
        $output .= '<div class="fon-flipbox-panel' . ($flip_style == '3d' ? '-3d' : '') . '">';

        if ($flip_style == '3d') {
            $output .= '<div class="fon-flipbox-3d-item">';
        }

        $output .= '<div class="fon-flipbox-front' . ($flip_style == '3d' ? '-3d' : '') . ' flipbox">';
        $output .= '<div class="fon-flipbox-inner' . ($flip_style == '3d' ? '-3d' : '') . '">';
        $output .= $front_text;
        $output .= '</div>';
        $output .= '</div>';
        $output .= '<div class="fon-flipbox-back' . ($flip_style == '3d' ? '-3d' : '') . ' flipbox">';
        $output .= '<div class="fon-flipbox-inner' . ($flip_style == '3d' ? '-3d' : '') . '">';
        $output .= $back_text;
        $output .= '</div>';
        $output .= '</div>';

        if ($flip_style == '3d') {
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function formbuilder_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $email_addresses = Config::get('contact/email-addresses');
        $to_email = (isset($content->to_email) && $content->to_email ? $content->to_email : $email_addresses[0]);
        $email_subject = (isset($content->email_subject) && $content->email_subject ? $content->email_subject : '');
        $email_body = (isset($content->email_body) && $content->email_body ? $content->email_body : '');
        $hide_labels = (isset($content->hide_labels) && $content->hide_labels == 'yes' ? 1 : 0);
        $hidden_label_class = ($hide_labels ? 'visually-hidden' : '');
        $floating_labels = (isset($content->floating_labels) && $content->floating_labels == 'yes' ? 1 : 0);
        $captcha_status = (isset($content->enable_captcha) && $content->enable_captcha == 'yes' ? 1 : 0);
        $enable_policy = (isset($content->enable_policy) && $content->enable_policy == 'yes' ? 1 : 0);
        $enable_redirect = (isset($content->enable_redirect) && $content->enable_redirect == 'yes' ? 1 : 0);
        $redirect_link = (isset($content->redirect_link->{$this->lang}) && $content->redirect_link->{$this->lang} ? $content->redirect_link->{$this->lang} : '');
        $field_gap = (isset($content->field_gap) && $content->field_gap ? 'g-' . $content->field_gap : 'g-3');
        $required_message = (isset($content->required_message->{$this->lang}) && $content->required_message->{$this->lang} ? $content->required_message->{$this->lang} : __('theme/formbuilder/required_message'));
        $error_message = (isset($content->error_message->{$this->lang}) && $content->error_message->{$this->lang} ? $content->error_message->{$this->lang} : __('theme/formbuilder/error_message'));
        $success_message = (isset($content->success_message->{$this->lang}) && $content->success_message->{$this->lang} ? $content->success_message->{$this->lang} : __('theme/formbuilder/success_message'));
        $button_text = (isset($content->button_text->{$this->lang}) && $content->button_text->{$this->lang} ? $content->button_text->{$this->lang} : array_values((array) $content->button_text)[0] ?? '');
        $button_position = (isset($content->button_position) && $content->button_position ? $content->button_position : 'end');
        if (!$captcha_status && Config::get('options/captcha/status')) {
            $captcha_status = Config::get('options/captcha/status');
        }
        if (!$captcha_status && Config::get('options/BotShield/status')) {
            Helper::Load('BotShield');
            $captcha_status = BotShield::is_blocked('contact');
        }

        if ($captcha_status) {
            Helper::Load('Captcha');
            $captcha = Helper::get('Captcha');
        }

        $style = '';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-label{';
        if (isset($content->label_color) && $content->label_color) {
            $style .= 'color: ' . $content->label_color . ';';
        }
        if (isset($content->label_font) && $content->label_font) {
            $style .= self::parseFontProperties($content->label_font);
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-select, #' . $widgetId . ' .fon-formbuilder-form .form-control {';
        if (isset($content->field_color) && $content->field_color->normal) {
            $style .= 'color: ' . $content->field_color->normal . ';';
        }
        if (isset($content->field_background) && $content->field_background->normal) {
            $style .= 'background-color: ' . $content->field_background->normal . ';';
        }
        if (isset($content->field_border_width) && $content->field_border_width->normal) {
            $style .= 'border-width: ' . $content->field_border_width->normal . 'px;';
        }
        if (isset($content->field_border_color) && $content->field_border_color->normal) {
            $style .= 'border-color: ' . $content->field_border_color->normal . ';';
        }
        if (isset($content->field_border_radius) && 0 < $content->field_border_radius) {
            $style .= 'border-radius: ' . $content->field_border_radius . 'px;';
        }
        if (isset($content->field_padding) && $content->field_padding) {
            $padding = '';
            if (isset($content->field_padding->top) && $content->field_padding->top) {
                $padding .= $content->field_padding->top . 'px ';
            }
            if (isset($content->field_padding->right) && $content->field_padding->right) {
                $padding .= $content->field_padding->right . 'px ';
            }
            if (isset($content->field_padding->bottom) && $content->field_padding->bottom) {
                $padding .= $content->field_padding->bottom . 'px ';
            }
            if (isset($content->field_padding->left) && $content->field_padding->left) {
                $padding .= $content->field_padding->left . 'px ';
            }

            if ($padding) {
                $style .= 'padding: ' . $padding . ';';
            }
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-select:hover,#' . $widgetId . ' .fon-formbuilder-form .form-select:focus, #' . $widgetId . ' .fon-formbuilder-form .form-control:hover, #' . $widgetId . ' .fon-formbuilder-form .form-control:active, #' . $widgetId . ' .fon-formbuilder-form .form-control:focus{';
        if (isset($content->field_color) && $content->field_color->hover) {
            $style .= 'color: ' . $content->field_color->hover . ';';
        }
        if (isset($content->field_background) && $content->field_background->hover) {
            $style .= 'background-color: ' . $content->field_background->hover . ';';
        }
        if (isset($content->field_border_width) && $content->field_border_width->hover) {
            $style .= 'border-width: ' . $content->field_border_width->hover . 'px!important;';
        }
        if (isset($content->field_border_color) && $content->field_border_color->hover) {
            $style .= 'border-color: ' . $content->field_border_color->hover . '!important;';
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-select, #' . $widgetId . ' .fon-formbuilder-form .input-icon .from-control{';
        if (isset($content->field_padding) && $content->field_padding) {
            $padding = 0;
            if (isset($content->field_padding->left) && $content->field_padding->left) {
                $padding = $content->field_padding->left;
            }
            else if (isset($content->field_padding->right) && $content->field_padding->right) {
                $padding = $content->field_padding->right;
            }

            $style .= 'padding-left: ' . ($padding + 30) . 'px;';
        }

        $style .= '}';

        if (!$floating_labels) {
            $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-control:placeholder{';
            if (isset($content->field_placeholder) && $content->field_placeholder->normal) {
                $style .= 'color: ' . $content->field_placeholder->normal . ';';
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-control:hover::placeholder{';
            if (isset($content->field_placeholder) && $content->field_placeholder->hover) {
                $style .= 'color: ' . $content->field_placeholder->hover . ';';
            }

            $style .= '}';
        }
        if (isset($content->radio_color) && $content->radio_color) {
            $style .= '#' . $widgetId . ' .fon-formbuilder-form input[type="radio"].form-check-input:checked{';
            $style .= 'border-color: ' . $content->radio_color . ';';
            $style .= 'background-color: ' . $content->radio_color . ';';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-formbuilder-form input[type="radio"]:hover, #' . $widgetId . ' .fon-formbuilder-form input[type="radio"]:focus{';
            $style .= 'border-color: ' . $content->radio_color . ';';
            $style .= '}';
        }
        if (isset($content->checkbox_color) && $content->checkbox_color) {
            $style .= '#' . $widgetId . ' .fon-formbuilder-form input[type="checkbox"].form-check-input:checked{';
            $style .= 'border-color: ' . $content->checkbox_color . ';';
            $style .= 'background-color: ' . $content->checkbox_color . ';';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-formbuilder-form input[type="checkbox"]:hover,#' . $widgetId . ' .fon-formbuilder-form input[type="checkbox"]:focus{';
            $style .= 'border-color: ' . $content->checkbox_color . ';';
            $style .= '}';
        }

        $style .= '#' . $widgetId . ' .fon-formbuilder-form .input-group .input-group-text{';
        if (isset($content->input_group_color) && $content->input_group_color->normal) {
            $style .= 'color: ' . ($content->input_group_color->normal ?? 'var(--bs-body-color)') . ';';
        }
        if (isset($content->input_group_bg) && $content->input_group_bg->normal) {
            $style .= 'background-color: ' . ($content->input_group_bg->normal ?? 'var(--bs-body-color)') . ';';
        }
        if (isset($content->field_border_width) && $content->field_border_width->normal) {
            $style .= 'border-width: ' . $content->field_border_width->normal . 'px;';
        }
        if (isset($content->field_border_color) && $content->field_border_color->normal) {
            $style .= 'border-color: ' . $content->field_border_color->normal . ';';
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .input-group:hover .input-group-text{';
        if (isset($content->input_group_color) && $content->input_group_color->hover) {
            $style .= 'color: ' . ($content->input_group_color->hover ?? 'var(--bs-body-color)') . ';';
        }
        if (isset($content->input_group_bg) && $content->input_group_bg->hover) {
            $style .= 'background-color: ' . ($content->input_group_bg->hover ?? 'var(--bs-body-color)') . ';';
        }
        if (isset($content->field_border_width) && $content->field_border_width->hover) {
            $style .= 'border-width: ' . $content->field_border_width->hover . 'px!important;';
        }
        if (isset($content->field_border_color) && $content->field_border_color->hover) {
            $style .= 'border-color: ' . $content->field_border_color->hover . '!important;';
        }

        $style .= '}';
        if (isset($content->field_background) && $content->field_background->hover) {
            $style .= '#' . $widgetId . ' form-floating>.form-control-plaintext~label::after, .form-floating>.form-control:focus~label::after, .form-floating>.form-control:not(:placeholder-shown)~label::after, .form-floating>.form-select~label::after {';
            $style .= 'background-color: ' . $content->field_background->hover . ';';
            $style .= '}';
        }

        $style .= "\n" . '            .fon-website-field {' . "\n" . '                opacity: 0;' . "\n" . '                position: absolute;' . "\n" . '                top: 0;' . "\n" . '                left: 0;' . "\n" . '                height: 0;' . "\n" . '                width: 0;' . "\n" . '                z-index: -1;' . "\n" . '                overflow: hidden;' . "\n" . '            }' . "\n" . '        ';

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-formbuilder-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<form class="fon-formbuilder-form row ' . $field_gap . ' needs-validation"  ' . ($enable_redirect && $redirect_link != '' ? 'data-redirect="true" data-redirect-link="' . $redirect_link . '"' : '') . ' method="post" action="' . APP_URI . '/addon/FonPageBuilder" id="fon-' . $moduleId . '" novalidate>';
        if (isset($content->items) && is_array($content->items)) {
            $increated_id = mt_rand(100000, 999999);

            foreach ($content->items as $item_key => $item_value) {
                if ($increated_id === $increated_id) {
                    ++$increated_id;
                }
                $field_type = (isset($item_value->field_type) && $item_value->field_type ? $item_value->field_type : 'text');
                $field_name = (isset($item_value->field_name) && $item_value->field_name ? $item_value->field_name : '');
                $field_title = (isset($item_value->field_title->{$this->lang}) && $item_value->field_title->{$this->lang} ? $item_value->field_title->{$this->lang} : array_values((array) $item_value->field_title)[0] ?? '');
                $field_placeholder = (isset($item_value->field_placeholder->{$this->lang}) && $item_value->field_placeholder->{$this->lang} ? $item_value->field_placeholder->{$this->lang} : array_values((array) $item_value->field_title)[0] ?? '');
                $field_is_required = (isset($item_value->field_is_required) && $item_value->field_is_required == 'yes' ? true : false);
                $field_required_star = (isset($item_value->field_required_star) && $item_value->field_required_star == 'yes' ? true : false);
                $item_name_id = ($field_type ? 'fon-formbuilder-field-' . $item_key . '-' . $moduleId : '');
                $field_number_min = (isset($item_value->field_number_min) && $item_value->field_number_min != '' ? $item_value->field_number_min : '');
                $field_number_max = (isset($item_value->field_number_max) && $item_value->field_number_max ? $item_value->field_number_max : '');
                $field_number_step = (isset($item_value->field_number_step) && $item_value->field_number_step ? $item_value->field_number_step : '');
                $field_height = (isset($item_value->field_height) && $item_value->field_height ? $item_value->field_height . 'px' : '100px');
                $field_is_resize = (isset($item_value->field_is_resize) && $item_value->field_is_resize == 'yes' ? true : false);
                $field_min_character = (isset($item_value->field_min_character) && $item_value->field_min_character ? ' minlength = ' . $item_value->field_min_character : '');
                $field_max_character = (isset($item_value->field_max_character) && $item_value->field_max_character ? ' maxlength = ' . $item_value->field_max_character : '');
                $field_width = (isset($item_value->field_width) && $item_value->field_width ? $item_value->field_width : (object) ['xl=>12', 'lg=>12', 'md=>12', 'sm=>12', 'xs=>12']);
                $field_width_class = 'col-' . $field_width->xs . ' col-sm-' . $field_width->sm . ' col-md-' . $field_width->md . ' col-lg-' . $field_width->lg . ' col-xl-' . $field_width->xl;
                $field_inline = (isset($item_value->field_inline) && $item_value->field_inline == 'yes' ? true : false);
                $field_hide_label = (isset($item_value->field_hide_label) && $item_value->field_hide_label == 'yes' ? true : false);
                $field_show_icon = (isset($item_value->field_show_icon) && $item_value->field_show_icon == 'yes' ? true : false);
                $field_icon = (isset($item_value->field_icon) && $item_value->field_icon ? $item_value->field_icon : '');

                if ($field_type == 'radio') {
                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$field_hide_label) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    $output .= '<div class="fon-formbuilder-radio-content">';
                    if (isset($item_value->field_radio_items) && is_array($item_value->field_radio_items)) {
                        $inner_values = $item_value->field_radio_items;

                        foreach ($inner_values as $inner_item_key => $inner_item_value) {
                            $inner_item_value_title = (isset($inner_item_value->title->{$this->lang}) && $inner_item_value->title->{$this->lang} ? $inner_item_value->title->{$this->lang} : array_values((array) $inner_item_value->title)[0] ?? '');

                            if ($inner_item_value_title) {
                                $output .= '<div class="form-check ' . ($field_inline ? 'form-check-inline' : '') . '">';
                                $inner_item_id = 'fon-form-' . $increated_id . '-radio-' . $inner_item_key;
                                $is_radio_checked = (isset($inner_item_value->is_checked) && $inner_item_value->is_checked == '1' ? true : false);
                                $output .= '<input type="radio" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" id="' . $inner_item_id . '" value="' . $inner_item_value->value . '" class="form-check-input"' . ($is_radio_checked ? ' checked' : '') . '' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                                $output .= '<label for="' . $inner_item_id . '" class="form-check-label">' . $inner_item_value_title . '</label>';
                                $output .= '</div>';
                            }
                        }
                    }

                    $output .= ($field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    $output .= '</div>';
                    $output .= '</div>';
                }
                else if ($field_type === 'checkbox') {
                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$field_hide_label) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    $output .= '<div class="fon-formbuilder-checkbox-content">';
                    if (isset($item_value->field_checkbox_items) && is_array($item_value->field_checkbox_items)) {
                        $inner_values = $item_value->field_checkbox_items;
                        $checkbocFieldName = 'formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']';
                        if (is_array($inner_values) && 1 < count($inner_values)) {
                            $checkbocFieldName .= '[]';
                        }

                        foreach ($inner_values as $inner_item_key => $inner_item_value) {
                            $inner_item_value_title = (isset($inner_item_value->title->{$this->lang}) && $inner_item_value->title->{$this->lang} ? $inner_item_value->title->{$this->lang} : array_values((array) $inner_item_value->title)[0] ?? '');

                            if ($inner_item_value_title) {
                                $output .= '<div class="form-check ' . ($field_inline ? 'form-check-inline' : '') . '">';
                                $inner_item_id = 'fon-form-' . $increated_id . '-checkbox-' . $inner_item_key;
                                $is_checkbox_checked = (isset($inner_item_value->is_checked) && $inner_item_value->is_checked == '1' ? true : false);
                                $output .= '<input type="checkbox" name="' . $checkbocFieldName . '" id="' . $inner_item_id . '" value="' . $inner_item_value->value . '" class="form-check-input ' . (1 < count($inner_values) ? 'multiple' : '') . '"' . ($is_checkbox_checked ? ' checked' : '') . '' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                                $output .= '<label for="' . $inner_item_id . '" class="form-check-label">' . $inner_item_value_title . '</label>';
                                $output .= '</div>';
                            }
                        }
                    }

                    $output .= ($field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    $output .= '</div>';
                    $output .= '</div>';
                }
                else if ($field_type == 'textarea') {
                    $invalidMessage = [];

                    if ($field_is_required) {
                        $invalidMessage[] = __('theme/required_field');
                    }

                    if ($field_min_character != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_min_char'), $item_value->field_min_character);
                    }

                    if ($field_max_character != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_max_char'), $item_value->field_max_character);
                    }

                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '<div class="input-group ' . ($field_is_required ? 'has-validation' : '') . '">';
                        $output .= '<span class="input-group-text"><i class="' . $field_icon . '"></i></span>';
                    }

                    if ($floating_labels) {
                        $output .= '<div class="form-floating">';
                    }
                    $output .= '<textarea name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" id="' . $item_name_id . '" rows="5" class="form-control' . ($field_is_resize ? '' : ' not-resize') . '" placeholder="' . ($field_placeholder && !$floating_labels ? $field_placeholder : $field_title) . '" ' . ($field_is_required ? ' aria-required="true" required' : '') . $field_max_character . $field_min_character . ' style="height:' . $field_height . '"></textarea>';
                    if ($field_title && $floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if (!$floating_labels && $field_is_required || $field_min_character != '' || $field_max_character != '') {
                        $output .= '<div class="invalid-feedback">' . implode(', ', $invalidMessage) . '</div>';
                    }

                    if ($floating_labels) {
                        $output .= '</div>';
                        if ($field_is_required || $field_min_character != '' || $field_max_character != '') {
                            $output .= '<div class="invalid-feedback">' . implode(', ', $invalidMessage) . '</div>';
                        }
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }
                else if ($field_type == 'select') {
                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '<div class="input-group ' . ($field_is_required ? 'has-validation' : '') . '">';
                        $output .= '<span class="input-group-text"><i class="' . $field_icon . '"></i></span>';
                    }

                    if ($floating_labels) {
                        $output .= '<div class="form-floating">';
                    }
                    if (isset($item_value->field_select_items) && is_array($item_value->field_select_items)) {
                        $inner_values = $item_value->field_select_items;
                        $output .= '<select class="form-select" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" id="' . $item_name_id . '"' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                        $output .= ($field_placeholder ? '<option value="">' . $field_placeholder . '</option>' : '');

                        foreach ($inner_values as $inner_item_key => $inner_item_value) {
                            $inner_item_value_title = (isset($inner_item_value->title->{$this->lang}) && $inner_item_value->title->{$this->lang} ? $inner_item_value->title->{$this->lang} : array_values((array) $inner_item_value->title)[0] ?? '');

                            if ($inner_item_value_title) {
                                $is_checked = (isset($inner_item_value->is_checked) && $inner_item_value->is_checked == '1' ? true : false);
                                $output .= '<option value="' . $inner_item_value->value . '"' . ($is_checked ? ' selected' : '') . '>' . $inner_item_value_title . '</option>';
                            }
                        }

                        $output .= '</select>';
                        $output .= (!$floating_labels && $field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    }
                    if ($field_title && $floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    if ($floating_labels) {
                        $output .= '</div>';
                        $output .= ($field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }
                else if ($field_type == 'number') {
                    $invalidMessage = [];

                    if ($field_is_required) {
                        $invalidMessage[] = __('theme/required_field');
                    }

                    if ($field_number_min != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_min'), $field_number_min);
                    }

                    if ($field_number_max != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_max'), $field_number_max);
                    }

                    if ($field_number_step != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_step'), $field_number_step);
                    }

                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '<div class="input-group ' . ($field_is_required ? 'has-validation' : '') . '">';
                        $output .= '<span class="input-group-text"><i class="' . $field_icon . '"></i></span>';
                    }

                    if ($floating_labels) {
                        $output .= '<div class="form-floating">';
                    }
                    $output .= '<input type="number" id="' . $item_name_id . '" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" class="form-control"' . ($field_number_min != '' ? ' min="' . $field_number_min . '"' : '') . '' . ($field_number_max ? ' max="' . $field_number_max . '"' : '') . '' . ($field_number_step ? ' step="' . $field_number_step . '"' : '') . ' placeholder="' . ($field_placeholder && !$floating_labels ? $field_placeholder : $field_title) . '" ' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                    if (!$floating_labels && $field_is_required || $field_number_min != '' || $field_number_max != '' || $field_number_step != '') {
                        $output .= '<div class="invalid-feedback">' . implode(', ', $invalidMessage) . '</div>';
                    }
                    if ($field_title && $floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    if ($floating_labels) {
                        $output .= '</div>';
                        if ($field_is_required || $field_number_min != '' || $field_number_max != '' || $field_number_step != '') {
                            $output .= '<div class="invalid-feedback">' . implode(', ', $invalidMessage) . '</div>';
                        }
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }
                else if ($field_type == 'title') {
                    $font_style = self::parseFontProperties($item_value->heading_font);
                    $item_unique_class = 'fon-formbuilder-heading-' . $item_key;
                    $heading_selector = (isset($item_value->heading_selector) && $item_value->heading_selector ? $item_value->heading_selector : 'h3');
                    $output .= '<' . $heading_selector . ' class="fon-widget-title ' . $item_unique_class . '" style="' . $font_style . '">';
                    $output .= $field_title;
                    $output .= '</' . $heading_selector . '>';
                }
                else {
                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if ($field_show_icon && $field_icon && !in_array($field_type, ['date' => true, 'time' => true, 'date-time' => true, 'tel' => true])) {
                        $output .= '<div class="input-group ' . ($field_is_required ? 'has-validation' : '') . '">';
                        $output .= '<span class="input-group-text"><i class="' . $field_icon . '"></i></span>';
                    }

                    if ($floating_labels) {
                        $output .= '<div class="form-floating">';
                    }

                    if ($field_type == 'tel') {
                        $output .= '<input type="hidden" id="' . $item_name_id . '-hidden" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']"/>';
                        $output .= '<input type="' . $field_type . '" id="' . $item_name_id . '" class="form-control" placeholder="' . ($field_placeholder && !$floating_labels ? $field_placeholder : $field_title) . '" ' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                    }
                    else {
                        $output .= '<input type="' . $field_type . '" id="' . $item_name_id . '" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" class="form-control" placeholder="' . ($field_placeholder && !$floating_labels ? $field_placeholder : $field_title) . '" ' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                    }
                    $output .= (!$floating_labels && $field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    if ($field_title && $floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    if ($floating_labels) {
                        $output .= '</div>';
                        $output .= ($field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    }
                    if ($field_show_icon && $field_icon && !in_array($field_type, ['date' => true, 'time' => true, 'date-time' => true, 'tel' => true])) {
                        $output .= '</div>';
                    }

                    if ($field_type == 'email') {
                        $output .= '<input type="hidden" name="email_field" value="' . $field_name . '" >';
                    }

                    $output .= '</div>';
                }
            }
        }

        $required_fields_list = [];
        if (isset($content->items) && is_array($content->items)) {
            foreach ($content->items as $item) {
                $is_req = isset($item->field_is_required) && $item->field_is_required == 'yes';

                if ($is_req) {
                    $required_fields_list[] = $item->field_name;
                }
            }
        }

        $hidden_fields = ['to_email' => base64_encode($to_email), 'req_fields' => $required_fields_list];
        $hidden_fields_json = json_encode($hidden_fields);
        $hiddenFields = Crypt::encode($hidden_fields_json, Config::get('crypt/system'));
        $salt_key = md5('e5i6t8sev0e3ne2sur6mvpl3tx6oz2608u8llzr8w1czagy0jxff' . $hiddenFields);
        $output .= '<input type="hidden" name="form_features" value="' . $hiddenFields . ':' . $salt_key . '" >';
        $output .= '<input type="hidden" name="form_id" value="fon-' . $moduleId . '">';
        $output .= '<input type="hidden" name="email_subject" value="' . Crypt::encode($email_subject, Config::get('crypt/system')) . '">';
        $output .= '<textarea style="display:none;" name="email_body" aria-label="Not For Read">' . Crypt::encode($email_body, Config::get('crypt/system')) . '</textarea>';
        $output .= '<input type="hidden" name="success_message" value="' . Crypt::encode($success_message, Config::get('crypt/system')) . '">';
        $output .= '<input type="hidden" name="error_message" value="' . Crypt::encode($error_message, Config::get('crypt/system')) . '">';
        $output .= '<input type="hidden" name="module_operation" value="ajax_form_submit">';
        $output .= '<input type="hidden" name="lang" value="' . $this->lang . '">';
        $output .= '<input type="hidden" name="enable_captcha" value="' . $captcha_status . '">';
        $honeypot_name = 'formbuilder_' . md5(uniqid(mt_rand(), true));
        Session::set('formbuilder_honeypot_name', $honeypot_name, true);
        $output .= '<input type="hidden" name="' . $honeypot_name . '" value="">';
        $output .= Validation::get_csrf_token('formbuilder_form');
        $encrypted_time = Crypt::encode(time(), Config::get('crypt/system'));
        $output .= '<input type="hidden" name="form_loaded_at" value="' . $encrypted_time . '">';
        if (isset($captcha) && $captcha) {
            $output .= '<div class="' . ($captcha->input ? 'mb-3' : '') . '">';
            $output .= '<div class="input-group has-validation">';
            $output .= '<span class="input-group-text p-0 border-0 overflow-hidden">' . $captcha->getOutput() . '</span>';

            if ($captcha->input) {
                $output .= '<input name="' . $captcha->input_name . '" type="text"  class="form-control" aria-label="' . ___('needs/form-captcha-label') . '" placeholder="' . ___('needs/form-captcha-label') . '" required>';
                $output .= '<div class="invalid-feedback">' . __('theme/required_field') . '</div>';
            }

            $output .= '</div>';
            $output .= '</div>';
        }
        if ($enable_policy || Config::get('options/gdpr-status')) {
            $output .= '<div class="form-check">';
            $output .= '<input class="form-check-input" type="checkbox" name="policy" id="policy-' . $widgetId . '" value="Yes" aria-required="true" required onchange="if($(this).prop(\'checked\')) {$(\'#fon-btn-' . $moduleId . '\').removeClass(\'disabled\').removeAttr(\'role aria-disabled\')} else {$(\'#fon-btn-' . $moduleId . '\').addClass(\'disabled\').attr({\'role\':\'button\',\'aria-disabled\':\'true\'});}">';
            $output .= '<label class="form-check-label fs-12" for="policy-' . $widgetId . '">' . __('website/account_info/gdpr-tx4', ['{link}' => Controllers::$init->CRLink('contract2')]) . '</label>';
            $output .= '<input type="hidden" value="true" name="is_policy">';
            $output .= '</div>';
        }

        if ($button_text) {
            $output .= '<div class="fon-formbuilder-btn text-' . $button_position . '">';
            $btnProperties = ['is_btn' => true, 'type' => 'submit', 'disabled' => ($enable_policy || Config::get('options/gdpr-status') ? 'true' : 'false')];
            $output .= $this->parseButton($content, $moduleId, $pageData, $btnProperties);
            $output .= '</div>';
        }

        $output .= '<div class="fon-website-field" aria-hidden="true">' . "\n" . '                            <label for="website_control">Website</label>' . "\n" . '                            <input type="text" id="website_control" name="website_control" tabindex="-1" autocomplete="off">' . "\n" . '                        </div>';
        $output .= '</form>';
        $output .= '<div style="display:none;margin-top:10px;" class="fon-formbuilder-ajax-status"></div>';
        $output .= '</div>';
        $output .= '</div>';
        $this->addAsset('intlTelInput');
        $ipInfo = UserManager::ip_info();
        $countryCode = ($ipInfo && isset($ipInfo['countryCode']) ? $ipInfo['countryCode'] : ___('package/code'));
        if (!$countryCode || strlen($countryCode) !== 2) {
            $countryCode = 'TR';
        }
        $captchaJs = (isset($captcha) && $captcha ? $captcha->submit_after_js() : '');
        $selectedLangJs = (Language::selected() == 'tr' ? 'Ara' : 'Search');
        $pendingText = addslashes(__('website/others/button1-pending'));
        $js = '        <script>' . "\n" . '    function ' . $moduleId . '_submit(result){' . "\n" . '        ' . $captchaJs . "\n" . '                if(result != ""){' . "\n" . '                    var solve = typeof result === "string" ? getJson(result) : result;' . "\n" . '                    if(solve !==false && solve != undefined && typeof(solve) == "object"){                        ' . "\n" . '                        if(solve.status == "error"){' . "\n" . '                            if(solve.for != undefined && solve.for != ""){' . "\n" . '                        $("#fon-' . $moduleId . '").removeClass("was-validated");' . "\n" . '                        $("#fon-' . $moduleId . ' " +solve.for).focus();' . "\n" . '                        $("#fon-' . $moduleId . ' " +solve.for).addClass("is-invalid");' . "\n" . '                        $("#fon-' . $moduleId . ' " +solve.for).parent(".form-floating").addClass("is-invalid");' . "\n" . '                        $("#fon-' . $moduleId . ' " +solve.for).change(function(){' . "\n" . '                                    $(this).removeClass("is-invalid");' . "\n" . '                                     $(this).parent(".form-floating").removeClass("is-invalid");' . "\n" . '                                });' . "\n" . '                            }' . "\n" . '                            if(solve.fors != undefined && solve.fors.length > 0){' . "\n" . '                        $("#fon-' . $moduleId . '").removeClass("was-validated");' . "\n" . '                                for (var i = 0; i < solve.fors.length; i++) {' . "\n" . '                            $(\'#fon-' . $moduleId . ' [name="formbuilder[\' +solve.fors[i] + \']"]\').addClass("is-invalid");' . "\n" . '                            $(\'#fon-' . $moduleId . ' [name="formbuilder[\' +solve.fors[i] + \']"]\').parent(".form-floating").addClass("is-invalid");' . "\n" . '                            $(\'#fon-' . $moduleId . ' [name="formbuilder[\' +solve.fors[i] + \']"]\').change(function(){' . "\n" . '                                        $(this).removeClass("is-invalid");' . "\n" . '                                        $(this).parent(".form-floating").removeClass("is-invalid");' . "\n" . '                                    });' . "\n" . '                                }' . "\n" . '                            }' . "\n" . '                            alert_error(solve.message,{timer:3000});' . "\n" . '                        }' . "\n" . '                        else if(solve.status == "success"){ ' . "\n" . '                            alert_success(solve.message,{timer:3000});' . "\n" . '                            setTimeout(function(){' . "\n" . '                                location.reload();' . "\n" . '                            }, 3000);' . "\n" . '                        }' . "\n" . '                    }else {' . "\n" . '                        console.log(result);' . "\n" . '                    }' . "\n" . '                }' . "\n" . '            }' . "\n" . '            ' . "\n" . '            function initAllPhoneInputs() {' . "\n" . '                if (typeof window.intlTelInput !== "function") {' . "\n" . '                    return;' . "\n" . '                }' . "\n" . '                if (window.allPhonesInitialized) return;' . "\n" . '            ' . "\n" . '        const telInputs = document.querySelectorAll(\'input[type="tel"]\');' . "\n" . '                if (telInputs.length === 0) {' . "\n" . '                    return; ' . "\n" . '                }' . "\n" . '                ' . "\n" . '                const object_code = {' . "\n" . '                    geoIpLookup: function (callback) {' . "\n" . '                callback("' . $countryCode . '");' . "\n" . '                    },' . "\n" . '                    autoPlaceholder: "on",' . "\n" . '                    formatOnDisplay: true,' . "\n" . '                    initialCountry: "auto",                   ' . "\n" . '                    nationalMode: false,' . "\n" . '                    placeholderNumberType: "MOBILE",' . "\n" . '                    preferredCountries: ["tr","us", "gb", "ch", "ca", "de", "it"],' . "\n" . '                    showSelectedDialCode: true,' . "\n" . '                    countrySearch: true,' . "\n" . '                    strictMode: true,' . "\n" . '                    i18n: {' . "\n" . '                        tr: "Türkiye",' . "\n" . '                searchPlaceholder: "' . $selectedLangJs . '"' . "\n" . '                    },' . "\n" . '                    useFullscreenPopup: false,' . "\n" . '            utilsScript: "' . $pageData['tadress'] . 'js/intltelinput/js/utils.js"' . "\n" . '                };' . "\n" . '                telInputs.forEach(function(input) {' . "\n" . '                if (input.getAttribute("data-intl-initialized") === "true") return;' . "\n" . '                ' . "\n" . '                input.setAttribute("data-intl-initialized", "true");' . "\n" . '            ' . "\n" . '                const iti = window.intlTelInput(input, object_code);' . "\n" . '                ' . "\n" . '                if (iti.promise) {' . "\n" . '                    iti.promise.then(() => {' . "\n" . '                        const hiddenInputId = input.id + "-hidden";' . "\n" . '                        const hiddenInput = document.getElementById(hiddenInputId);' . "\n" . '            ' . "\n" . '                        const updateHidden = () => {' . "\n" . '                            if (hiddenInput) {' . "\n" . '                                hiddenInput.value = iti.getNumber();' . "\n" . '                            }' . "\n" . '                        };' . "\n" . '                            ' . "\n" . '                            updateHidden();' . "\n" . '                            input.addEventListener("input", updateHidden);' . "\n" . '                            input.addEventListener("countrychange", updateHidden);' . "\n" . '                        });' . "\n" . '                    }' . "\n" . '                });' . "\n" . '                window.allPhonesInitialized = true;' . "\n" . '            }' . "\n" . '            var phoneInitInterval = setInterval(function() {' . "\n" . '                if (typeof window.intlTelInput === "function") {' . "\n" . '                    initAllPhoneInputs();' . "\n" . '                    if (window.allPhonesInitialized) {' . "\n" . '                        clearInterval(phoneInitInterval);' . "\n" . '                    }' . "\n" . '                }' . "\n" . '            }, 200);' . "\n" . '            ' . "\n" . '            $(document).ready(function(){' . "\n" . '        $("#fon-btn-' . $moduleId . '").on("click",function(e){' . "\n" . '                    e.preventDefault();' . "\n" . '            var form = $("#fon-' . $moduleId . '");' . "\n" . '                    if (!form[0].checkValidity()) {' . "\n" . '                        e.preventDefault();' . "\n" . '                        e.stopPropagation();' . "\n" . '                        form.addClass("was-validated");' . "\n" . '                        form.find(":invalid").parent(".form-floating").addClass("is-invalid");' . "\n" . '                return (alert_error("' . $required_message . '",{timer:3000}));' . "\n" . '                    }' . "\n" . '                    MioAjaxElement($(this),{' . "\n" . '                waiting_text: "' . $pendingText . '",' . "\n" . '                result:"' . $moduleId . '_submit",' . "\n" . '                    });' . "\n" . '               });' . "\n" . '        if($("#fon-' . $moduleId . ' .form-check-input.multiple").length > 0){' . "\n" . '            var _requiredCheckboxes = $("#fon-' . $moduleId . ' .form-check-input.multiple:checkbox[required]");' . "\n" . '                    _requiredCheckboxes.each(function (i, el) {' . "\n" . '                      var _checkboxList = $(this).closest(".fon-formbuilder-checkbox-content");' . "\n" . '                ' . "\n" . '                      if (!_checkboxList.hasClass("rqCheckboxList")) {' . "\n" . '                        _checkboxList.addClass("rqCheckboxList");' . "\n" . '                      }' . "\n" . '                    });' . "\n" . '                ' . "\n" . '                    var _requiredCheckboxLists = $(".rqCheckboxList");' . "\n" . '                    ' . "\n" . '                    _requiredCheckboxLists.each(function (i, el) {' . "\n" . '                      var _checkboxList = $(this);' . "\n" . '                      _checkboxList.on("change", "input[type=\\"checkbox\\"]", function (e) {' . "\n" . '                        updateCheckboxesRequired($(this).parents(".rqCheckboxList"));' . "\n" . '                      });' . "\n" . '                ' . "\n" . '                      updateCheckboxesRequired(_checkboxList);' . "\n" . '                    });' . "\n" . '                    ' . "\n" . '                    function updateCheckboxesRequired(_checkboxList) {' . "\n" . '                      var _checkbox = _checkboxList.find("input[type=\\"checkbox\\"]").eq(0),' . "\n" . '                        checkboxName = _checkbox.attr("name"),' . "\n" . '                        checkboxNameAttr = "[name=\\"" + checkboxName + "\\"]",' . "\n" . '                        _checkBoxes = _checkboxList.find("input[type=\\"checkbox\\"]" + checkboxNameAttr);' . "\n" . '                ' . "\n" . '                      if (_checkboxList.find(checkboxNameAttr + ":checked").length > 0) {' . "\n" . '                        _checkBoxes.prop("required", false);' . "\n" . '                      } else {' . "\n" . '                        _checkBoxes.prop("required", true);' . "\n" . '                      }' . "\n" . '                    }' . "\n" . '                }' . "\n" . '                ' . "\n" . '                ' . "\n" . '            });' . "\n" . '            ' . "\n" . '         </script>';
        $this->addScript('footer', $pageData['page'], $js);
        return $output;
    }

    private function gallery_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $uploadDir = RESOURCE_DIR . 'uploads' . DIRECTORY_SEPARATOR . 'fonpagebuilder';
        $imageBaseDir = RESOURCE_DIR . 'uploads' . DIRECTORY_SEPARATOR . 'fonpagebuilder';
        $thumbBaseDir = RESOURCE_DIR . 'uploads' . DIRECTORY_SEPARATOR . 'fongallerythumb';
        $layout = (isset($content->layout) && $content->layout ? $content->layout : 'bootstrap');
        $thumb_width = (isset($content->thumb_width) && $content->thumb_width ? (int) $content->thumb_width : 600);
        $thumb_height = (isset($content->thumb_height) && $content->thumb_height ? (int) $content->thumb_height : 400);
        $border_radius = (isset($content->border_radius) && $content->border_radius ? (int) $content->border_radius : 0);
        $column = (isset($content->column) && $content->column ? (array) $content->column : ['xl' => 4, 'lg' => 4, 'md' => 3, 'sm' => 2, 'xs' => 2]);
        $method = (isset($content->method) && $content->method ? $content->method : 'folder');
        $folder = (isset($content->folder) && $content->folder ? trim((string) $content->folder) : '');
        $items = (isset($content->items) && $content->items ? $content->items : []);
        $fallbackImage = '/templates/website/Datawise/images/image-fallback.svg';
        $gridXs = min(6, max(1, (int) ($column['xs'] ?? 2)));
        $gridSm = min(6, max(1, (int) ($column['sm'] ?? 2)));
        $gridMd = min(6, max(1, (int) ($column['md'] ?? 3)));
        $gridLg = min(6, max(1, (int) ($column['lg'] ?? 4)));
        $gridXl = min(6, max(1, (int) ($column['xl'] ?? 4)));
        $gridRowClasses = sprintf('row g-3 row-cols-%d row-cols-sm-%d row-cols-md-%d row-cols-lg-%d row-cols-xl-%d', $gridXs, $gridSm, $gridMd, $gridLg, $gridXl);

        if ($layout === 'slide') {
            $gridRowClasses = 'flex-nowrap ' . $gridRowClasses;
        }

        $masonryColumnCounts = sprintf('--column-xs: %d; --column-sm: %d; --column-md: %d; --column-lg: %d; --column-xl: %d;', $gridXs, $gridSm, $gridMd, $gridLg, $gridXl);
        $images = [];
        if (($method == 'folder') && $folder) {
            $folder = trim($this->sanitizeRelativePath($folder), '/');
            $targetFolder = realpath($imageBaseDir . DIRECTORY_SEPARATOR . $folder);
            $baseRealPath = realpath($uploadDir);
            if ($targetFolder === false || $baseRealPath === false || strpos($targetFolder, $baseRealPath) !== 0) {
                return '<div class="alert alert-danger">Klasör bulunamadı veya erişim izni yok.</div>';
            }

            $extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif'];
            $files = scandir($targetFolder) ?: [];

            foreach ($files as $fileName) {
                if (($fileName === '.') || $fileName === '..') {
                    continue;
                }

                $fullPath = $targetFolder . DIRECTORY_SEPARATOR . $fileName;

                if (!is_file($fullPath)) {
                    continue;
                }

                $extension = strtolower((string) pathinfo($fileName, PATHINFO_EXTENSION));

                if (!in_array($extension, $extensions, true)) {
                    continue;
                }

                $imagePath = $folder . '/' . $fileName;
                $thumbs = $this->buildGalleryThumbForImage($imagePath, $imageBaseDir, $thumbBaseDir, $thumb_width, $thumb_height);
                $images[] = ['path' => static::assetLinkDetermine('resources/uploads/fonpagebuilder/' . $imagePath), 'title' => $this->buildGalleryPrettyTitle((string) pathinfo($fileName, PATHINFO_FILENAME)), 'thumb_crop' => static::assetLinkDetermine('resources/uploads/' . $thumbs['crop']), 'thumb_fit' => static::assetLinkDetermine('resources/uploads/' . $thumbs['fit'])];
            }
        }
        else if (($method == 'images') && is_array($items)) {
            foreach ($items as $item) {
                if (isset($item->gallery_image) && $item->gallery_image) {
                    $imagePath = trim((string) $item->gallery_image);

                    if (preg_match('/^https?:\\/\\//i', $imagePath)) {
                        $thumbs = ['crop' => $imagePath, 'fit' => $imagePath];
                    }
                    else {
                        $search = 'resources/uploads/fonpagebuilder/';
                        $cleanPath = str_replace($search, '', ltrim($imagePath, '/'));
                        $thumbs = $this->buildGalleryThumbForImage($cleanPath, $imageBaseDir, $thumbBaseDir, $thumb_width, $thumb_height);
                    }

                    $title = '';

                    if (is_object($item->image_title)) {
                        $title = (isset($item->image_title->{$this->lang}) && $item->image_title->{$this->lang} ? $item->image_title->{$this->lang} : array_values((array) $item->image_title)[0] ?? '');
                    }
                    else if (is_string($item->image_title)) {
                        $title = $item->image_title;
                    }

                    $images[] = ['path' => static::assetLinkDetermine($imagePath), 'title' => ($title ? $title : $this->buildGalleryPrettyTitle((string) pathinfo($imagePath, PATHINFO_FILENAME))), 'thumb_crop' => static::assetLinkDetermine('resources/uploads/' . $thumbs['crop']), 'thumb_fit' => static::assetLinkDetermine('resources/uploads/' . $thumbs['fit'])];
                }
            }
        }

        $style = '@keyframes _gallery-shimmer {' . "\n" . '            0%   { background-position: 200% 0; }' . "\n" . '            100% { background-position: -200% 0; }' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .horizontal-slider-viewport {' . "\n" . '            overflow: hidden;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] .gallery-item {' . "\n" . '            break-inside: avoid;' . "\n" . '            margin-bottom: 1rem;' . "\n" . '        }' . "\n" . '        ' . "\n" . '        .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="justified"] {' . "\n" . '            display: grid;' . "\n" . '            grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));' . "\n" . '            gap: 0.75rem;' . "\n" . '            align-items: start;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="metro"] {' . "\n" . '            display: grid;' . "\n" . '            grid-template-columns: repeat(2, minmax(0, 1fr));' . "\n" . '            gap: 15px;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item.is-loading {' . "\n" . '            background: linear-gradient(' . "\n" . '                90deg,' . "\n" . '                #e9ecef 25%,' . "\n" . '                #f4f5f6 50%,' . "\n" . '                #e9ecef 75%' . "\n" . '            );' . "\n" . '            background-size: 400% 100%;' . "\n" . '            animation: _gallery-shimmer 1.6s ease-in-out infinite;' . "\n" . '            min-height: 120px;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item.is-loading {' . "\n" . '            min-height: 0;' . "\n" . '            aspect-ratio: 4 / 3;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item.is-loading figcaption,' . "\n" . '        .gallery-css-pending.fon-gallery-widget .slider-nav-btn {' . "\n" . '            display: none;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item.is-loading img {' . "\n" . '            opacity: 0;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item img {' . "\n" . '            display: block;' . "\n" . '            width: 100%;' . "\n" . '            height: auto;' . "\n" . '            transition: opacity 0.35s ease;' . "\n" . '        }' . "\n" . '        @media (min-width: 576px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 2;' . "\n" . '            }' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="metro"] {' . "\n" . '                grid-template-columns: repeat(2, minmax(0, 1fr));' . "\n" . '            }' . "\n" . '        }' . "\n" . '        @media (min-width: 768px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 2;' . "\n" . '            }' . "\n" . '        }' . "\n" . '        @media (min-width: 992px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 3;' . "\n" . '            }' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="metro"] {' . "\n" . '                grid-template-columns: repeat(4, minmax(0, 1fr));' . "\n" . '            }' . "\n" . '        }' . "\n" . '        @media (min-width: 1200px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 4;' . "\n" . '            }' . "\n" . '        }' . "\n" . '        @media (min-width: 1400px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 4;' . "\n" . '            }' . "\n" . '        }';

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $this->addAsset('fon-gallery');
        $output = '';

        if ($images) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container gallery-css-pending fon-gallery-widget ' . ($content->fon_class ?? '') . '" data-gallery-widget data-widget-id="' . $widgetId . '">';
            $output .= '<div class="horizontal-slider js-horizontal-slider ' . ($layout === 'slide' ? 'is-active' : '') . '">';

            if ($layout === 'slide') {
                $output .= '<button type="button" class="btn btn-circle btn-default align-items-center justify-content-center slider-nav-btn slider-prev-btn js-horizontal-prev-btn" aria-label="Onceki" style="' . ($layout === 'slide' ? '' : 'display:none;') . '">';
                $output .= '<i class="fa-solid fa-chevron-left"></i>';
                $output .= '</button>';
            }

            $output .= '<div class="horizontal-slider-viewport js-horizontal-viewport">';
            $output .= '<div' . "\n" . '                                class="gallery-layout js-gallery-wrap ' . $layout . ' ' . (($layout === 'bootstrap') || $layout === 'slide' ? $gridRowClasses : '') . '" ' . "\n" . '                                data-gallery-layout="' . $layout . '"' . "\n" . '                                style="' . ($layout === 'masonry' ? $masonryColumnCounts : '') . '"' . "\n" . '                            >';

            foreach ($images as $index => $image) {
                $path = (string) ($image['path'] ?? '');
                $title = (string) ($image['title'] ?? '');
                $thumbCrop = (string) ($image['thumb_crop'] ?? '');
                $thumbFit = (string) ($image['thumb_fit'] ?? '');
                $useFitThumb = in_array($layout, ['masonry' => true, 'justified' => true]);
                $thumbPath = ($useFitThumb ? $thumbFit : $thumbCrop);
                if (($layout === 'bootstrap') || $layout === 'slide') {
                    $output .= '<div class="col">';
                }

                $output .= ' <figure class="gallery-item is-loading" style="' . (0 < $border_radius ? 'border-radius:' . (int) $border_radius . 'px;' : '') . '">';
                $output .= '<a' . "\n" . '                                            href="' . $path . '"' . "\n" . '                                            class="gallery-link js-gallery-link"' . "\n" . '                                            data-index="' . (int) $index . '"' . "\n" . '                                            data-title="' . $title . '"' . "\n" . '                                        style="' . (0 < $border_radius ? 'border-radius:' . (int) $border_radius . 'px;' : '') . '"' . "\n" . '                                        >';
                $output .= '<img' . "\n" . '                                                src="' . $thumbPath . '"' . "\n" . '                                                alt="' . ($title !== '' ? $title : 'Galeri gorseli') . '"' . "\n" . '                                                class="img-fluid rounded shadow-sm"' . "\n" . '                                                data-fallback="' . $fallbackImage . '"' . "\n" . '                                                onerror="this.onerror=null;this.src=this.dataset.fallback;"' . "\n" . '                                                ' . (0 < $thumb_width ? 'width="' . (int) $thumb_width . '"' : '') . ' ' . "\n" . '                                                ' . (0 < $thumb_height ? 'height="' . (int) $thumb_height . '"' : '') . ' ' . "\n" . '                                                loading="lazy"' . "\n" . '                                            >';
                $output .= '</a>';

                if ($title !== '') {
                    $output .= '<figcaption>' . $title . '</figcaption>';
                }

                $output .= '</figure>';
                if (($layout === 'bootstrap') || $layout === 'slide') {
                    $output .= '</div>';
                }
            }

            $output .= '</div>';
            $output .= '</div>';

            if ($layout === 'slide') {
                $output .= '<button type="button" class="btn btn-circle btn-default align-items-center justify-content-center slider-nav-btn slider-next-btn js-horizontal-next-btn" aria-label="Sonraki">';
                $output .= '<i class="fa-solid fa-chevron-right"></i>';
                $output .= '</button>';
            }

            $output .= '</div>';
            $output .= '<div class="modal fade gallery-modal js-gallery-modal" id="' . $widgetId . '-modal" tabindex="-1" aria-hidden="true">';
            $output .= '<div class="modal-dialog modal-xl modal-dialog-centered">';
            $output .= '<div class="modal-content bg-dark text-white">';
            $output .= '<div class="modal-header border-0">';
            $output .= '<h5 class="modal-title js-gallery-modal-title text-white" id="' . $widgetId . '-modal-title"></h5>';
            $output .= '<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Kapat"></button>';
            $output .= '</div>';
            $output .= '<div class="modal-body text-center position-relative">';
            $output .= '<button type="button" class="btn btn-light modal-nav-btn prev-btn js-prev-image-btn">';
            $output .= '<i class="fa-solid fa-chevron-left"></i>';
            $output .= '</button>';
            $output .= '<img src="" alt="" class="img-fluid rounded gallery-modal-image js-modal-image">';
            $output .= '<button type="button" class="btn btn-light modal-nav-btn next-btn js-next-image-btn">';
            $output .= '<i class="fa-solid fa-chevron-right"></i>';
            $output .= '</button>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function heading_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $title = '';

        if (is_object($content->title)) {
            $title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        }
        else if (is_string($content->title)) {
            $title = $content->title;
        }

        $title_link = '';

        if (is_object($content->title_link)) {
            $title_link = (isset($content->title_link->{$this->lang}) && $content->title_link->{$this->lang} ? $content->title_link->{$this->lang} : array_values((array) $content->title_link)[0] ?? '');
        }
        else if (is_string($content->title_link)) {
            $title_link = $content->title_link;
        }
        $title_link_target = (isset($content->title_link_target) && $content->title_link_target ? $content->title_link_target : '_self');
        $title_link_rel = (isset($content->title_link_rel) && $content->title_link_rel ? $content->title_link_rel : []);
        $title_link_rel = ($title_link_rel ? ' rel="' . implode(' ', $title_link_rel) . '" ' : '');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $show_icon = (isset($content->show_icon) && $content->show_icon == 'yes' ? true : false);
        $icon_type = (isset($content->icon_type) && $content->icon_type ? $content->icon_type : 'icon');
        $title_icon = (isset($content->title_icon) && $content->title_icon ? $content->title_icon : '');
        $title_svg = (isset($content->title_svg) && $content->title_svg ? $content->title_svg : '');
        $title_icon_position = (isset($content->title_icon_position) && $content->title_icon_position ? $content->title_icon_position : 'before');
        $title_icon_color = (isset($content->title_icon_color) && $content->title_icon_color ? $content->title_icon_color : '');
        $scroll_effect = (isset($content->scroll_effect) && $content->scroll_effect == 'yes' ? true : false);
        $title_color = (isset($content->title_color) && $content->title_color ? $content->title_color : '');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : '');
        $title_text_shadow = (isset($content->title_text_shadow) && $content->title_text_shadow ? $content->title_text_shadow : '');
        $title_margin = (isset($content->title_margin) && $content->title_margin ? $content->title_margin : (object) ['xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => '']);
        $title_padding = (isset($content->title_padding) && $content->title_padding ? $content->title_padding : (object) ['xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => '']);
        $aligns = (isset($content->align) && $content->align ? $content->align : (object) ['xl' => 'left', 'lg' => 'left', 'md' => 'left', 'sm' => 'left', 'xs' => 'left']);
        $alignClass = [];

        if ($aligns) {
            foreach ($aligns as $key => $align) {
                $map = ['left' => 'start', 'right' => 'end', 'center' => 'center'];
                $val = $map[$align] ?? 'start';
                $prefix = ($key === 'xs' ? '' : '-' . $key);
                $alignClass[] = 'text' . $prefix . '-' . $val;
            }
        }

        $alignClass = implode(' ', $alignClass);
        $isScrolled = false;
        $scrollAlignsClass = [];
        if ($scroll_effect && is_string($title) && strpos($title, ':') !== false) {
            $title = explode(':', $title);
            $isScrolled = true;

            foreach ($aligns as $key => $align) {
                $prefix = ($key === 'xs' ? '' : '-' . $key);

                switch ($align) {
                case 'center':
                    $scrollAlignsClass[] = 'mx' . $prefix . '-auto';
                    break;
                case 'right':
                    $scrollAlignsClass[] = 'ms' . $prefix . '-auto';
                    $scrollAlignsClass[] = 'me' . $prefix . '-0';
                    break;
                case 'left':
                    $scrollAlignsClass[] = 'me' . $prefix . '-auto';
                    $scrollAlignsClass[] = 'ms' . $prefix . '-0';
                    break;
                }
            }
        }

        $scrollAlignsClass = implode(' ', $scrollAlignsClass);
        $style = '';

        if ($title) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';

            if ($title_color) {
                $style .= 'color: ' . $title_color . ';';
            }

            if ($title_text_shadow) {
                $style .= 'text-shadow: ' . $title_text_shadow . ';';
            }

            if ($title_font) {
                $style .= self::parseFontProperties($title_font);
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-widget-title a{';

            if ($title_color) {
                $style .= 'color: ' . $title_color . ';';
            }

            $style .= '}';
            if ($isScrolled && $title_color) {
                $style .= '#' . $widgetId . ' .scrolling-sector{';
                $style .= '--title-color: ' . $title_color . ';';
                $style .= '}';
            }
        }
        if ($show_icon && $title_icon) {
            $style .= '#' . $widgetId . ' .fon-widget-title i{';

            if ($title_icon_color) {
                $style .= 'color: ' . $title_icon_color . ';';
            }

            $style .= '}';
        }

        $responsiveItems = [
            '.fon-widget-title' => [
            ['type' => 'margin', 'unit' => '', 'value' => $title_margin],
            ['type' => 'padding', 'unit' => '', 'value' => $title_padding]
        ]
        ];
        $style .= self::parseResponsiveItems($responsiveItems, $widgetId);

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-heading-widget ' . ($content->fon_class ?? '') . '">';
        $output .= '<div class="fon-widget-content ' . ($isScrolled ? 'scrolling-sector-wrapper ' . $scrollAlignsClass : '') . '">';

        if ($title) {
            $output .= '<' . $heading_selector . ' class="fon-widget-title ' . ($isScrolled ? 'scrolling-sector-inner' : $alignClass) . '">';
            if ($title_link && !$scroll_effect) {
                $output .= '<a href="' . $title_link . '" target="' . $title_link_target . '" ' . $title_link_rel . '>';
            }
            if ($show_icon && $title_icon_position == 'before') {
                if ($icon_type == 'icon') {
                    $output .= '<i class="' . $title_icon . '"></i> ';
                }
                else if ($icon_type == 'svg') {
                    $output .= '<span class="me-2">' . $title_svg . '</span>';
                }
            }

            if ($isScrolled) {
                $output .= '<div class="scrolling-sector"><span>' . implode('</span><span>', $title) . '</span></div>';
            }
            else {
                $output .= self::getPriceHolders($title);
            }
            if ($show_icon && $title_icon_position == 'after') {
                if ($icon_type == 'icon') {
                    $output .= '<i class="' . $title_icon . ' me-2"></i>';
                }
                else if ($icon_type == 'svg') {
                    $output .= '<span class="me-2">' . $title_svg . '</span>';
                }
            }
            if ($title_link && !$scroll_effect) {
                $output .= '</a>';
            }

            $output .= '</' . $heading_selector . '>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function hosting_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetProducts($content, $moduleId, $pageData, $row, 'hosting');
    }

    private function image_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $title = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        $show_title = (isset($content->name_widget_status) && $content->name_widget_status == 'yes' ? true : false);
        $title_position = (isset($content->title_position) && $content->title_position ? $content->title_position : 'top');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $alt_text = (isset($content->alt_text->{$this->lang}) && $content->alt_text->{$this->lang} ? $content->alt_text->{$this->lang} : array_values((array) $content->alt_text)[0] ?? '');
        $title_text = (isset($content->title_text->{$this->lang}) && $content->title_text->{$this->lang} ? $content->title_text->{$this->lang} : (isset($content->title_text) ? array_values((array) $content->title_text)[0] ?? '' : ''));
        $open_lightbox = (isset($content->open_lightbox) && $content->open_lightbox == 'yes' ? true : false);
        $overlay_type = (isset($content->overlay_type) && $content->overlay_type ? $content->overlay_type : 'none');
        $image_overlay = ($overlay_type != 'none' ? true : false);
        $link = (isset($content->link) && $content->link ? $content->link : '');
        $link_target = (isset($content->link_target) && $content->link_target ? $content->link_target : '_blank');
        $link_rel = (isset($content->link_rel) && $content->link_rel ? $content->link_rel : []);
        $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');
        $image = '';

        if (is_object($content->image)) {
            $image = (isset($content->image->{$this->lang}) && $content->image->{$this->lang} ? $content->image->{$this->lang} : array_values((array) $content->image)[0] ?? '');
        }
        else if (is_string($content->image)) {
            $image = $content->image;
        }

        $image_src = ($image ? static::assetLinkDetermine($image) : $lazyPlaceholder);
        $imageDimensions = static::getImageDimensions($image_src, $pageData['badress']);
        $image_width = (isset($content->image_width) && $content->image_width ? $content->image_width : false);
        $image_height = (isset($content->image_height) && $content->image_height ? $content->image_height : false);
        $align = (isset($content->align) && $content->align ? $content->align : 'center');
        $use_border = (isset($content->use_border) && $content->use_border == 'yes' ? true : false);
        $border = (isset($content->border) && $content->border ? $content->border : '');
        $padding = (isset($content->padding) && $content->padding ? $content->padding : '');
        $border_radius = (isset($content->border_radius) && $content->border_radius ? $content->border_radius : 0);
        $shadow = (isset($content->shadow) && $content->shadow ? $content->shadow : '');
        $disable_lazy = (isset($content->disable_lazy) && $content->disable_lazy == 'yes' ? true : false);

        if (empty($alt_text)) {
            if (!empty($title)) {
                $alt_text = $title;
            }
            else if (!empty($title_text)) {
                $alt_text = $title_text;
            }
            else {
                $alt_text = basename($image_src);
            }
        }

        if (empty($title_text)) {
            if (!empty($title)) {
                $title_text = $title;
            }
            else if (!empty($alt_text)) {
                $title_text = $alt_text;
            }
            else {
                $title_text = basename($image_src);
            }
        }

        if ($align == 'left') {
            $align = 'start';
        }
        else if ($align == 'right') {
            $align = 'end';
        }

        $style = '';

        if ($image) {
            $style .= '#' . $widgetId . ' .fon-image-widget-container img{';
            $style .= ($border && $use_border ? 'border:' . $border . ';' : '');
            $style .= ($padding && $use_border ? 'padding:' . $padding . 'px;' : '');
            $style .= ($border_radius ? 'border-radius:' . $border_radius . 'px;' : '');
            $style .= ($shadow ? 'box-shadow:' . $shadow . ';' : '');
            $style .= '}';
            $responsiveValues = [];

            if ($image_height) {
                $responsiveValues[] = ['type' => 'height', 'unit' => 'px', 'value' => $image_height];
            }

            if ($image_width) {
                $responsiveValues[] = ['type' => 'width', 'unit' => 'px', 'value' => $image_width];
            }

            $responsiveItems = ['#' . $widgetId . ' .fon-image-widget-container img' => $responsiveValues];
            $style .= self::parseResponsiveItems($responsiveItems);
        }
        if ($image_overlay && $open_lightbox) {
            $style .= '#' . $widgetId . ' .fon-image-widget-overlay{';

            if ($overlay_type == 'color') {
                $style .= (isset($content->color_overlay) && $content->color_overlay ? 'background-color:' . $content->color_overlay . ';' : '');
            }

            if ($overlay_type == 'gradient') {
                $style .= (isset($content->gradient_overlay) && $content->gradient_overlay ? self::parseGradient($content->gradient_overlay) : '');
            }
            if ($padding && $use_border) {
                $style .= ($image_width ? 'width:calc(100% - ' . ($padding * 2) . 'px);' : '');
                $style .= ($image_height ? 'height:calc(100% - ' . ($padding * 2) . 'px);' : '');
                $style .= 'left:' . $padding . 'px;';
                $style .= 'right:' . $padding . 'px;';
                $style .= 'top:' . $padding . 'px;';
                $style .= 'bottom:' . $padding . 'px;';
                $style .= ($border_radius ? 'border-radius:' . round($border_radius / 2) . 'px;' : '');
            }
            else {
                $style .= ($image_width ? 'width:100%;' : '');
                $style .= ($image_height ? 'height:100%;' : '');
                $style .= ($border_radius ? 'border-radius:' . $border_radius . 'px;' : '');
            }

            $style .= '}';
        }
        if ($show_title && $title) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';
            $style .= self::parseFontProperties($content->title_font);
            $style .= ($content->title_color ? 'color:' . $content->title_color . ';' : '');
            $style .= ($content->title_margin->top ? 'margin-top:' . $content->title_margin->top . 'px;' : '');
            $style .= ($content->title_margin->bottom ? 'margin-bottom:' . $content->title_margin->bottom . 'px;' : '');
            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        if ($isLCPCandidate && $image) {
            $this->addPreloadLink($image, $pageData['page']);
            self::$lcpHandled = true;
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-image-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content text-' . $align . '">';
        $output .= ($show_title && $title && $title_position != 'bottom' ? '<' . $heading_selector . ' class="fon-widget-title d-block">' . $title . '</' . $heading_selector . '>' : '');
        $output .= '<div class="fon-image-widget-container text-' . $align . '">';
        if ($image_overlay && $open_lightbox) {
            $output .= '<div class="fon-image-widget-overlay">';
            $output .= '</div>';
        }

        if ($open_lightbox) {
            $this->addAsset('magnific');
            $output .= '<a class="fon-magnific-popup fon-image-widget-overlay-icon" data-popuptype="image" data-mainclass="mfp-no-margins mfp-with-zoom" href="' . $image_src . '">+</a>';
        }

        if (!$open_lightbox) {
            $output .= (!empty($link) ? '<a href="' . $link . '" target="' . $link_target . '" ' . $link_rel . '>' : '');
        }

        $loadingAttr = 'loading="lazy" decoding="async"';
        $fetchPriority = 'low';
        if (($isLCPCandidate && $image_src) || $disable_lazy) {
            $loadingAttr = 'loading="eager"';
            $fetchPriority = 'high';
        }
        else if (!$enableLazyLoading) {
            $loadingAttr = 'loading="eager"';
            $fetchPriority = 'auto';
        }

        $output .= '<img class="img-fluid" src="' . $image_src . '" alt="' . $alt_text . '" title="' . $title_text . '" ' . $imageDimensions . ' ' . $loadingAttr . ' fetchpriority="' . $fetchPriority . '"/>';

        if (!$open_lightbox) {
            $output .= (!empty($link) ? '</a>' : '');
        }

        $output .= '</div>';
        $output .= ($show_title && $title && $title_position === 'bottom' ? '<' . $heading_selector . ' class="fon-widget-title d-block">' . $title . '</' . $heading_selector . '>' : '');
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function modal_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $modalUniqueId = 'fon-modal-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $modal_selector = (isset($content->modal_selector) && $content->modal_selector ? $content->modal_selector : 'image');
        $name_widget = '';

        if (is_object($content->name_widget)) {
            $name_widget = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        }
        else if (is_string($content->name_widget)) {
            $name_widget = $content->name_widget;
        }

        $image = '';

        if (is_object($content->image)) {
            $image = (isset($content->image->{$this->lang}) && $content->image->{$this->lang} ? $content->image->{$this->lang} : array_values((array) $content->image)[0] ?? '');
        }
        else if (is_string($content->image)) {
            $image = $content->image;
        }

        $image_src = ($image ? static::assetLinkDetermine($image) : static::assetLinkDetermine(self::$imagePlaceholder));
        $image_width = (isset($content->image_width) && $content->image_width ? $content->image_width : (object) ['xxl' => '100', 'xl' => '100', 'lg' => '100', 'md' => '100', 'sm' => '100', 'xs' => '100']);
        $image_height = (isset($content->image_height) && $content->image_height ? $content->image_height : (object) ['xxl' => '100', 'xl' => '100', 'lg' => '100', 'md' => '100', 'sm' => '100', 'xs' => '100']);
        $image_use_border = (isset($content->image_use_border) && $content->image_use_border == 'yes' ? true : false);
        $image_border = (isset($content->image_border) && $content->image_border ? $content->image_border : '2px solid #ffffff');
        $image_radius = (isset($content->image_radius) && $content->image_radius ? $content->image_radius : '');
        $image_show_icon = (isset($content->image_show_icon) && $content->image_show_icon == 'yes' ? true : false);
        $image_icon = (isset($content->image_icon) && $content->image_icon ? $content->image_icon : 'fa-solid fa-play');
        $image_icon_size = (isset($content->image_icon_size) && $content->image_icon_size ? $content->image_icon_size : '14');
        $image_icon_color = (isset($content->image_icon_color) && $content->image_icon_color ? $content->image_icon_color : '#fff');
        $button = ['button_text' => $content->button_text ?? '', 'button_target' => '', 'button_type' => $content->button_type ?? 'default', 'button_style' => $content->button_style ?? 'default', 'button_custom_style' => $content->button_custom_style ?? 'default', 'button_shape' => $content->button_shape ?? '', 'button_size' => $content->button_size ?? '', 'button_padding' => $content->button_padding ?? '', 'button_color_normal' => $content->button_color->normal ?? '', 'button_color_hover' => $content->button_color->hover ?? '', 'button_background_normal' => $content->button_background->normal ?? '', 'button_background_hover' => $content->button_background->hover ?? '', 'button_gradient_normal' => $content->button_gradient->normal ?? '', 'button_gradient_hover' => $content->button_gradient->hover ?? '', 'show_button_icon' => $content->show_button_icon ?? 'no', 'button_icon' => $content->button_icon ?? '', 'button_icon_position' => $content->button_icon_position ?? '', 'scroll_button' => 'no', 'block_button' => 'no', 'button_font' => $content->button_font ?? ''];
        $icon = (isset($content->icon) && $content->icon ? $content->icon : 'fa-solid fa-play');
        $icon_size = (isset($content->icon_size) && $content->icon_size ? $content->icon_size : (object) ['xxl' => '36', 'xl' => '36', 'lg' => '36', 'md' => '36', 'sm' => '36', 'xs' => '36']);
        $icon_color = (isset($content->icon_color) && $content->icon_color ? $content->icon_color : '#ffffff');
        $icon_bg_color = (isset($content->icon_bg_color) && $content->icon_bg_color ? $content->icon_bg_color : 'var(--theme-secondary)');
        $icon_width = (isset($content->icon_width) && $content->icon_width ? $content->icon_width : (object) ['xxl' => '100', 'xl' => '100', 'lg' => '100', 'md' => '100', 'sm' => '100', 'xs' => '100']);
        $icon_height = (isset($content->icon_height) && $content->icon_height ? $content->icon_height : (object) ['xxl' => '100', 'xl' => '100', 'lg' => '100', 'md' => '100', 'sm' => '100', 'xs' => '100']);
        $icon_use_border = (isset($content->icon_use_border) && $content->icon_use_border == 'yes' ? true : false);
        $icon_border = (isset($content->icon_border) && $content->icon_border ? $content->icon_border : '1px solid var(--theme-primary)');
        $icon_border_radius = (isset($content->icon_border_radius) && $content->icon_border_radius ? $content->icon_border_radius : '');
        $icon_shadow = (isset($content->icon_shadow) && $content->icon_shadow ? $content->icon_shadow : '');
        $selector_position_type = (isset($content->selector_position_type) && $content->selector_position_type ? $content->selector_position_type : 'none');
        $selector_position = (isset($content->selector_position) && $content->selector_position ? $content->selector_position : (object) ['left' => '', 'right' => '', 'top' => '', 'bottom' => '']);
        $center_selector = (isset($content->center_selector) && $content->center_selector == 'yes' ? true : false);
        $show_ripple_effect = (isset($content->show_ripple_effect) && $content->show_ripple_effect == 'yes' ? true : false);
        $ripple_effect_color = (isset($content->ripple_effect_color) && $content->ripple_effect_color ? $content->ripple_effect_color : '#000000');
        $ripple_effect_color = self::validateAndNormalizeColor($ripple_effect_color);
        $content_type = (isset($content->content_type) && $content->content_type ? $content->content_type : 'video');
        $video_source = (isset($content->video_source) && $content->video_source ? $content->video_source : 'youtube');
        $video_url = '';

        if (is_object($content->video_url)) {
            $video_url = (isset($content->video_url->{$this->lang}) && $content->video_url->{$this->lang} ? $content->video_url->{$this->lang} : array_values((array) $content->video_url)[0] ?? '');
        }
        else if (is_string($content->video_url)) {
            $video_url = $content->video_url;
        }

        $mp4_video = '';

        if (is_object($content->mp4_video)) {
            $mp4_video = (isset($content->mp4_video->{$this->lang}) && $content->mp4_video->{$this->lang} ? $content->mp4_video->{$this->lang} : array_values((array) $content->mp4_video)[0] ?? '');
        }
        else if (is_string($content->mp4_video)) {
            $mp4_video = $content->mp4_video;
        }

        if ($mp4_video) {
            $mp4_video = static::assetLinkDetermine($mp4_video);
        }
        $show_control = (isset($content->show_control) && $content->show_control == 'yes' ? true : false);
        $video_loop = (isset($content->video_loop) && $content->video_loop == 'yes' ? true : false);
        $video_mute = (isset($content->video_mute) && $content->video_mute == 'yes' ? true : false);
        $autoplay_video = (isset($content->autoplay_video) && $content->autoplay_video == 'yes' ? true : false);
        $text_content = '';

        if (is_object($content->text_content)) {
            $text_content = (isset($content->text_content->{$this->lang}) && $content->text_content->{$this->lang} ? $content->text_content->{$this->lang} : array_values((array) $content->text_content)[0] ?? '');
        }
        else if (is_string($content->text_content)) {
            $text_content = $content->text_content;
        }

        $image_content = '';

        if (is_object($content->image_content)) {
            $image_content = (isset($content->image_content->{$this->lang}) && $content->image_content->{$this->lang} ? $content->image_content->{$this->lang} : array_values((array) $content->image_content)[0] ?? '');
        }
        else if (is_string($content->image_content)) {
            $image_content = $content->image_content;
        }

        $image_content_src = ($image ? static::assetLinkDetermine($image_content) : static::assetLinkDetermine(self::$imagePlaceholder));
        $image_content_alt = '';

        if (is_object($content->image_content_alt)) {
            $image_content_alt = (isset($content->image_content_alt->{$this->lang}) && $content->image_content_alt->{$this->lang} ? $content->image_content_alt->{$this->lang} : array_values((array) $content->image_content_alt)[0] ?? '');
        }
        else if (is_string($content->image_content_alt)) {
            $image_content_alt = $content->image_content_alt;
        }
        $modal_popup_sizes = (isset($content->modal_popup_sizes) && $content->modal_popup_sizes ? $content->modal_popup_sizes : (object) ['width' => '760', 'height' => '400']);
        $modal_popup_overflow = (isset($content->modal_popup_overflow) && $content->modal_popup_overflow ? $content->modal_popup_overflow : 'auto');
        $style = '';
        if (($modal_selector == 'image') && $image) {
            if ($image_use_border) {
                $style .= '#' . $widgetId . ' .fon-modal-selector .fon-modal-image{';
                $style .= ($image_border ? 'border:' . $image_border . ';' : '');
                $style .= '}';
            }

            $style .= '#' . $widgetId . ' .fon-modal-selector, #' . $widgetId . ' .fon-modal-image, #' . $widgetId . ' .fon-ripple-effect{';
            $style .= ($image_radius ? 'border-radius:' . $image_radius . ';' : '');
            $style .= '}';
            $responsiveValues = [];

            if ($image_height) {
                $responsiveValues[] = ['type' => 'height', 'unit' => 'px', 'value' => $image_height];
            }

            if ($image_width) {
                $responsiveValues[] = ['type' => 'width', 'unit' => 'px', 'value' => $image_width];
            }

            $responsiveItems = ['#' . $widgetId . ' .fon-modal-selector, #' . $widgetId . ' .fon-modal-image, #' . $widgetId . ' .fon-modal-image img' => $responsiveValues];
            $style .= self::parseResponsiveItems($responsiveItems);
            if ($image_show_icon && $image_icon) {
                $style .= '#' . $widgetId . ' .fon-modal-image .fon-modal-image-icon{';
                $style .= ($image_icon_size ? 'font-size:' . $image_icon_size . 'px;' : '');
                $style .= ($image_icon_color ? 'color:' . $image_icon_color . ';' : '');
                $style .= 'position: absolute;';
                $style .= 'top: 50%;';
                $style .= 'left: 50%;';
                $style .= 'transform: translate(-50%, -50%);';

                if ($icon_shadow) {
                    $style .= 'text-shadow:' . $icon_shadow . ';';
                }

                $style .= '}';
            }
        }
        else if (($modal_selector == 'icon') && $icon) {
            $style .= '#' . $widgetId . ' .fon-modal-icon{';
            $style .= ($icon_color ? 'color:' . $icon_color . ';' : '');
            $style .= ($icon_bg_color ? 'background:' . $icon_bg_color . ';' : '');
            $style .= ($icon_border_radius ? 'border-radius:' . $icon_border_radius . ';' : '');
            $style .= ($icon_shadow ? 'box-shadow:' . $icon_shadow . ';' : '');
            $style .= ($icon_use_border && $icon_border ? 'border:' . $icon_border . ';' : '');
            $style .= 'aspect-ratio: 1 / 1;';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-ripple-effect{';
            $style .= ($icon_border_radius ? 'border-radius:' . $icon_border_radius . ';' : '');
            $style .= '}';
            $responsiveValues = [];

            if ($icon_size) {
                $responsiveValues[] = ['type' => 'font-size', 'unit' => 'px', 'value' => $icon_size];
            }

            if ($icon_height) {
                $responsiveValues[] = ['type' => 'height', 'unit' => 'px', 'value' => $icon_height];
            }

            if ($icon_width) {
                $responsiveValues[] = ['type' => 'width', 'unit' => 'px', 'value' => $icon_width];
            }

            $responsiveItems = ['#' . $widgetId . ' .fon-modal-icon' => $responsiveValues];
            $style .= self::parseResponsiveItems($responsiveItems);
        }

        if ($selector_position_type != 'none') {
            $style .= '#' . $widgetId . '{';
            if (in_array($selector_position_type, ['absolute' => true, 'relative' => true]) && $center_selector) {
                $style .= 'transform: translate(-50%, -50%);';
            }

            $style .= '}';
            $responsiveValues = [
                ['type' => 'left', 'unit' => '', 'value' => $selector_position->left],
                ['type' => 'right', 'unit' => '', 'value' => $selector_position->right],
                ['type' => 'top', 'unit' => '', 'value' => $selector_position->top],
                ['type' => 'bottom', 'unit' => '', 'value' => $selector_position->bottom]
            ];
            $responsiveItems = ['#' . $widgetId => $responsiveValues];
            $style .= self::parseResponsiveItems($responsiveItems);
        }

        if ($content_type != 'video') {
            $style .= '#' . $modalUniqueId . ' .fon-modal-inner-block {';
            $style .= 'width:' . $modal_popup_sizes->width . 'px;';
            $style .= 'height:' . $modal_popup_sizes->height . 'px;';
            $style .= 'max-width:100%!important;';

            if ($content_type != 'image') {
                $style .= 'overflow-y:' . $modal_popup_overflow . ';';
            }

            $style .= '}';
        }
        if ($show_ripple_effect && isset($ripple_effect_color['color']) && $ripple_effect_color['color']) {
            $style .= '#' . $widgetId . ' .fon-ripple-effect{';
            $style .= '--fon-effect-rgb:' . $ripple_effect_color['color'] . ';';
            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $this->addAsset('magnific');
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-modal-widget ' . ($content->fon_class ?? '') . ' position-' . $selector_position_type . '">';

        if ($content_type === 'text') {
            $url = '#' . $modalUniqueId;
            $output .= '<div id="' . $modalUniqueId . '" class="mfp-hide fon-modal-text-popup-block position-relative mx-auto" style="width:min-content;max-width:90%!important">';
            $output .= '<div class="fon-modal-inner-block position-relative p-4 rounded-3 overflow-x-hidden bg-white">';
            $output .= $text_content;
            $output .= '</div>';
            $output .= '</div>';
            $attribs = 'data-popup_type="inline" data-mainclass="mfp-no-margins mfp-with-zoom"';
        }
        else if ($content_type === 'video') {
            if ($video_source == 'mp4') {
                $url = $mp4_video;
                $attribs = 'data-popup_type="video" data-mainclass="mfp-no-margins mfp-with-zoom" data-show-control="' . $show_control . '" data-video-loop="' . $video_loop . '" data-video-mute="' . $video_mute . '" data-autoplay-video="' . $autoplay_video . '"';
            }
            else {
                $url = $video_url;
                $attribs = 'data-popup_type="iframe" data-mainclass="mfp-no-margins mfp-with-zoom"';
            }
        }
        else {
            if (empty($image_content_alt)) {
                $url_part_of_content = explode('/', $image_content_src);
                $modal_content_image_alt_text = end($url_part_of_content);
            }

            $url = '#' . $modalUniqueId;
            $imageDimensions = static::getImageDimensions($image_content_src, $pageData['badress']);
            $output .= '<div id="' . $modalUniqueId . '" class="mfp-hide fon-modal-popup-image-block position-relative mx-auto" style="width:fit-content; height:fit-content;">';
            $output .= '<div class="fon-modal-inner-block">';
            $output .= '<img class="mfp-img" src="' . $image_content_src . '" alt="' . $modal_content_image_alt_text . '" ' . $imageDimensions . '>';
            $output .= '</div>';
            $output .= '</div>';
            $attribs = 'data-popup_type="inline" data-mainclass="mfp-no-margins mfp-with-zoom"';
        }

        if ($modal_selector === 'image') {
            if ($image_src) {
                $imageDimensions = static::getImageDimensions($image_src, $pageData['badress']);
                $output .= '<a class="fon-modal-selector fon-magnific-popup d-inline-block position-relative" ' . $attribs . ' href="' . $url . '" id="' . $modalUniqueId . '-selector">';

                if ($show_ripple_effect) {
                    $output .= '<span class="fon-ripple-effect"></span>';
                }

                $output .= '<span class="fon-modal-image overflow-hidden d-block position-relative z-1">';
                $output .= '<img src="' . $image_src . '" class="img img-fluid object-fit-cover" alt="' . $name_widget . '" ' . $imageDimensions . '/>';
                $output .= ($image_show_icon ? '<span class="fon-modal-image-icon"><i class="' . $image_icon . '"></i></span>' : '');
                $output .= '</span>';
                $output .= '</a>';
            }
        }
        else if ($modal_selector === 'icon') {
            if ($icon) {
                $select_icon = explode(' ', $icon);

                if (count($select_icon) === 1) {
                    $icon = 'fa-solid ' . $icon;
                }

                $output .= '<a class="fon-modal-selector fon-magnific-popup d-inline-block position-relative" href="' . $url . '" ' . $attribs . ' id="' . $modalUniqueId . '-selector">';

                if ($show_ripple_effect) {
                    $output .= '<span class="fon-ripple-effect"></span>';
                }

                $output .= '<span class="fon-modal-icon d-inline-flex align-items-center justify-content-center position-relative z-1">';
                $output .= '<i class="' . $icon . '" aria-hidden="true"></i>';
                $output .= '</span>';
                $output .= '</a>';
            }
        }
        else {
            $button['button_link'] = $url;
            $modalButton = $this->parseButton((object) $button, $moduleId, $pageData, ['class' => 'fon-magnific-popup fon-modal-selector position-relative z-1', 'attributes' => $attribs, 'id' => $modalUniqueId . '-selector']);
            $output .= '<span class="fon-modal-button d-inline-block position-relative">';

            if ($show_ripple_effect) {
                $output .= '<span class="fon-ripple-effect rounded-4"></span>';
            }

            $output .= $modalButton;
            $output .= '</span>';
        }

        $output .= '</div>';
        return $output;
    }

    private function news_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetPages($content, $moduleId, $pageData, 'news');
    }

    private function number_box_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        $style .= '#' . $widgetId . ' .number-box .number{';
        if (isset($content->number_size) && $content->number_size) {
            $style .= 'font-size:' . $content->number_size . 'px;';
        }
        if (isset($content->number_weight) && $content->number_weight) {
            $style .= 'font-weight:' . $content->number_weight . ';';
        }

        $style .= 'width:' . $content->number_size . 'px;';
        $style .= 'height:' . $content->number_size . 'px;';
        $style .= 'line-height:' . $content->number_size . 'px;';
        if (isset($content->number_color_type) && $content->number_color_type == 'flat') {
            $style .= '--bs-normal-color:' . $content->number_color->normal . ';';
            $style .= '--bs-hover-color:' . $content->number_color->hover . ';';
        }
        else if (isset($content->number_color_type) && $content->number_color_type == 'gradient') {
            $style .= self::parseGradient($content->number_gradient->normal, 'normal-color');
            $style .= self::parseGradient($content->number_gradient->hover, 'hover-color');
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .number-container{';
        if (isset($content->number_size) && $content->number_size) {
            $style .= 'width:' . ($content->number_size + 30) . 'px;';
            $style .= 'height:' . ($content->number_size + 30) . 'px;';
        }
        if (isset($content->number_border->normal) && $content->number_border->normal) {
            $style .= '--bs-normal-border:' . $content->number_border->normal . ';';
        }
        if (isset($content->number_border->hover) && $content->number_border->hover) {
            $style .= '--bs-hover-border:' . $content->number_border->hover . ';';
        }
        if (isset($content->number_radius->normal) && $content->number_radius->normal) {
            $style .= '--bs-normal-radius:' . $content->number_radius->normal . 'px;';
        }
        if (isset($content->number_radius->hover) && $content->number_radius->hover) {
            $style .= '--bs-hover-radius:' . $content->number_radius->hover . 'px;';
        }
        if (isset($content->number_shadow->normal) && $content->number_shadow->normal) {
            $style .= '--bs-normal-shadow:' . $content->number_shadow->normal . ';';
        }
        if (isset($content->number_shadow->hover) && $content->number_shadow->hover) {
            $style .= '--bs-hover-shadow:' . $content->number_shadow->hover . ';';
        }
        if (isset($content->number_background_type) && $content->number_background_type == 'flat') {
            $style .= '--bs-normal-bg:' . $content->number_bg->normal . ';';
            $style .= '--bs-hover-bg:' . $content->number_bg->hover . ';';
        }
        else if (isset($content->number_background_type) && $content->number_background_type == 'gradient') {
            $style .= self::parseGradient($content->number_bg_gradient->normal, 'normal-bg');
            $style .= self::parseGradient($content->number_bg_gradient->hover, 'hover-bg');
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .number-box-title{';
        if (isset($content->title_color->normal) && $content->title_color->normal) {
            $style .= '--bs-normal-color:' . $content->title_color->normal . ';';
        }
        if (isset($content->title_color->hover) && $content->title_color->hover) {
            $style .= '--bs-hover-color:' . $content->title_color->hover . ';';
        }

        if (isset($content->title_font)) {
            $style .= self::parseFontProperties($content->title_font);
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .number-box-desc{';
        if (isset($content->content_color->normal) && $content->content_color->normal) {
            $style .= '--bs-normal-color:' . $content->content_color->normal . ';';
        }
        if (isset($content->content_color->hover) && $content->content_color->hover) {
            $style .= '--bs-hover-color:' . $content->content_color->hover . ';';
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .number-box{';
        if (isset($content->background_type) && $content->background_type == 'flat') {
            $style .= '--bs-normal-bg:' . $content->background->normal . ';';
            $style .= '--bs-hover-bg:' . $content->background->hover . ';';
        }
        else if (isset($content->background_type) && $content->background_type == 'gradient') {
            $style .= self::parseGradient($content->background_gradient->normal, 'normal-bg');
            $style .= self::parseGradient($content->background_gradient->hover, 'hover-bg');
        }
        if (isset($content->shadow->normal) && $content->shadow->normal) {
            $style .= '--bs-normal-shadow:' . $content->shadow->normal . ';';
        }
        if (isset($content->shadow->hover) && $content->shadow->hover) {
            $style .= '--bs-hover-shadow:' . $content->shadow->hover . ';';
        }
        if (isset($content->border_radius->normal) && $content->border_radius->normal) {
            $style .= '--bs-normal-radius:' . $content->border_radius->normal . 'px;';
        }
        if (isset($content->border_radius->hover) && $content->border_radius->hover) {
            $style .= '--bs-hover-radius:' . $content->border_radius->hover . 'px;';
        }
        if (isset($content->use_border) && $content->use_border == 'yes') {
            if (isset($content->border->normal) && $content->border->normal) {
                $style .= '--bs-normal-border:' . $content->border->normal . ';';
            }
            if (isset($content->border->hover) && $content->border->hover) {
                $style .= '--bs-hover-border:' . $content->border->hover . ';';
            }
        }
        if (isset($content->padding) && $content->padding) {
            $style .= 'padding:' . $content->padding . 'px;';
        }

        $style .= '}';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = '';

        if ($content->number_position == 'top') {
            $attributes .= 'align-items-center ';

            switch ($content->align) {
            case 'left':
                $attributes .= 'justify-content-start text-start';
                break;
            case 'right':
                $attributes .= 'justify-content-end text-end';
                break;
            case 'center':
                $attributes .= 'justify-content-center text-center';
                break;
            }
        }
        else {
            if ($content->number_position == 'left') {
                $attributes .= 'justify-content-start text-start ';
            }
            else if ($content->number_position == 'right') {
                $attributes .= 'justify-content-end text-end ';
            }
            if (isset($content->vertical_align) && $content->vertical_align) {
                switch ($content->vertical_align) {
                case 'top':
                    $attributes .= 'align-items-start';
                    break;
                case 'bottom':
                    $attributes .= 'align-items-end';
                    break;
                case 'center':
                    $attributes .= 'align-items-bottom';
                    break;
                }
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-number-box-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<div class="number-box number-' . $content->number_position . ' ' . $attributes . ' ' . $content->background_type . '">';
        $output .= '<div class="number-box-number">';
        $output .= '<div class="number-container ' . $content->number_background_type . '">';
        $output .= '<div class="number ' . $content->number_color_type . '">';
        $output .= trim($content->number);
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '<div class="number-box-content">';
        $contentTitle = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $contentDesc = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');

        if ($contentTitle) {
            $output .= '<' . $content->heading_selector . ' class="number-box-title">';
            $output .= $contentTitle;
            $output .= '</' . $content->heading_selector . '>';
        }

        if ($contentDesc) {
            $output .= '<div class="number-box-desc">';
            $output .= $contentDesc;
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function page_menu_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $items = (isset($content->items) && $content->items ? $content->items : []);
        $enable_fixed = (isset($content->enable_fixed) && $content->enable_fixed == 'yes' ? true : false);
        $menu_type = (isset($content->menu_type) && $content->menu_type ? $content->menu_type : 'menu');
        $menu_align = (isset($content->menu_align) && $content->menu_align ? $content->menu_align : 'start');
        $menu_position = (isset($content->menu_position) && $content->menu_position ? $content->menu_position : 'right');
        $menu_seperate = (isset($content->menu_seperate) && $content->menu_seperate == 'yes' ? true : false);
        $disable = (isset($content->disable) && $content->disable ? $content->disable : (object) ['xl' => 'block', 'lg' => 'block', 'md' => 'block', 'sm' => 'none', 'xs' => 'none']);
        $style = '';
        $style .= '#' . $widgetId . ' .nav-link{';
        if (isset($content->link_color->normal) && $content->link_color->normal) {
            $style .= '--link-color:' . $content->link_color->normal . ';';
        }
        if (isset($content->link_color->hover) && $content->link_color->hover) {
            $style .= '--link-color-hover:' . $content->link_color->hover . ';';
        }
        if (isset($content->link_backround->normal) && $content->link_backround->normal) {
            $style .= '--background-color:' . $content->link_backround->normal . ';';
        }
        if (isset($content->link_backround->hover) && $content->link_backround->hover) {
            $style .= '--background-color-hover:' . $content->link_backround->hover . ';';
        }
        if (isset($content->icon_color->normal) && $content->icon_color->normal) {
            $style .= '--icon-color:' . $content->icon_color->normal . ';';
        }
        if (isset($content->icon_color->hover) && $content->icon_color->hover) {
            $style .= '--icon-color-hover:' . $content->icon_color->hover . ';';
        }
        if (isset($content->link_font) && $content->link_font) {
            $style .= self::parseFontProperties($content->link_font);
        }

        $style .= '}';
        if (isset($content->link_padding) && $content->link_padding) {
            $responsiveItems = [
                '.nav-link' => [
                ['type' => 'padding', 'value' => $content->link_padding]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $menuClasses = ['page-inner-nav', 'gumshoe'];
        if ($enable_fixed && $menu_type != 'float') {
            $menuClasses[] = 'nav-fixed';
        }

        if ($menu_type == 'menu') {
            $menuClasses[] = 'nav-' . $menu_align;
        }

        if ($menu_type == 'float') {
            $menuClasses[] = 'nav-' . $menu_position;
        }

        if ($menu_type) {
            $menuClasses[] = 'nav-' . $menu_type;
        }

        if ($menu_type == 'menu') {
            $menuClasses[] = 'navbar navbar-expand-sm p-sm-0';
        }
        if ($menu_seperate && $menu_align != 'center') {
            $menuClasses[] = 'nav-seperate';
        }
        if (isset($content->fon_class) && $content->fon_class) {
            $menuClasses[] = $content->fon_class;
        }

        foreach ($disable as $k => $d) {
            if ($k == 'xs') {
                $menuClasses[] = 'd-' . $d;
            }
            else {
                $menuClasses[] = 'd-' . $k . '-' . $d;
            }
        }

        $this->addAsset('gumshoe');
        $output = '';

        if ($items) {
            $output .= '<div id="' . $widgetId . '" class="' . implode(' ', $menuClasses) . '">';

            if ($menu_type == 'menu') {
                $output .= '<div class="container">';
                $output .= '<a class="navbar-brand d-inline-block d-sm-none fs-16 fw-bold" href="javascript:void(0)">' . __('theme/quick_access') . '</a>';
                $output .= '<button class="navbar-toggler collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#' . $widgetId . 'navbar" aria-controls="navbarsExample03" aria-expanded="false" aria-label="Toggle navigation">' . "\n" . '                    <i class="fa-solid fa-bars"></i>';
                $output .= '</button>';
                $output .= '<div class="navbar-collapse collapse w-100" id="' . $widgetId . 'navbar" style="">';
            }

            $output .= '<ul class="nav ' . ($menu_type != 'menu' ? 'list-group' : 'w-100 flex-column flex-sm-row') . '">';

            foreach ($items as $key => $item) {
                if ($item) {
                    $menu_title = (isset($item->menu_title->{$this->lang}) && $item->menu_title->{$this->lang} ? $item->menu_title->{$this->lang} : array_values((array) $item->menu_title)[0] ?? '');
                    $menu_external = (isset($item->menu_external) && $item->menu_external == 'yes' ? true : false);
                    $menu_link = (isset($item->menu_link) && $item->menu_link ? $item->menu_link : '#');
                    $menu_external_link = (isset($item->menu_external_link->{$this->lang}) && $item->menu_external_link->{$this->lang} ? $item->menu_external_link->{$this->lang} : '#');
                    $menu_target = (isset($item->menu_target) && $item->menu_target ? $item->menu_target : '_self');
                    $show_icon = (isset($item->show_icon) && $item->show_icon == 'yes' ? true : false);
                    $menu_icon = (isset($item->menu_icon) && $item->menu_icon ? $item->menu_icon : '');

                    if ($menu_external) {
                        $menu_external_link = self::checkLink($menu_external_link);
                    }
                    $output .= '<li class="nav-item ' . (($key == 0) && !$menu_external ? 'active' : '') . ' ' . ($menu_type == 'list' ? 'list-group-item' : '') . '">';
                    $output .= '<a class="nav-link ' . ($menu_external ? 'external-link' : 'fon-scroll-button') . '" ' . (($key == 0) && !$menu_external ? 'aria-current="page"' : '') . ' href="' . ($menu_external ? $menu_external_link : $menu_link) . '" ' . ($menu_external ? 'target="' . $menu_target . '"' : '') . '>';

                    if ($menu_type == 'float') {
                        $output .= '<span class="nav-link-icon">';
                        if ($show_icon && $menu_icon) {
                            $output .= '<i class="' . $menu_icon . '"></i>';
                        }
                        else {
                            $output .= '<i class="fa-solid fa-circle"></i>';
                        }

                        $output .= '</span>';
                        $output .= '<span class="nav-link-text">';
                        $output .= $menu_title;
                        $output .= '</span>';
                    }
                    else {
                        $output .= ($show_icon && $menu_icon ? '<i class="' . $menu_icon . '"></i> ' : '');
                        $output .= $menu_title;
                    }

                    $output .= '</a>';
                    $output .= '</li>';
                }
            }

            $output .= '</ul>';

            if ($menu_type == 'menu') {
                $output .= '</div>';
                $output .= '</div>';
            }

            $output .= '</div>';
        }

        return $output;
    }

    private function product_wizard_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        require_once __DIR__ . '/builder/widget-styles/product_wizard.php';
        $widgetId = 'fon-widget-' . $moduleId;
        $scriptId = 'fon-widget-' . $moduleId . '-data';
        $display_mode = (isset($content->display_mode) && $content->display_mode ? $content->display_mode : 'inline');
        $trigger_class = (isset($content->trigger_class) && $content->trigger_class ? $content->trigger_class : 'btn btn-default btn-lg');
        $trigger_align = (isset($content->trigger_align) && $content->trigger_align ? $content->trigger_align : 'center');
        $container_width = (isset($content->container_width) && $content->container_width ? $content->container_width : '');
        $container_width = ProductWizardHelper::getValidatedMaxWidth($container_width);
        $accent_color = (isset($content->accent_color) && $content->accent_color ? $content->accent_color : '#4f46e5');
        $trigger_text = self::getFieldMultilingualText($content->trigger_text ?? NULL, $this->lang, 'Ürün Sihirbazı');
        $back_btn_text = self::getFieldMultilingualText($content->back_btn_text ?? NULL, $this->lang, 'Geri');
        $next_btn_text = self::getFieldMultilingualText($content->next_btn_text ?? NULL, $this->lang, 'Devam Et');
        $result_btn_text = self::getFieldMultilingualText($content->result_btn_text ?? NULL, $this->lang, 'Sonucu Görüntüle');
        $restart_btn_text = self::getFieldMultilingualText($content->restart_btn_text ?? NULL, $this->lang, 'Testi Yeniden Başlat');
        $result_badge_text = self::getFieldMultilingualText($content->result_badge_text ?? NULL, $this->lang, 'Analiz Tamamlandı');
        $result_title_text = self::getFieldMultilingualText($content->result_title_text ?? NULL, $this->lang, 'Sizin için en uygun plan');
        $result_subtitle_text = self::getFieldMultilingualText($content->result_subtitle_text ?? NULL, $this->lang, 'Verdiğiniz yanıtlara göre aşağıdaki paketi öneriyoruz.');
        $planIds = (isset($content->plans) && $content->plans ? $content->plans : 'none');
        $plans = [];
        $finalPlans = [];
        $scoresMap = [];

        if ($planIds != 'none') {
            $planIds = ProductWizardHelper::parsePlanSource($planIds);

            if ($planIds) {
                $plans = $this->getProducts('', $planIds, count($planIds), true);
            }
        }

        if ($plans) {
            $colorMap = ProductWizardHelper::generateColorClasses($plans);

            foreach ($plans as $k => $plan) {
                $scoresMap[$plan['id']] = 0;
                $id = $plan['id'];
                $type = $plan['type'] ?? '';
                $features = $plan['features'] ?? NULL;
                $options = $plan['options'] ?? [];
                $prices = $plan['prices'] ?? [];
                $currency_symbols = self::getCurrencySymbols();
                $productPrice = self::calculatePrices($prices, $currency_symbols, $plan['override_usrcurrency'], $type);
                $desc = '';
                $featuresArr = ProductWizardHelper::maybeJsonToArray($features);
                if ($featuresArr !== null && isset($featuresArr['slogan'])) {
                    $desc = $featuresArr['slogan'];
                }

                $featuresList = [];

                if ($type === 'server') {
                    $featuresList = ProductWizardHelper::parseFeaturesServer($options);
                }
                else if ($type === 'special') {
                    if ($featuresArr !== null) {
                        if (isset($featuresArr['features'])) {
                            $featuresList = ProductWizardHelper::parseFeaturesArray($featuresArr);
                        }
                        else {
                            $clOptions = ProductWizardHelper::maybeJsonToArray($plan['cl_options'] ?? NULL) ?? [];
                            $featuresList = ProductWizardHelper::parseFeaturesSpecialColumns($featuresArr, $clOptions);
                        }
                    }
                    else {
                        $featuresList = ProductWizardHelper::parseFeaturesString((string) $features);
                    }
                }
                else if ($featuresArr !== null) {
                    if (isset($featuresArr['features'])) {
                        $featuresList = ProductWizardHelper::parseFeaturesArray($featuresArr);
                    }
                }
                else if (is_string($features) && trim($features) !== '') {
                    $featuresList = ProductWizardHelper::parseFeaturesString($features);
                }
                if (isset($plan['options_lang']['external_link']) && $plan['options_lang']['external_link'] != '') {
                    $buy_link = $plan['options_lang'];
                }
                else if (isset($plan['options']['external_link']) && $plan['options']['external_link'] != '') {
                    $buy_link = $plan['options']['external_link'];
                }
                else {
                    $buy_link = Controllers::$init->CRLink('order-steps', [$type, $id]);
                }
                if (isset($plan['options_lang']['buy_button_name']) && $plan['options_lang']['buy_button_name'] != '') {
                    $buy_button_name = $plan['options_lang']['buy_button_name'];
                }
                else if (isset($plan['options']['buy_button_name']) && $plan['options']['buy_button_name'] != '') {
                    $buy_button_name = $plan['options']['buy_button_name'];
                }
                else {
                    $buy_button_name = __('website/index/add-basket-button');
                }
                $finalPlans[$id] = ['colorClass' => $colorMap[$id], 'name' => $plan['title'] ?? '', 'desc' => $desc, 'price' => (isset($productPrice['price']) && $productPrice['price'] ? strip_tags($productPrice['price']) : ''), 'period' => $productPrice['period'] ?? '', 'features' => $featuresList, 'buyLink' => $buy_link, 'buyButtonName' => $buy_button_name];
            }
        }
        $steps = (isset($content->questions) && $content->questions ? $content->questions : []);
        $finalSteps = [];
        $countSteps = count($steps);

        if ($steps) {
            foreach ($steps as $k => $step) {
                $title = self::getFieldMultilingualText($step->title ?? NULL, $this->lang, 'Soru ' . ($k + 1));
                $desc = self::getFieldMultilingualText($step->desc ?? NULL, $this->lang, '');
                $options = [];
                if (isset($step->options) && is_array($step->options) && 0 < count($step->options)) {
                    foreach ($step->options as $option) {
                        $optionTitle = self::getFieldMultilingualText($option->title ?? NULL, $this->lang, '');
                        $optionDesc = self::getFieldMultilingualText($option->desc ?? NULL, $this->lang, '');
                        $optionIcon = $option->icon ?? '';
                        $optionScores = $option->scores ?? '';
                        if (!empty($optionScores) && is_string($optionScores)) {
                            $optionScores = ProductWizardHelper::parseScores($optionScores);
                        }

                        $options[] = ['icon' => $optionIcon, 'title' => $optionTitle, 'desc' => $optionDesc, 'score' => $optionScores];
                    }
                }
                if ($title && $options) {
                    $finalSteps[] = ['question' => $title, 'desc' => $desc, 'options' => $options];
                }
            }
        }

        $payload = [
            'scriptId'  => $scriptId,
            'widgetId'  => $widgetId,
            'labels'    => ['resultBtn' => $result_btn_text, 'restartBtn' => $restart_btn_text, 'resultBadge' => $result_badge_text, 'resultTitle' => $result_title_text, 'resultSubtitle' => $result_subtitle_text, 'triggerText' => $trigger_text, 'triggerClass' => $trigger_class, 'backBtn' => $back_btn_text, 'nextBtn' => $next_btn_text, 'accentColor' => $accent_color],
            'steps'     => $finalSteps,
            'plans'     => $finalPlans,
            'scoresMap' => $scoresMap
        ];
        $encoded = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

        if (!is_string($encoded)) {
            $encoded = '{}';
        }

        $style = '';

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $this->addAsset('fon-product-wizard');
        $output = '';

        if ($steps) {
            $modalUid = 'fonPWModal_' . md5($widgetId);

            if ($display_mode === 'modal') {
                $output .= '<p class="text-' . $trigger_align . '">';
                $output .= '<button type="button" class="' . htmlspecialchars($trigger_class) . '" data-bs-toggle="modal" data-bs-target="#' . $modalUid . '">';
                $output .= '<i class="fa-solid fa-wand-magic-sparkles me-2"></i>' . $trigger_text;
                $output .= '</button>';
                $output .= '</p>';
                $output .= '<div class="modal fade" id="' . $modalUid . '" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-hidden="true">';
                $output .= '    <div class="modal-dialog modal-dialog-centered fon-wz-dialog">';
                $output .= '        <div class="modal-content border-0 p-0 rounded-4 overflow-hidden position-relative">';
                $output .= '            <button type="button" class="fon-wz-modal-close" data-bs-dismiss="modal" aria-label="Kapat">✕</button>';
            }

            $maxWidthStyle = ($display_mode === 'modal' ? '' : 'max-width:' . $container_width . ';');
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-product-wizard-widget ' . ($content->fon_class ?? '') . '" data-display="' . $display_mode . '" data-script-id="' . $scriptId . '" style="--fpw-accent:' . $accent_color . '; ' . $maxWidthStyle . '" ' . ($display_mode === 'modal' ? 'data-modal-id="' . $modalUid . '"' : '') . '>';
            $output .= '    <div class="fon-wizard-progress">';
            $output .= '        <div class="fon-wizard-progress-fill" style="width:25%"></div>';
            $output .= '    </div>';
            $output .= '    <div class="fon-wizard-header">';
            $output .= '        <div class="fon-wizard-step-label">' . __('theme/wizard-step') . ' <span class="fon-current-step">1</span> / ' . $countSteps . '</div>';
            $output .= '        <p class="fon-wizard-question"></p>';
            $output .= '        <p class="fon-wizard-desc"></p>';
            $output .= '    </div>';
            $output .= '    <div class="fon-wizard-body">';
            $output .= '        <div class="fon-wizard-options fon-step-panel"></div>';
            $output .= '    </div>';
            $output .= '    <div class="fon-wizard-footer">';
            $output .= '        <button type="button" class="fon-btn-back" disabled><i class="fa-solid fa-angle-left"></i> ' . $back_btn_text . '</button>';
            $output .= '        <div class="fon-wizard-dots"></div>';
            $output .= '        <button type="button" class="fon-btn-next" disabled>' . $next_btn_text . ' <i class="fa-solid fa-angle-right"></i> </button>';
            $output .= '    </div>';
            $output .= '</div>';

            if ($display_mode === 'modal') {
                $output .= '        </div>';
                $output .= '    </div>';
                $output .= '</div>';
            }

            $output .= '<script type="application/json" id="' . $scriptId . '">' . htmlspecialchars($encoded, ENT_NOQUOTES, 'UTF-8') . '</script>';
        }

        return $output;
    }

    private function progress_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $type = (isset($content->type) && $content->type ? $content->type : 'bar');
        $striped = (isset($content->striped) && $content->striped == 'yes' ? true : false);
        $animated = (isset($content->animated) && $content->animated == 'yes' ? true : false);
        $column = (isset($content->column) && $content->column ? (array) $content->column : ['xl' => 4, 'lg' => 4, 'md' => 3, 'sm' => 2, 'xs' => 1]);
        $width = (isset($content->width) && $content->width ? $content->width : '160');
        $items = (isset($content->items) && $content->items ? $content->items : []);
        $xs = min(6, max(1, (int) ($column['xs'] ?? 1)));
        $sm = min(6, max(1, (int) ($column['sm'] ?? 2)));
        $md = min(6, max(1, (int) ($column['md'] ?? 3)));
        $lg = min(6, max(1, (int) ($column['lg'] ?? 4)));
        $xl = min(6, max(1, (int) ($column['xl'] ?? 4)));
        $rowClasses = sprintf('row g-3 row-cols-%d row-cols-sm-%d row-cols-md-%d row-cols-lg-%d row-cols-xl-%d', $xs, $sm, $md, $lg, $xl);
        $style = '';

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';

        if ($items) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-progress-widget ' . ($content->fon_class ?? '') . '">';

            if ($type == 'circle') {
                $output .= '<div class="fon-progress-circle-wrapper ' . $rowClasses . '">';
            }

            foreach ($items as $index => $item) {
                $title = '';

                if (is_object($item->title)) {
                    $title = (isset($item->title->{$this->lang}) && $item->title->{$this->lang} ? $item->title->{$this->lang} : array_values((array) $item->title)[0] ?? '');
                }
                else if (is_string($item->title)) {
                    $title = $item->title;
                }

                $subtitle = '';

                if (is_object($item->subtitle)) {
                    $subtitle = (isset($item->subtitle->{$this->lang}) && $item->subtitle->{$this->lang} ? $item->subtitle->{$this->lang} : array_values((array) $item->subtitle)[0] ?? '');
                }
                else if (is_string($item->subtitle)) {
                    $subtitle = $item->subtitle;
                }

                $description = '';

                if (is_object($item->description)) {
                    $description = (isset($item->description->{$this->lang}) && $item->description->{$this->lang} ? $item->description->{$this->lang} : array_values((array) $item->description)[0] ?? '');
                }
                else if (is_string($item->description)) {
                    $description = $item->description;
                }
                $value = (isset($item->value) && $item->value ? $item->value : '0');
                $color = (isset($item->color) && $item->color ? $item->color : 'var(--theme-primary)');

                if ($type == 'bar') {
                    $output .= '<div class="fon-progress-wrapper" data-value="' . $value . '">';
                    $output .= '<div class="fon-progress-info">';
                    $output .= '<h3 class="fon-progress-title">' . $title . '</h3>';

                    if ($subtitle) {
                        $output .= '<span class="fon-progress-percent"><span class="fon-progress-sub me-1 fw-normal">' . $subtitle . '</span><span class="fon-progress-rate" style="color: ' . $color . ';">0%</span></span>';
                    }
                    else {
                        $output .= '<span class="fon-progress-percent"><span class="fon-progress-rate" style="color: ' . $color . ';">0%</span></span>';
                    }

                    $output .= '</div>';
                    $output .= '<div class="progress fon-custom-progress">';
                    $output .= '<div class="progress-bar ' . ($striped ? 'progress-bar-striped' : '') . ' ' . ($striped && $animated ? 'progress-bar-animated' : '') . '" ' . "\n" . '                                    role="progressbar" ' . "\n" . '                                    style="width: 0%; background-color: ' . $color . ';"' . "\n" . '                                    aria-valuenow="' . $value . '" ' . "\n" . '                                    aria-valuemin="0" ' . "\n" . '                                    aria-valuemax="100">';
                    $output .= '</div>';
                    $output .= '</div>';

                    if ($description) {
                        $output .= '<p class="fon-progress-description mt-2">' . $description . '</p>';
                    }

                    $output .= '</div>';
                }
                else if ($type == 'circle') {
                    $output .= '<div class="col">';
                    $output .= '<div class="fon-circle-progress-wrapper text-center" data-value="' . $value . '">';
                    $output .= '<div class="fon-circle-progress-container mx-auto mb-3 position-relative" style="width: ' . $width . 'px;">';
                    $output .= '<svg viewBox="0 0 100 100">';
                    $output .= '<circle class="fon-circle-progress-bg" cx="50" cy="50" r="45"></circle>';
                    $output .= '<circle class="fon-circle-progress-bar is-striped is-animated" cx="50" cy="50" r="45" style="stroke: ' . $color . '"></circle>';
                    $output .= '</svg>';
                    $output .= '<div class="fon-circle-progress-info">';
                    $output .= '<span class="fon-circle-progress-percent">0%</span>';

                    if ($subtitle) {
                        $output .= '<span class="fon-progress-sub mx-auto">' . $subtitle . '</span>';
                    }

                    $output .= '</div>';
                    $output .= '</div>';

                    if ($title) {
                        $output .= '<h3 class="fon-progress-title d-inline-block my-2">' . $title . '</h3>';
                    }

                    if ($description) {
                        $output .= '<p class="fon-progress-description px-3">' . $description . '</p>';
                    }

                    $output .= '</div>';
                    $output .= '</div>';
                }
            }

            if ($type == 'circle') {
                $output .= '</div>';
            }

            $output .= '</div>';
        }

        return $output;
    }

    private function raw_content_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $raw_code = (isset($content->raw_code->{$this->lang}) && $content->raw_code->{$this->lang} ? $content->raw_code->{$this->lang} : array_values((array) $content->raw_code)[0] ?? '');

        if ($raw_code) {
            $raw_code = self::parseShortcodesToHtml($raw_code);
        }

        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="' . $content->fon_class . '">';
        $output .= $raw_code;
        $output .= '</div>';
        return $output;
    }

    private function references_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetPages($content, $moduleId, $pageData, 'references');
    }

    private function review_badge_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'micro_button');
        $value_display = (isset($content->value_display) && $content->value_display ? $content->value_display : 'both');
        $review_provider = (isset($content->review_provider) && $content->review_provider ? $content->review_provider : 'google');
        $review_title = (isset($content->review_title->{$this->lang}) && $content->review_title->{$this->lang} ? $content->review_title->{$this->lang} : $this->language['review_badge']['default_title']);
        $review_score = (isset($content->review_score) && $content->review_score ? $content->review_score : 0);
        $review_count = (isset($content->review_count) && $content->review_count ? $content->review_count : 0);
        $review_link = (isset($content->review_link) && $content->review_link ? $content->review_link : '');
        $review_link_rel = (isset($content->review_link_rel) && $content->review_link_rel ? $content->review_link_rel : []);
        $review_link_rel = ($review_link_rel ? ' rel="' . implode(' ', $review_link_rel) . '" ' : '');
        $color = ($review_provider == 'trustpilot' ? '#00B67A' : '#fbb004');
        $svgStyle = 'height: 25px;';
        $starSize = 18;
        $ticonfill = '#00b67a';
        $ticon2fill = '#005128';
        $ttextfill = '#191919';

        switch ($widget_style) {
        case 'micro_button':
            $ticonfill = $ttextfill = '#fff';
            $ticon2fill = '#00b67a';
            break;
        case 'micro_horizontal':
            break;
        case 'mini_box':
            $svgStyle = 'height: 35px;';
            $starSize = 25;
            break;
        case 'flex_box':
            $svgStyle = 'height: 35px;';
            $starSize = 20;
            $ttextfill = '#fff';
            break;
        case 'flex_mini':
            $svgStyle = 'height: 20px;';
            $starSize = 12;
            $ttextfill = '#fff';
            break;
        }

        $stars = self::getStarRating($review_score, $color, $starSize);
        $trustpilot = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1132.8 278.2" style="' . $svgStyle . '" preserveAspectRatio="xMidYMid" ><path d="M297.7 98.6h114.7V120h-45.1v120.3h-24.8V120h-44.9V98.6zm109.8 39.1h21.2v19.8h.4c.7-2.8 2-5.5 3.9-8.1 1.9-2.6 4.2-5.1 6.9-7.2 2.7-2.2 5.7-3.9 9-5.3 3.3-1.3 6.7-2 10.1-2 2.6 0 4.5.1 5.5.2s2 .3 3.1.4v21.8c-1.6-.3-3.2-.5-4.9-.7-1.7-.2-3.3-.3-4.9-.3-3.8 0-7.4.8-10.8 2.3-3.4 1.5-6.3 3.8-8.8 6.7-2.5 3-4.5 6.6-6 11s-2.2 9.4-2.2 15.1v48.8h-22.6V137.7zm164 102.6h-22.2V226h-.4c-2.8 5.2-6.9 9.3-12.4 12.4-5.5 3.1-11.1 4.7-16.8 4.7-13.5 0-23.3-3.3-29.3-10s-9-16.8-9-30.3v-65.1H504v62.9c0 9 1.7 15.4 5.2 19.1 3.4 3.7 8.3 5.6 14.5 5.6 4.8 0 8.7-.7 11.9-2.2 3.2-1.5 5.8-3.4 7.7-5.9 2-2.4 3.4-5.4 4.3-8.8.9-3.4 1.3-7.1 1.3-11.1v-59.5h22.6v102.5zm38.5-32.9c.7 6.6 3.2 11.2 7.5 13.9 4.4 2.6 9.6 4 15.7 4 2.1 0 4.5-.2 7.2-.5s5.3-1 7.6-1.9c2.4-.9 4.3-2.3 5.9-4.1 1.5-1.8 2.2-4.1 2.1-7-.1-2.9-1.2-5.3-3.2-7.1-2-1.9-4.5-3.3-7.6-4.5-3.1-1.1-6.6-2.1-10.6-2.9-4-.8-8-1.7-12.1-2.6-4.2-.9-8.3-2.1-12.2-3.4-3.9-1.3-7.4-3.1-10.5-5.4-3.1-2.2-5.6-5.1-7.4-8.6-1.9-3.5-2.8-7.8-2.8-13 0-5.6 1.4-10.2 4.1-14 2.7-3.8 6.2-6.8 10.3-9.1 4.2-2.3 8.8-3.9 13.9-4.9 5.1-.9 10-1.4 14.6-1.4 5.3 0 10.4.6 15.2 1.7 4.8 1.1 9.2 2.9 13.1 5.5 3.9 2.5 7.1 5.8 9.7 9.8 2.6 4 4.2 8.9 4.9 14.6h-23.6c-1.1-5.4-3.5-9.1-7.4-10.9-3.9-1.9-8.4-2.8-13.4-2.8-1.6 0-3.5.1-5.7.4-2.2.3-4.2.8-6.2 1.5-1.9.7-3.5 1.8-4.9 3.2-1.3 1.4-2 3.2-2 5.5 0 2.8 1 5 2.9 6.7 1.9 1.7 4.4 3.1 7.5 4.3 3.1 1.1 6.6 2.1 10.6 2.9 4 .8 8.1 1.7 12.3 2.6 4.1.9 8.1 2.1 12.1 3.4 4 1.3 7.5 3.1 10.6 5.4 3.1 2.3 5.6 5.1 7.5 8.5 1.9 3.4 2.9 7.7 2.9 12.7 0 6.1-1.4 11.2-4.2 15.5-2.8 4.2-6.4 7.7-10.8 10.3-4.4 2.6-9.4 4.6-14.8 5.8-5.4 1.2-10.8 1.8-16.1 1.8-6.5 0-12.5-.7-18-2.2-5.5-1.5-10.3-3.7-14.3-6.6-4-3-7.2-6.7-9.5-11.1-2.3-4.4-3.5-9.7-3.7-15.8H610zm74.6-69.7h17.1v-30.8h22.6v30.8h20.4v16.9h-20.4v54.8c0 2.4.1 4.4.3 6.2.2 1.7.7 3.2 1.4 4.4.7 1.2 1.8 2.1 3.3 2.7 1.5.6 3.4.9 6 .9 1.6 0 3.2 0 4.8-.1 1.6-.1 3.2-.3 4.8-.7v17.5c-2.5.3-5 .5-7.3.8-2.4.3-4.8.4-7.3.4-6 0-10.8-.6-14.4-1.7-3.6-1.1-6.5-2.8-8.5-5-2.1-2.2-3.4-4.9-4.2-8.2-.7-3.3-1.2-7.1-1.3-11.3v-60.5h-17.1v-17.1zm76.1 0h21.4v13.9h.4c3.2-6 7.6-10.2 13.3-12.8 5.7-2.6 11.8-3.9 18.5-3.9 8.1 0 15.1 1.4 21.1 4.3 6 2.8 11 6.7 15 11.7 4 5 6.9 10.8 8.9 17.4 2 6.6 3 13.7 3 21.2 0 6.9-.9 13.6-2.7 20-1.8 6.5-4.5 12.2-8.1 17.2-3.6 5-8.2 8.9-13.8 11.9-5.6 3-12.1 4.5-19.7 4.5-3.3 0-6.6-.3-9.9-.9-3.3-.6-6.5-1.6-9.5-2.9-3-1.3-5.9-3-8.4-5.1-2.6-2.1-4.7-4.5-6.5-7.2h-.4v51.2h-22.6V137.7zm79 51.4c0-4.6-.6-9.1-1.8-13.5-1.2-4.4-3-8.2-5.4-11.6-2.4-3.4-5.4-6.1-8.9-8.1-3.6-2-7.7-3.1-12.3-3.1-9.5 0-16.7 3.3-21.5 9.9-4.8 6.6-7.2 15.4-7.2 26.4 0 5.2.6 10 1.9 14.4 1.3 4.4 3.1 8.2 5.7 11.4 2.5 3.2 5.5 5.7 9 7.5 3.5 1.9 7.6 2.8 12.2 2.8 5.2 0 9.5-1.1 13.1-3.2 3.6-2.1 6.5-4.9 8.8-8.2 2.3-3.4 4-7.2 5-11.5.9-4.3 1.4-8.7 1.4-13.2zm39.9-90.5h22.6V120h-22.6V98.6zm0 39.1h22.6v102.6h-22.6V137.7zm42.8-39.1H945v141.7h-22.6V98.6zm91.9 144.5c-8.2 0-15.5-1.4-21.9-4.1-6.4-2.7-11.8-6.5-16.3-11.2-4.4-4.8-7.8-10.5-10.1-17.1-2.3-6.6-3.5-13.9-3.5-21.8 0-7.8 1.2-15 3.5-21.6 2.3-6.6 5.7-12.3 10.1-17.1 4.4-4.8 9.9-8.5 16.3-11.2 6.4-2.7 13.7-4.1 21.9-4.1s15.5 1.4 21.9 4.1c6.4 2.7 11.8 6.5 16.3 11.2 4.4 4.8 7.8 10.5 10.1 17.1 2.3 6.6 3.5 13.8 3.5 21.6 0 7.9-1.2 15.2-3.5 21.8-2.3 6.6-5.7 12.3-10.1 17.1-4.4 4.8-9.9 8.5-16.3 11.2-6.4 2.7-13.7 4.1-21.9 4.1zm0-17.9c5 0 9.4-1.1 13.1-3.2 3.7-2.1 6.7-4.9 9.1-8.3 2.4-3.4 4.1-7.3 5.3-11.6 1.1-4.3 1.7-8.7 1.7-13.2 0-4.4-.6-8.7-1.7-13.1s-2.9-8.2-5.3-11.6c-2.4-3.4-5.4-6.1-9.1-8.2-3.7-2.1-8.1-3.2-13.1-3.2s-9.4 1.1-13.1 3.2c-3.7 2.1-6.7 4.9-9.1 8.2-2.4 3.4-4.1 7.2-5.3 11.6-1.1 4.4-1.7 8.7-1.7 13.1 0 4.5.6 8.9 1.7 13.2 1.1 4.3 2.9 8.2 5.3 11.6 2.4 3.4 5.4 6.2 9.1 8.3 3.7 2.2 8.1 3.2 13.1 3.2zm58.4-87.5h17.1v-30.8h22.6v30.8h20.4v16.9h-20.4v54.8c0 2.4.1 4.4.3 6.2.2 1.7.7 3.2 1.4 4.4.7 1.2 1.8 2.1 3.3 2.7 1.5.6 3.4.9 6 .9 1.6 0 3.2 0 4.8-.1 1.6-.1 3.2-.3 4.8-.7v17.5c-2.5.3-5 .5-7.3.8-2.4.3-4.8.4-7.3.4-6 0-10.8-.6-14.4-1.7-3.6-1.1-6.5-2.8-8.5-5-2.1-2.2-3.4-4.9-4.2-8.2-.7-3.3-1.2-7.1-1.3-11.3v-60.5h-17.1v-17.1z" fill="' . $ttextfill . '"/><path fill="' . $ticonfill . '" d="M271.3 98.6H167.7L135.7 0l-32.1 98.6L0 98.5l83.9 61L51.8 258l83.9-60.9 83.8 60.9-32-98.5 83.8-60.9z"/><path fill="' . $ticon2fill . '" d="M194.7 181.8l-7.2-22.3-51.8 37.6z"/></svg>';
        $google = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 168" style="' . $svgStyle . '" preserveAspectRatio="xMidYMid"><g>' . "\n" . '                <path d="M496.052455,102.672055 L510.255737,112.140909 C505.6459,118.931075 494.619668,130.580258 475.557368,130.580258 C451.885231,130.580258 434.255719,112.2655 434.255719,88.967133 C434.255719,64.1736841 452.072116,47.3540078 473.563925,47.3540078 C495.180323,47.3540078 505.77049,64.5474546 509.19672,73.8294242 L511.065574,78.5638516 L455.373756,101.613038 C459.609823,109.960581 466.213103,114.196648 475.557368,114.196648 C484.901633,114.196648 491.380323,109.586811 496.052455,102.672055 L496.052455,102.672055 Z M452.383592,87.6589359 L489.573765,72.2097517 C487.518026,67.0392586 481.413107,63.3638478 474.124581,63.3638478 C464.842612,63.3638478 451.947526,71.5868007 452.383592,87.6589359 L452.383592,87.6589359 Z" fill="#FF302F"/>' . "\n" . '                <path d="M407.406531,4.93104632 L425.347519,4.93104632 L425.347519,126.780257 L407.406531,126.780257 L407.406531,4.93104632 L407.406531,4.93104632 Z" fill="#20B15A"/>' . "\n" . '                <path d="M379.124557,50.5933528 L396.442594,50.5933528 L396.442594,124.599929 C396.442594,155.311412 378.314721,167.957316 356.885207,167.957316 C336.701596,167.957316 324.554051,154.376986 320.00651,143.350753 L335.891759,136.747473 C338.757334,143.537639 345.67209,151.573706 356.885207,151.573706 C370.652424,151.573706 379.124557,143.039278 379.124557,127.091732 L379.124557,121.111404 L378.501606,121.111404 C374.39013,126.095011 366.540947,130.580258 356.573731,130.580258 C335.767169,130.580258 316.704869,112.452385 316.704869,89.0917231 C316.704869,65.6064713 335.767169,47.2917126 356.573731,47.2917126 C366.478652,47.2917126 374.39013,51.7146646 378.501606,56.5736822 L379.124557,56.5736822 L379.124557,50.5933528 L379.124557,50.5933528 Z M380.370459,89.0917231 C380.370459,74.3900801 370.590128,63.6753233 358.131109,63.6753233 C345.547499,63.6753233 334.957333,74.3900801 334.957333,89.0917231 C334.957333,103.606481 345.547499,114.134352 358.131109,114.134352 C370.590128,114.196648 380.370459,103.606481 380.370459,89.0917231 L380.370459,89.0917231 Z" fill="#3686F7"/>' . "\n" . '                <path d="M218.21632,88.7802476 C218.21632,112.763861 199.527791,130.393373 176.603195,130.393373 C153.678599,130.393373 134.990069,112.701565 134.990069,88.7802476 C134.990069,64.6720448 153.678599,47.1048274 176.603195,47.1048274 C199.527791,47.1048274 218.21632,64.6720448 218.21632,88.7802476 L218.21632,88.7802476 Z M200.026151,88.7802476 C200.026151,73.8294242 189.186804,63.5507331 176.603195,63.5507331 C164.019585,63.5507331 153.180238,73.8294242 153.180238,88.7802476 C153.180238,103.606481 164.019585,114.009763 176.603195,114.009763 C189.186804,114.009763 200.026151,103.606481 200.026151,88.7802476 L200.026151,88.7802476 Z" fill="#FF302F"/>' . "\n" . '                <path d="M309.104867,88.967133 C309.104867,112.950746 290.416338,130.580258 267.491742,130.580258 C244.567146,130.580258 225.878617,112.950746 225.878617,88.967133 C225.878617,64.8589302 244.567146,47.3540078 267.491742,47.3540078 C290.416338,47.3540078 309.104867,64.796635 309.104867,88.967133 L309.104867,88.967133 Z M290.852404,88.967133 C290.852404,74.0163095 280.013057,63.7376184 267.429447,63.7376184 C254.845837,63.7376184 244.00649,74.0163095 244.00649,88.967133 C244.00649,103.793366 254.845837,114.196648 267.429447,114.196648 C280.075352,114.196648 290.852404,103.731071 290.852404,88.967133 L290.852404,88.967133 Z" fill="#FFBA40"/>' . "\n" . '                <path d="M66.5900525,112.327794 C40.4884066,112.327794 20.0556146,91.2720515 20.0556146,65.1704056 C20.0556146,39.0687598 40.4884066,18.0130168 66.5900525,18.0130168 C80.6687446,18.0130168 90.9474357,23.5572805 98.5474373,30.6589216 L111.068752,18.137607 C100.478585,7.98350613 86.3375984,0.258913997 66.5900525,0.258913997 C30.8326666,0.258913997 0.744134408,29.4130196 0.744134408,65.1704056 C0.744134408,100.927792 30.8326666,130.081897 66.5900525,130.081897 C85.9015328,130.081897 100.478585,123.727797 111.878588,111.891729 C123.590067,100.180251 127.203183,83.7343447 127.203183,70.4031939 C127.203183,66.2294223 126.704822,61.9310606 126.144166,58.7540106 L66.5900525,58.7540106 L66.5900525,76.0720477 L109.013014,76.0720477 C107.767112,86.9113947 104.340882,94.3245113 99.2949785,99.3704142 C93.1900592,105.537629 83.534319,112.327794 66.5900525,112.327794 L66.5900525,112.327794 L66.5900525,112.327794 Z" fill="#3686F7"/>' . "\n" . '            </g>' . "\n" . '        </svg>';
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-review-badge ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';

        if ($widget_style == 'micro_button') {
            $output .= '<div class="fon-review-badge-micro-button position-relative d-flex align-items-center">';
            $output .= '<div class="fon-review-badge-logo py-2 px-3 rounded-start-3 d-flex align-items-center justify-content-center border flex-shrink-0" style="background-color:' . ($review_provider == 'trustpilot' ? $color : 'var(--bs-theme-light)') . '; border-color:' . ($review_provider == 'trustpilot' ? $color : 'var(--bs-theme-light-100)') . '; height:40px;min-width:135px;">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</div>';
            $output .= '<div class="fon-review-badge-review py-2 px-3 rounded-end d-flex align-items-center bg-white border-end border-top border-bottom" style="height:40px;">';

            if ($value_display == 'score') {
                $output .= '<span class="fon-review-badge-score fs-6 text-dark strong">' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</span>';
            }
            else if ($value_display == 'count') {
                $output .= '<span class="fon-review-badge-score fs-6 text-dark strong">' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }
            else if ($value_display == 'both') {
                $output .= '<span class="fon-review-badge-score fs-6 text-dark"><strong>' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</strong> | ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }

            $output .= '</div>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }
        else if ($widget_style == 'micro_horizontal') {
            $output .= '<div class="fon-review-badge-micro-horizontal position-relative d-flex align-items-' . ($review_provider == 'trustpilot' ? 'end' : 'center') . ' gap-3">';
            $output .= '<span class="fon-review-badge-logo">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</span>';
            $output .= '<strong class="fon-review-badge-title text-dark">';
            $output .= $review_title;
            $output .= '</strong>';
            $output .= '<span class="fon-review-badge-review">';

            if ($value_display == 'score') {
                $output .= '<span class="fon-review-badge-score">' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</span>';
            }
            else if ($value_display == 'count') {
                $output .= '<span class="fon-review-badge-score">' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }
            else if ($value_display == 'both') {
                $output .= '<span class="fon-review-badge-score">' . sprintf($this->language['review_badge']['score_short'], $review_score) . ' | ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }

            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars position-relative">';
            $output .= '<span class="fon-review-badge-stars-empty d-flex gap-1">';
            $output .= str_repeat('<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white" style="width:' . ($starSize + 8) . 'px;height:' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>', 5);
            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars-fill d-flex gap-1 position-absolute start-0 top-0">' . $stars . '</span>';
            $output .= '</span>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }
        else if ($widget_style == 'mini_box') {
            $output .= '<div class="fon-review-badge-mini-box d-flex flex-column align-items-center justify-content-center position-relative">';
            $output .= '<div class="fon-review-badge-logo mb-3">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</div>';
            $output .= '<span class="fon-review-badge-stars position-relative mb-2">';
            $output .= '<span class="fon-review-badge-stars-empty d-flex gap-1">';
            $output .= str_repeat('<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white"  style="width:' . ($starSize + 8) . 'px;height:' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>', 5);
            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars-fill d-flex gap-1 position-absolute start-0 top-0">' . $stars . '</span>';
            $output .= '</span>';
            $output .= '<div class="fon-review-badge-review fs-18 fw-semibold text-dark">';

            if ($value_display == 'score') {
                $output .= '<span class="fon-review-badge-score">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</span>';
            }
            else if ($value_display == 'count') {
                $output .= '<span class="fon-review-badge-score">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }
            else if ($value_display == 'both') {
                $output .= '<span class="fon-review-badge-score">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['score_short'], $review_score) . ' | ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }

            $output .= '</div>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }
        else if ($widget_style == 'flex_box') {
            $output .= '<div class="fon-review-badge-flex-box d-flex flex-column align-items-stretch justify-content-between position-relative bg-dark rounded-4 p-4 bg-theme-light-800 overflow-hidden" style="min-height:250px;max-width: 450px;">';
            $output .= '<div class="fon-review-badge-header d-flex align-items-center justify-content-between position-relative">';
            $output .= '<h5 class="fon-review-badge-score flex-shrink-1 w-50 text-white fw-light">' . sprintf($this->language['review_badge']['score_long'], $review_score) . '</h5>';
            $output .= '<span class="fon-review-badge-icon text-white me-4 mt-4"><i class="fa-solid fa-laptop fa-3x"></i></span>';
            $output .= '</div>';
            $output .= '<div class="flex-grow-1"></div>';
            $output .= '<div class="fon-review-badge-footer d-flex align-items-end justify-content-between position-relative">';
            $output .= '<div class="fon-review-badge-review d-flex flex-column align-items-start justify-content-start">';
            $output .= '<h6 class="fon-review-badge-score text-white fw-normal mb-0">' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</h6>';
            $output .= '<div class="fon-review-badge-stars position-relative my-2">';
            $output .= '<span class="fon-review-badge-stars-empty d-flex gap-1">';
            $output .= str_repeat('<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white"  style="width:' . ($starSize + 8) . 'px;height:' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>', 5);
            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars-fill d-flex gap-1 position-absolute start-0 top-0">' . $stars . '</span>';
            $output .= '</div>';
            $output .= '<div class="fon-review-badge-title text-white">';
            $output .= $review_title;
            $output .= '</div>';
            $output .= '</div>';
            $output .= '<div class="fon-review-badge-logo position-absolute end-0 bottom-0">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</div>';
            $output .= '</div>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }
        else if ($widget_style == 'flex_mini') {
            $output .= '<div class="fon-review-badge-flex-mini d-flex align-items-center justify-content-start position-relative bg-theme-light-800 rounded-4 p-3 overflow-hidden" style="min-height:50px;">';
            $output .= '<div class="fon-review-badge-icon text-white me-5 position-relative"><i class="fa-solid fa-laptop fa-2x"></i></div>';
            $output .= '<div class="fon-review-badge-review d-flex flex-column align-items-start justify-content-start position-relative">';

            if ($value_display == 'score') {
                $output .= '<h6 class="fon-review-badge-score fs-14 mb-1 text-white">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</h6>';
            }
            else if ($value_display == 'count') {
                $output .= '<h6 class="fon-review-badge-score fs-14 mb-1 text-white">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</h6>';
            }
            else if ($value_display == 'both') {
                $output .= '<h6 class="fon-review-badge-score fs-14 mb-1 text-white">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['score_short'], $review_score) . ' | ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</h6>';
            }

            $output .= '<div class="fon-review-badge-stars position-relative">';
            $output .= '<span class="fon-review-badge-stars-empty d-flex gap-1">';
            $output .= str_repeat('<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white"  style="width:' . ($starSize + 8) . 'px;height:' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>', 5);
            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars-fill d-flex gap-1 position-absolute start-0 top-0">' . $stars . '</span>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '<div class="fon-review-badge-logo ms-auto position-relative">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</div>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function server_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetProducts($content, $moduleId, $pageData, $row, 'server');
    }

    private function sidebar_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        if ($pageData['sidebar'] && 0 < count($pageData['sidebar'])) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-sidebar-widget sidebar-' . $content->widget_style . ' ' . $content->fon_class . '">';
            $output .= '<div class="list-group ' . ($content->widget_style == 'horizontal' ? 'list-group-horizontal-md align-items-center justify-content-' . $content->align : '') . '">';

            foreach ($pageData['sidebar'] as $sidebar) {
                $output .= '<a href="' . $sidebar['link'] . '" class="list-group-item list-group-item-action">' . $sidebar['title'] . '</a>';
            }

            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function slideshow_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $autoplay = (isset($content->autoplay) && $content->autoplay == 'yes' ? 1 : 0);
        $pause_on_hover = (isset($content->pause) && $content->pause == 'yes' ? 1 : 0);
        $interval = (isset($content->interval) && $content->interval ? $content->interval : 5);
        $speed = (isset($content->speed) && $content->speed ? $content->speed : '800');
        $content_container_option = (isset($content->content_width) && $content->content_width ? $content->content_width : '');
        $slider_animation = (isset($content->animation_style) && $content->animation_style ? $content->animation_style : '');
        $content_vertical_center = (isset($content->content_vertical_center) && $content->content_vertical_center = 'yes' ? 1 : 0);
        $height = (isset($content->height) && $content->height ? $content->height : '');
        $custom_height = (isset($content->custom_height) && $content->custom_height ? $content->custom_height : (object) ['xl' => '750', 'lg' => '700', 'md' => '600', 'sm' => '500', 'xs' => '450']);
        $dot_controllers = (isset($content->dot_controllers) && $content->dot_controllers == 'yes' ? 1 : 0);
        $dot_position = (isset($content->dot_controllers_position) && $content->dot_controllers_position ? 'dot-' . $content->dot_controllers_position : 'dot-bottom_center');
        $arrow_controllers = (isset($content->arrow_controllers) && $content->arrow_controllers = 'yes' ? 1 : 0);
        $arrow_position = (isset($content->arrow_controllers_position) && $content->arrow_controllers_position ? 'arrow-' . $content->arrow_controllers_position : 'arrow-center');
        $arrow_on_hover = (isset($content->arrow_controllers_hover) && $content->arrow_controllers_hover = 'yes' ? 1 : 0);
        $arrow_class = $arrow_position;

        if ($arrow_on_hover) {
            $arrow_class .= ' arrow-show-on-hover';
        }

        $this->addAsset(['slick', 'slick-animate']);
        $style = '';
        $style .= '#' . $widgetId . '.fon-slider .fon-item:not(:first-child) { display: none; }';
        $style .= '#' . $widgetId . '.fon-slider.slick-initialized .fon-item { display: flex; }';

        if ($height == 'full') {
            $style .= '#' . $widgetId . '.fon-slider,#' . $widgetId . '.fon-slider .fon-item{';
            $style .= 'height: 100vh;';
            $style .= '}';
        }
        else {
            $responsiveItems = [
                '#' . $widgetId . ' .fon-item' => [
                ['type' => 'height', 'unit' => 'px!important', 'value' => $custom_height]
            ],
                '#' . $widgetId . '.fon-slider' => [
                ['type' => 'height', 'unit' => 'px!important', 'value' => $custom_height]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-slideshow-widget fon-slider ' . $content->fon_class . ' ' . $dot_position . ' ' . $arrow_class . '"' . "\n\t\t" . '    data-id="fon-widget-slideshow-' . $moduleId . '"' . "\n\t\t" . '    data-effect="' . $slider_animation . '"' . "\n\t\t" . '    data-autoplay="' . ($autoplay ? 'true' : 'false') . '"' . "\n\t\t" . '    data-autoplay-speed="' . ($interval ? $interval * 1000 : '4000') . '"' . "\n\t\t" . '    data-speed="' . $speed . '"' . "\n\t\t" . '    data-dots="' . ($dot_controllers ? 'true' : 'false') . '"' . "\n\t\t" . '    data-arrows="' . ($arrow_controllers ? 'true' : 'false') . '"' . "\n\t\t" . '    data-pause="' . ($pause_on_hover && $autoplay ? 'true' : 'false') . '" style="overflow:hidden; ' . ($height != 'full' ? 'height:' . $custom_height->xl . 'px;' : '') . '">';
        if (isset($content->items) && is_array($content->items)) {
            foreach ($content->items as $item_key => $item_value) {
                $isFirstSlide = $item_key === 0;
                $uniqid = 'fon-slider-item-' . $moduleId . '-num-' . $item_key . '-key';
                $content_class = (isset($item_value->slide_class) && $item_value->slide_class ? ' ' . $item_value->slide_class : '');
                $patternStyle = $this->handlePatternImages($content_class, $pageData['page'], $pageData['tadress'], $isFirstSlide && $isLCPCandidate);
                $image_in_column = (isset($item_value->use_slide_image) && $item_value->use_slide_image == 'yes' ? 1 : 0);
                $image_column_width = (isset($item_value->slide_image_column) && $item_value->slide_image_column ? $item_value->slide_image_column : (object) []);
                $image_column_width_xl = (isset($image_column_width->xl) && $image_column_width->xl ? (int) $image_column_width->xl : 6);
                $image_column_width_lg = (isset($image_column_width->lg) && $image_column_width->lg ? (int) $image_column_width->lg : 6);
                $image_column_width_md = (isset($image_column_width->md) && $image_column_width->md ? (int) $image_column_width->md : 6);
                $image_column_width_sm = (isset($image_column_width->sm) && $image_column_width->sm ? (int) $image_column_width->sm : 6);
                $image_column_width_xs = (isset($image_column_width->xs) && $image_column_width->xs ? (int) $image_column_width->xs : 6);
                $slide_image_order = (isset($item_value->slide_image_order) && $item_value->slide_image_order ? $item_value->slide_image_order : (object) []);
                $slide_image_order_xl = (isset($slide_image_order->xl) && $slide_image_order->xl ? (int) $slide_image_order->xl : 2);
                $slide_image_order_lg = (isset($slide_image_order->lg) && $slide_image_order->lg ? (int) $slide_image_order->lg : 2);
                $slide_image_order_md = (isset($slide_image_order->md) && $slide_image_order->md ? (int) $slide_image_order->md : 2);
                $slide_image_order_sm = (isset($slide_image_order->sm) && $slide_image_order->sm ? (int) $slide_image_order->sm : 2);
                $slide_image_order_xs = (isset($slide_image_order->xs) && $slide_image_order->xs ? (int) $slide_image_order->xs : 2);
                $slide_content_order_xl = ($slide_image_order_xl == 2 ? 1 : 2);
                $slide_content_order_lg = ($slide_image_order_lg == 2 ? 1 : 2);
                $slide_content_order_md = ($slide_image_order_md == 2 ? 1 : 2);
                $slide_content_order_sm = ($slide_image_order_sm == 2 ? 1 : 2);
                $slide_content_order_xs = ($slide_image_order_xs == 2 ? 1 : 2);
                $slide_image_text_align = '';
                $slide_image_text_align .= ($slide_image_order_xl == 2 ? ' text-xl-end' : ' text-xl-start');
                $slide_image_text_align .= ($slide_image_order_lg == 2 ? ' text-lg-end' : ' text-lg-start');
                $slide_image_text_align .= ($slide_image_order_md == 2 ? ' text-md-end' : ' text-md-start');
                $slide_image_text_align .= ($slide_image_order_sm == 2 ? ' text-sm-end' : ' text-sm-start');
                $slide_image_text_align .= ($slide_image_order_xs == 2 ? ' text-end' : ' text-start');
                $aligns = (isset($item_value->slide_content_align) && $item_value->slide_content_align ? $item_value->slide_content_align : '');
                $alignClass = '';

                if ($aligns) {
                    foreach ($aligns as $ak => $av) {
                        if ($av) {
                            $alignClass .= ($ak == 'xs' ? 'text-' : 'text-' . $ak . '-');

                            if ($av == 'left') {
                                $alignClass .= 'start ';
                            }
                            else if ($av == 'right') {
                                $alignClass .= 'end ';
                            }
                            else {
                                $alignClass .= 'center ';
                            }
                        }
                    }
                }
                $slide_bg_color = (isset($item_value->slide_bg_color) && $item_value->slide_bg_color ? $item_value->slide_bg_color : '');
                $slide_bg_type = (isset($item_value->slide_bg_type) && $item_value->slide_bg_type ? $item_value->slide_bg_type : '');
                $slide_bg_image = '';

                if (is_object($item_value->slide_bg_image)) {
                    $slide_bg_image = (isset($item_value->slide_bg_image->{$this->lang}) && $item_value->slide_bg_image->{$this->lang} ? $item_value->slide_bg_image->{$this->lang} : array_values((array) $item_value->slide_bg_image)[0] ?? '');
                }
                else if (is_string($item_value->slide_bg_image)) {
                    $slide_bg_image = $item_value->slide_bg_image;
                }

                $slide_bg_color_code = '';
                $hasColor = $slide_bg_color && $slide_bg_type != 'none';
                if ($hasColor || $patternStyle) {
                    $slide_bg_color_code = 'style="';

                    if ($hasColor) {
                        $slide_bg_color_code .= 'background-color: ' . $slide_bg_color . '; ';
                    }

                    if ($patternStyle) {
                        $slide_bg_color_code .= $patternStyle;
                    }

                    $slide_bg_color_code .= '"';
                }
                $title = (isset($item_value->slide_title->{$this->lang}) && $item_value->slide_title->{$this->lang} ? $item_value->slide_title->{$this->lang} : array_values((array) $item_value->slide_title)[0] ?? '');
                $title = self::getPriceHolders($title);
                $title_heading_selector = (isset($item_value->slide_title_heading) && $item_value->slide_title_heading ? $item_value->slide_title_heading : 'h3');
                $title_font = (isset($item_value->slide_title_font) && $item_value->slide_title_font ? self::parseFontProperties($item_value->slide_title_font, false) : '');
                $title_color = (isset($item_value->slide_title_color) && $item_value->slide_title_color ? $item_value->slide_title_color : '');
                $title_animation = (isset($item_value->slide_title_animation) && $item_value->slide_title_animation ? $item_value->slide_title_animation : 'none');
                $subtitle = (isset($item_value->slide_subtitle->{$this->lang}) && $item_value->slide_subtitle->{$this->lang} ? $item_value->slide_subtitle->{$this->lang} : array_values((array) $item_value->slide_subtitle)[0] ?? '');
                $subtitle = self::getPriceHolders($subtitle);
                $subtitle_heading_selector = (isset($item_value->slide_subtitle_heading) && $item_value->slide_subtitle_heading ? $item_value->slide_subtitle_heading : 'h2');
                $subtitle_font = (isset($item_value->slide_subtitle_font) && $item_value->slide_subtitle_font ? self::parseFontProperties($item_value->slide_subtitle_font, false) : '');
                $subtitle_color = (isset($item_value->slide_subtitle_color) && $item_value->slide_subtitle_color ? $item_value->slide_subtitle_color : '');
                $subtitle_animation = (isset($item_value->slide_subtitle_animation) && $item_value->slide_subtitle_animation ? $item_value->slide_subtitle_animation : 'none');
                $content_text = (isset($item_value->slide_description->{$this->lang}) && $item_value->slide_description->{$this->lang} ? $item_value->slide_description->{$this->lang} : array_values((array) $item_value->slide_description)[0] ?? '');
                $content_text = self::getPriceHolders($content_text);
                $content_color = (isset($item_value->slide_description_color) && $item_value->slide_description_color ? $item_value->slide_description_color : '');
                $content_animation = (isset($item_value->slide_description_animation) && $item_value->slide_description_animation ? $item_value->slide_description_animation : 'none');
                $use_slide_features = (isset($item_value->use_slide_features) && $item_value->use_slide_features == 'yes' ? true : false);
                $slide_features = (isset($item_value->slide_features) && $item_value->slide_features ? $item_value->slide_features : []);
                $slide_features_type = (isset($item_value->slide_features_type) && $item_value->slide_features_type ? $item_value->slide_features_type : 'list');
                $slide_features_icon_color = (isset($item_value->slide_features_icon_color) && $item_value->slide_features_icon_color ? $item_value->slide_features_icon_color : '');
                $slide_features_title_color = (isset($item_value->slide_features_title_color) && $item_value->slide_features_title_color ? $item_value->slide_features_title_color : '');
                $slide_features_desc_color = (isset($item_value->slide_features_desc_color) && $item_value->slide_features_desc_color ? $item_value->slide_features_desc_color : '');
                $slide_features_animation = (isset($item_value->slide_features_animation) && $item_value->slide_features_animation ? $item_value->slide_features_animation : 'none');
                $output .= '<div class="' . $uniqid . ' fon-item ' . $content_class . ' ' . ($item_key == 0 ? ' active d-flex' : '') . ' ' . ($content_vertical_center ? 'slider-content-vertically-center' : '') . ' ' . ($image_in_column ? 'image-in-column' : '') . '" ' . $slide_bg_color_code . '>';

                if ($slide_bg_type == 'video') {
                    $videoType = '';
                    $videoSrc = '';
                    $slider_video = (isset($item_value->slider_video) && $item_value->slider_video ? $item_value->slider_video : '');
                    if (strpos($slider_video, 'http://') === false || strpos($slider_video, 'https://') === false) {
                        $slider_video = static::assetLinkDetermine($slider_video);
                    }
                    if ($slider_video && strpos($slider_video, 'http://') !== false || strpos($slider_video, 'https://') !== false && isset($item_value->use_youtube_vimeo) && $item_value->use_youtube_vimeo == 'no') {
                        $videoType = 'video';
                        $videoSrc = $slider_video;
                    }
                    else if (isset($item_value->youtube_vimeo_url) && $item_value->youtube_vimeo_url && $item_value->use_youtube_vimeo == 'yes' && strpos($item_value->youtube_vimeo_url, 'http://') !== false || strpos($item_value->youtube_vimeo_url, 'https://') !== false) {
                        $video = parse_url($item_value->youtube_vimeo_url);
                        if (strpos($video['host'], 'youtube.com') !== false || strpos($video['host'], 'youtu.be') !== false) {
                            $videoType = 'youtube';
                            $videoId = '';

                            switch ($video['host']) {
                            case 'www.youtu.be':
                            case 'youtu.be':
                                $videoId = trim($video['path'], '/');
                                break;
                            case 'www.youtube.com':
                            case 'youtube.com':
                                parse_str($video['query'], $query);
                                $videoId = $query['v'];
                                break;
                            }

                            $videoSrc = '//www.youtube-nocookie.com/embed/' . $videoId . '?enablejsapi=1&controls=0&fs=0&iv_load_policy=3&rel=0&showinfo=0&loop=1&playlist=' . $videoId . '&start=1';
                        }
                        else {
                            if (strpos($video['host'], 'vimeo.com') !== false) {
                                $videoType = 'vimeo';
                                $videoId = trim($video['path'], '/');
                                $videoSrc = '//player.vimeo.com/video/' . $videoId . '?api=1&byline=0&portrait=0&title=0&background=1&mute=1&loop=1&autoplay=0&id=' . $videoId;
                            }
                            else {
                                $videoType = 'unknown';
                                $videoSrc = $item_value->youtube_vimeo_url;
                            }
                        }
                    }
                }
                if ($slide_bg_image && $slide_bg_type == 'image') {
                    $slide_bg_image = static::assetLinkDetermine($slide_bg_image);
                    $isBgLcp = false;
                    if ($isFirstSlide && $isLCPCandidate && self::$lcpHandled === false) {
                        $this->addPreloadLink($slide_bg_image, $pageData['page']);
                        self::$lcpHandled = true;
                        $isBgLcp = true;
                    }

                    $output .= '<div class="fon-background image">';
                    $bg_attrs = 'src="' . $slide_bg_image . '" class="d-block w-100 h-100" style="object-fit: cover; position: absolute; top:0; left:0; z-index:0;" alt="' . $title . '"';

                    if ($isBgLcp) {
                        $bg_attrs .= ' fetchpriority="high" loading="eager" decoding="sync"';
                    }
                    else {
                        $bg_attrs .= ' loading="lazy" decoding="async"';
                    }

                    $output .= '<img ' . $bg_attrs . '>';
                    $output .= '</div>';
                }

                if ($slide_bg_type == 'video') {
                    if ($videoType == 'video') {
                        $output .= '<div class="fon-background video">';
                        $output .= '<video class="slide-video " autoplay muted loop playsinline preload="metadata">';
                        $output .= '<source src="' . $videoSrc . '" type="video/mp4" />';
                        $output .= '</video>';
                        $output .= '</div>';
                    }
                    else {
                        $output .= '<div class="fon-background ' . $videoType . '">';
                        $output .= '<iframe class="embed-player " width="980" height="520" src="' . $videoSrc . '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
                        $output .= '</div>';
                    }
                }

                if ($content_container_option === 'bootstrap') {
                    $output .= '<div class="container">';

                    if (!$image_in_column) {
                        $columnClass = 'col-12';

                        if ($aligns) {
                            foreach ($aligns as $ak => $av) {
                                if (!in_array($ak, ['xs' => true, 'sm' => true])) {
                                    $columnClass .= (($av == 'left') || $av == 'right' ? ' col-' . $ak . '-' . ($ak == 'md' ? '7' : '6') : '');
                                }
                            }
                        }

                        $output .= '<div class="row">';
                        $output .= '<div class="' . $columnClass . '">';
                    }
                }
                else {
                    $output .= '<div class="fon-slider-content-wrap">';
                }

                $inner_uniqid = 'fon-slider-inner-item-' . $moduleId . '-num-' . $item_key;

                if ($image_in_column) {
                    $output .= '<div class="row align-items-center">';
                    $output .= '<div class="col-' . ($image_column_width_xs === 12 ? 12 : 12 - $image_column_width_xs) . ' col-sm-' . ($image_column_width_sm === 12 ? 12 : 12 - $image_column_width_sm) . ' col-md-' . ($image_column_width_md === 12 ? 12 : 12 - $image_column_width_md) . ' col-lg-' . ($image_column_width_lg === 12 ? 12 : 12 - $image_column_width_lg) . ' col-xl-' . ($image_column_width_xl === 12 ? 12 : 12 - $image_column_width_xl) . ' order-' . $slide_content_order_xs . ' order-sm-' . $slide_content_order_sm . ' order-md-' . $slide_content_order_md . ' order-lg-' . $slide_content_order_lg . ' order-xl-' . $slide_content_order_xl . '">';
                }

                $output .= '<div class="fon-slider-content-align ' . $alignClass . '">';
                $primarySlideButton = '';

                if (is_object($item_value->slide_link)) {
                    $primarySlideButton = (isset($item_value->slide_link->{$this->lang}) && $item_value->slide_link->{$this->lang} ? $item_value->slide_link->{$this->lang} : array_values((array) $item_value->slide_link)[0] ?? '');
                }
                else if (is_string($item_value->slide_link)) {
                    $primarySlideButton = $item_value->slide_link;
                }

                if ($primarySlideButton) {
                    $button = ['button_text' => $item_value->button_text ?? '', 'button_link' => $item_value->slide_link ?? '', 'button_rel' => $item_value->button_rel ?? [], 'button_target' => $item_value->slide_link_target ?? '', 'button_type' => $item_value->button_type ?? 'default', 'button_style' => $item_value->button_style ?? 'default', 'button_custom_style' => $item_value->button_custom_style ?? 'default', 'button_shape' => $item_value->button_shape ?? '', 'button_size' => $item_value->button_size ?? '', 'button_padding' => $item_value->button_padding ?? '', 'button_color_normal' => $item_value->button_color_normal ?? '', 'button_color_hover' => $item_value->button_color_hover ?? '', 'button_background_normal' => $item_value->button_background_normal ?? '', 'button_background_hover' => $item_value->button_background_hover ?? '', 'button_gradient_normal' => $item_value->button_gradient_normal ?? '', 'button_gradient_hover' => $item_value->button_gradient_hover ?? '', 'show_button_icon' => $item_value->show_button_icon ?? 'no', 'button_icon' => $item_value->button_icon ?? '', 'button_icon_position' => $item_value->button_icon_position ?? '', 'scroll_button' => $item_value->scroll_button ?? 'no', 'block_button' => 'no'];
                    $button_animation = (isset($item_value->button_animation) && $item_value->button_animation ? $item_value->button_animation : 'none');
                }
                $showSecondaryButton = (isset($item_value->show_secondary_button) && $item_value->show_secondary_button == 'yes' ? true : false);

                if ($showSecondaryButton) {
                    $secondaryButton = ['button_text' => $item_value->secondary_button_text ?? '', 'button_link' => $item_value->secondary_slide_link ?? '', 'button_rel' => $item_value->secondary_button_rel ?? [], 'button_target' => $item_value->secondary_slide_link_target ?? '', 'button_type' => $item_value->secondary_button_type ?? 'default', 'button_style' => $item_value->secondary_button_style ?? 'default', 'button_custom_style' => $item_value->secondary_button_custom_style ?? 'default', 'button_shape' => $item_value->secondary_button_shape ?? '', 'button_size' => $item_value->secondary_button_size ?? '', 'button_padding' => $item_value->secondary_button_padding ?? '', 'button_color_normal' => $item_value->secondary_button_color_normal ?? '', 'button_color_hover' => $item_value->secondary_button_color_hover ?? '', 'button_background_normal' => $item_value->secondary_button_background_normal ?? '', 'button_background_hover' => $item_value->secondary_button_background_hover ?? '', 'button_gradient_normal' => $item_value->secondary_button_gradient_normal ?? '', 'button_gradient_hover' => $item_value->secondary_button_gradient_hover ?? '', 'show_button_icon' => $item_value->secondary_show_button_icon ?? 'no', 'button_icon' => $item_value->secondary_button_icon ?? '', 'button_icon_position' => $item_value->secondary_button_icon_position ?? '', 'scroll_button' => $item_value->secondary_scroll_button ?? 'no', 'block_button' => 'no'];
                    $secondary_button_animation = (isset($item_value->secondary_button_animation) && $item_value->secondary_button_animation ? $item_value->secondary_button_animation : 'none');
                }

                $output .= '<' . $title_heading_selector . ' class="fon-slider-title ' . ($title_animation != 'none' ? 'animated' : '') . ' ' . $inner_uniqid . '-title" ' . ($title_animation != 'none' ? 'data-animation-in="' . $title_animation . '" data-delay-in="0"' : '') . '>';
                $output .= $title;
                $output .= '</' . $title_heading_selector . '>';
                $output .= '<' . $subtitle_heading_selector . ' class="fon-slider-title fon-slider-subtitle ' . ($subtitle_animation != 'none' ? 'animated' : '') . ' ' . $inner_uniqid . '-subtitle" ' . ($subtitle_animation != 'none' ? 'data-animation-in="' . $subtitle_animation . '"  data-delay-in="0.1"' : '') . '>';
                $output .= $subtitle;
                $output .= '</' . $subtitle_heading_selector . '>';
                $output .= '<div class="fon-slider-text ' . $inner_uniqid . '-description ' . ($content_animation != 'none' ? 'animated' : '') . '" ' . ($content_animation != 'none' ? 'data-animation-in="' . $content_animation . '"  data-delay-in="0.2"' : '') . '>';
                $output .= $content_text;
                $output .= '</div>';
                if ($slide_features && $use_slide_features) {
                    $output .= '<div id="' . $inner_uniqid . '-features" class="fon-slider-features ' . ($slide_features_animation != 'none' ? 'animated' : '') . ' d-none d-md-block" ' . ($slide_features_animation != 'none' ? 'data-animation-in="' . $slide_features_animation . '" data-delay-in="0.3"' : '') . '>';
                    $output .= '<ul class="list-unstyled ' . ($slide_features_type == 'column' ? 'row align-items-start' : '') . '">';

                    foreach ($slide_features as $sfkey => $slide_feature) {
                        $slide_feature_icon = (isset($slide_feature->icon) && $slide_feature->icon ? $slide_feature->icon : '');
                        $slide_feature_title = (isset($slide_feature->title->{$this->lang}) && $slide_feature->title->{$this->lang} ? $slide_feature->title->{$this->lang} : array_values((array) $slide_feature->title)[0] ?? '');
                        $slide_feature_desc = (isset($slide_feature->desc->{$this->lang}) && $slide_feature->desc->{$this->lang} ? $slide_feature->desc->{$this->lang} : array_values((array) $slide_feature->desc)[0] ?? '');
                        $output .= '<li class="' . ($slide_features_type == 'column' ? 'col-md-6' : '') . '">';
                        $output .= '<div class="fon-slider-feature">';

                        if ($slide_feature_icon) {
                            $output .= '<div class="fon-slider-feature-icon" style="' . ($slide_features_icon_color ? 'color:' . $slide_features_icon_color : '') . '"><i class="' . $slide_feature_icon . ' fa-fw"></i></div>';
                        }

                        $output .= '<div class="fon-slider-feature-text">';

                        if ($slide_feature_title) {
                            $output .= '<h4 class="fon-slider-feature-title fw-semibold mb-1" style="' . ($slide_features_title_color ? 'color:' . $slide_features_title_color : '') . '">' . $slide_feature_title . '</h4>';
                        }

                        if ($slide_feature_desc) {
                            $output .= '<p class="fon-slider-feature-desc" style="' . ($slide_features_desc_color ? 'color:' . $slide_features_desc_color : '') . '">' . $slide_feature_desc . '</span>';
                        }

                        $output .= '</div>';
                        $output .= '</div>';
                        $output .= '</li>';
                    }

                    $output .= '</ul>';
                    $output .= '</div>';
                }
                if ($primarySlideButton || $showSecondaryButton) {
                    $output .= '<div class="fon-slide-button-container ' . ($showSecondaryButton ? 'd-flex gap-3 justify-content-center justify-content-md-start' : '') . ' ' . ($use_slide_features ? 'mt-3' : 'mt-3 mt-lg-5') . ' ' . ($button_animation != 'none' ? 'animated' : '') . '" ' . ($button_animation != 'none' ? 'data-animation-in="' . $button_animation . '" data-delay-in="0.4"' : '') . '>';

                    if ($primarySlideButton) {
                        $output .= self::parseButton((object) $button, $moduleId . '-' . $inner_uniqid, $pageData);
                    }

                    if ($showSecondaryButton) {
                        $output .= self::parseButton((object) $secondaryButton, $moduleId . '-' . $inner_uniqid . '-secondary', $pageData);
                    }

                    $output .= '</div>';
                }

                $output .= '</div>';

                if ($image_in_column) {
                    $output .= '</div>';
                    $image_content = '';

                    if (is_object($item_value->slide_image)) {
                        $image_content = (isset($item_value->slide_image->{$this->lang}) && $item_value->slide_image->{$this->lang} ? $item_value->slide_image->{$this->lang} : array_values((array) $item_value->slide_image)[0] ?? '');
                    }
                    else if (is_string($item_value->slide_image)) {
                        $image_content = $item_value->slide_image;
                    }

                    $image_content_src = ($image_content ? static::assetLinkDetermine($image_content) : $lazyPlaceholder);
                    $imageDimensions = static::getImageDimensions($image_content_src, $pageData['badress']);
                    $isContentLcp = false;
                    if ($image_content && $isFirstSlide && $isLCPCandidate && self::$lcpHandled === false) {
                        $this->addPreloadLink($image_content, $pageData['page']);
                        self::$lcpHandled = true;
                        $isContentLcp = true;
                    }
                    $image_height = (isset($item_value->slide_image_height) && $item_value->slide_image_height ? $item_value->slide_image_height : false);
                    $image_animation = (isset($item_value->slide_image_animation) && $item_value->slide_image_animation ? $item_value->slide_image_animation : 'none');
                    $img_attrs = 'class="img-fluid fon-slider-image-entity d-inline" src="' . $image_content_src . '" alt="' . strip_tags($title) . '" ' . $imageDimensions;

                    if ($isFirstSlide) {
                        $img_attrs .= ' loading="eager" ';

                        if ($isContentLcp) {
                            $img_attrs .= ' fetchpriority="high" decoding="sync" ';
                        }
                        else {
                            $img_attrs .= ' fetchpriority="auto" decoding="async" ';
                        }
                    }
                    else {
                        $img_attrs .= ' loading="lazy" decoding="async" ';
                    }

                    $output .= '<div class="col-' . $image_column_width_xs . ' col-sm-' . $image_column_width_sm . ' col-md-' . $image_column_width_md . ' col-lg-' . $image_column_width_lg . ' col-xl-' . $image_column_width_xl . ' order-' . $slide_image_order_xs . ' order-sm-' . $slide_image_order_sm . ' order-md-' . $slide_image_order_md . ' order-lg-' . $slide_image_order_lg . ' order-xl-' . $slide_image_order_xl . '">';
                    $output .= '<div class="fon-slider-image-align">';
                    $output .= '<div class="fon-slider-image text-center ' . ($image_animation != 'none' ? 'animated' : '') . ' ' . $inner_uniqid . '-image" ' . ($image_animation != 'none' ? 'data-animation-in="' . $image_animation . '" data-delay-in="0.5"' : '') . '>';
                    $output .= '<img ' . $img_attrs . '>';
                    $output .= '</div>';
                    $output .= '</div>';
                    $output .= '</div>';
                    $output .= '</div>';
                }

                if ($content_container_option === 'bootstrap') {
                    if (!$image_in_column) {
                        $output .= '</div>';
                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }
                else {
                    $output .= '</div>';
                }
                if (isset($item_value->slider_overlay_type) && $item_value->slider_overlay_type == 'color') {
                    if (isset($item_value->slider_color_overlay) && $item_value->slider_color_overlay) {
                        $style .= '.fon-item.' . $uniqid . ' .fon-background:after{';
                        $style .= 'background-color:' . $item_value->slider_color_overlay . ';';
                        $style .= '}';
                    }
                }
                if (isset($item_value->slider_overlay_type) && $item_value->slider_overlay_type == 'gradient') {
                    if (isset($item_value->slider_gradient_overlay) && $item_value->slider_gradient_overlay) {
                        $item_value->slider_gradient_overlay = self::parseGradient($item_value->slider_gradient_overlay);
                        $style .= '.fon-item.' . $uniqid . ' .fon-background:after{';
                        $style .= $item_value->slider_gradient_overlay;
                        $style .= '}';
                    }
                }
                if ($title_font || $title_color) {
                    $style .= '.' . $inner_uniqid . '-title{';

                    if ($title_font) {
                        $style .= $title_font;
                    }

                    if ($title_color) {
                        $style .= 'color: ' . $title_color . ';';
                    }

                    $style .= '}';
                }
                if ($subtitle_font || $subtitle_color) {
                    $style .= '.' . $inner_uniqid . '-subtitle{';

                    if ($subtitle_font) {
                        $style .= $subtitle_font;
                    }

                    if ($subtitle_color) {
                        $style .= 'color: ' . $subtitle_color . ';';
                    }

                    $style .= '}';
                }

                if ($content_color) {
                    $style .= '.fon-slider .fon-slider-text.' . $inner_uniqid . '-description{';
                    $style .= 'color: ' . $content_color . ';';
                    $style .= '}';
                }
                if ($image_in_column && $image_content) {
                    if (isset($image_height) && $image_height) {
                        $responsiveItems = [
                            '.' . $inner_uniqid . '-image img' => [
                            ['type' => 'max-height', 'unit' => 'px', 'value' => $image_height]
                        ]
                        ];
                        $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
                    }
                    else {
                        $style .= '.' . $inner_uniqid . '-image img{';
                        $style .= 'max-height: 90%;';
                        $style .= '}';
                    }
                }

                $output .= '</div>';
            }
        }

        $output .= '</div>';

        if ($content_container_option !== 'bootstrap') {
            $style .= '#' . $widgetId . '.fon-slider .fon-slider-content-wrap{';
            $style .= 'margin: 0 auto;';
            $style .= 'width: ' . $content->content_custom_width . '%;';
            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        return $output;
    }

    private function sms_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetProducts($content, $moduleId, $pageData, $row, 'sms');
    }

    private function software_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetPages($content, $moduleId, $pageData, 'software');
    }

    private function social_share_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $social_networks = [
            'facebook'  => [
            'url'   => 'https://www.facebook.com/sharer.php?u={url}',
            'icon'  => 'fa-brands fa-facebook-f',
            'label' => 'Facebook',
            'popup' => ['width' => 600, 'height' => 300],
            'color' => ['normal' => '#306199', 'hover' => '#244872']
        ],
            'twitter'   => [
            'url'   => 'https://twitter.com/share?url={url}&text={title}',
            'icon'  => 'fa-brands fa-x-twitter',
            'label' => 'X (Twitter)',
            'popup' => ['width' => 600, 'height' => 300],
            'color' => ['normal' => '#000000c7', 'hover' => '#000']
        ],
            'linkedin'  => [
            'url'   => 'https://www.linkedin.com/shareArticle?mini=true&url={url}',
            'icon'  => 'fa-brands fa-linkedin',
            'label' => 'LinkedIn',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#007bb6', 'hover' => '#005983']
        ],
            'pinterest' => [
            'url'   => 'https://pinterest.com/pin/create/button/?url={url}&description={title}',
            'icon'  => 'fa-brands fa-pinterest',
            'label' => 'Pinterest',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#b81621', 'hover' => '#8a1119']
        ],
            'tumblr'    => [
            'url'   => 'https://tumblr.com/share?s=&v=3&t={title}&u={url}',
            'icon'  => 'fa-brands fa-tumblr',
            'label' => 'Tumblr',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#32506d', 'hover' => '#22364a']
        ],
            'getpocket' => [
            'url'   => 'https://getpocket.com/save?url={url}',
            'icon'  => 'fa-brands fa-get-pocket',
            'label' => 'Pocket',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#ed4054', 'hover' => '#e4162d']
        ],
            'reddit'    => [
            'url'   => 'https://www.reddit.com/submit?url={url}',
            'icon'  => 'fa-brands fa-reddit',
            'label' => 'Reddit',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#ff4500', 'hover' => '#e83f00']
        ],
            'vk'        => [
            'url'   => 'https://vk.com/share.php?url={url}',
            'icon'  => 'fa-brands fa-vk',
            'label' => 'VK',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#597ba5', 'hover' => '#3d5f88']
        ],
            'xing'      => [
            'url'   => 'https://www.xing.com/spi/shares/new?cb=0&url={url}',
            'icon'  => 'fa-brands fa-xing',
            'label' => 'Xing',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#005658', 'hover' => '#004748']
        ],
            'whatsapp'  => [
            'url'   => 'https://api.whatsapp.com/send?text={url}',
            'icon'  => 'fa-brands fa-whatsapp',
            'label' => 'WhatsApp',
            'popup' => false,
            'color' => ['normal' => '#00d66e', 'hover' => '#00b55d']
        ],
            'telegram'  => [
            'url'   => 'https://t.me/share/url?url={url}&text={title}',
            'icon'  => 'fa-brands fa-telegram',
            'label' => 'Telegram',
            'popup' => false,
            'color' => ['normal' => '#54a9eb', 'hover' => '#4998d5']
        ],
            'bluesky'   => [
            'url'   => 'https://bsky.app/intent/compose?text={url}',
            'icon'  => 'fa-brands fa-bluesky',
            'label' => 'Bluesky',
            'popup' => false,
            'color' => ['normal' => '#0285ff', 'hover' => '#2566a4']
        ],
            'email'     => [
            'url'   => 'mailto:?subject={title}&body={url}',
            'icon'  => 'fa-solid fa-envelope',
            'label' => 'E-Mail',
            'popup' => false,
            'color' => ['normal' => '#7d7d7d', 'hover' => '#4d4d4d']
        ]
        ];
        $widgetId = 'fon-widget-' . $moduleId;
        $social_media = (isset($content->social_media) && $content->social_media ? $content->social_media : []);
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'button');
        $dropdown_title = (isset($content->dropdown_title) && isset($content->dropdown_title->{$this->lang}) && $content->dropdown_title->{$this->lang} ? $content->dropdown_title->{$this->lang} : (isset($content->dropdown_title) ? array_values((array) $content->dropdown_title)[0] ?? '' : ''));
        $show_label = (isset($content->show_label) && $content->show_label == 'yes' ? true : false);
        $color_scheme = (isset($content->color_scheme) && $content->color_scheme ? $content->color_scheme : 'default');
        $text_color_normal = (isset($content->text_color) && isset($content->text_color->normal) && $content->text_color->normal ? $content->text_color->normal : '#000000');
        $text_color_hover = (isset($content->text_color) && isset($content->text_color->hover) && $content->text_color->hover ? $content->text_color->hover : '#ffffff');
        $background_color_normal = (isset($content->background_color) && isset($content->background_color->normal) && $content->background_color->normal ? $content->background_color->normal : '#f9f9f9');
        $background_color_hover = (isset($content->background_color) && isset($content->background_color->hover) && $content->background_color->hover ? $content->background_color->hover : '#000000');
        $border_radius = (isset($content->border_radius) && $content->border_radius ? $content->border_radius : 0);
        $fon_class = (isset($content->fon_class) && $content->fon_class ? $content->fon_class : '');
        $align = (isset($content->align) && $content->align ? $content->align : 'center');

        switch ($align) {
        case 'left':
            $align = 'start';
            break;
        case 'right':
            $align = 'end';
            break;
        case 'center':
            $align = 'center';
            break;
        }

        $style = '';

        if ($widget_style != 'dropdown') {
            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a{';

            if ($widget_style == 'button') {
                $style .= 'color:#fff;';

                if ($show_label) {
                    $style .= 'padding: .375rem .75rem;';
                }
                else {
                    $style .= 'padding: .75rem;';
                }

                $style .= 'font-size: .875rem;';

                if ($color_scheme == 'default') {
                    $style .= '--normal-color:var(--fon-link-color);';
                    $style .= '--hover-color:var(--fon-hover-color);';
                }
                else if ($color_scheme == 'primary') {
                    $style .= '--normal-color:var(--theme-primary);';
                    $style .= '--hover-color:var(--theme-secondary);';
                }
                else if ($color_scheme == 'secondary') {
                    $style .= '--normal-color:var(--theme-secondary);';
                    $style .= '--hover-color:var(--theme-primary);';
                }
                else if ($color_scheme == 'custom') {
                    $style .= '--normal-color:' . $background_color_normal . ';';
                    $style .= '--hover-color:' . $background_color_hover . ';';
                    $style .= 'color:' . $text_color_normal . ';';
                }

                $style .= 'background-color:var(--normal-color);';
            }
            else if ($widget_style == 'list') {
                $style .= 'color:var(--fon-link-color);';
            }

            $style .= 'cursor:pointer;';
            $style .= 'border-radius: ' . $border_radius . 'px;';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a:hover{';

            if ($widget_style == 'button') {
                $style .= 'background-color:var(--hover-color);';

                if ($color_scheme == 'custom') {
                    $style .= 'color:' . $text_color_hover . ';';
                }
            }
            else if ($widget_style == 'list') {
                $style .= 'color:var(--fon-hover-color);';
            }

            $style .= '}';
        }
        else {
            if (!$show_label) {
                $style .= '#' . $widgetId . ' .dropdown-menu{';
                $style .= 'text-align: center;';
                $style .= 'min-width: 56px;';
                $style .= '--bs-dropdown-item-padding-x: 0.5rem;';
                $style .= '}';
            }

            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a{';
            $style .= 'cursor:pointer;';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a > i{';
            $style .= 'color:var(--fon-link-color);';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a:hover > i{';
            $style .= 'color:var(--fon-hover-color);';
            $style .= '}';

            if ($color_scheme == 'default') {
                $dropdownBtnClass = 'btn-outline-dark';
            }
            else if ($color_scheme == 'primary') {
                $dropdownBtnClass = 'btn-default';
            }
            else if ($color_scheme == 'secondary') {
                $dropdownBtnClass = 'btn-secondary';
            }
            else if ($color_scheme == 'custom') {
                $dropdownBtnClass = 'btn-custom';
                $style .= '#' . $widgetId . ' .btn-custom.dropdown-toggle{';
                $style .= 'color:' . $text_color_normal . ';';
                $style .= 'background-color:' . $background_color_normal . ';';
                $style .= 'border-color:' . $background_color_normal . ';';
                $style .= '}';
                $style .= '#' . $widgetId . ' .btn-custom.dropdown-toggle:hover{';
                $style .= 'color:' . $text_color_hover . ';';
                $style .= 'background-color:' . $background_color_hover . ';';
                $style .= 'border-color:' . $background_color_hover . ';';
                $style .= '}';
            }
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-social-share-widget ' . $fon_class . '">';
        $output .= '<script>var socialSharePageTitle=encodeURIComponent(document.title); var socialSharepageLink = encodeURIComponent(window.location.href);</script>';
        $output .= '<div class="fon-widget-content ' . ($widget_style == 'dropdown' ? 'text-' . $align : '') . '">';

        if ($widget_style == 'dropdown') {
            $output .= '<div class="btn-group position-relative">';
            $output .= '<button class="btn ' . $dropdownBtnClass . ' dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="fa-solid fa-share-nodes"></i>' . ($show_label ? ' ' . $dropdown_title : '') . '</button>';
        }

        $output .= '<ul class="fon-social-share-list ' . ($widget_style != 'dropdown' ? 'list-unstyled d-flex flex-wrap align-item-center justify-content-' . $align . ' gap-3' : 'dropdown-menu dropdown-menu-' . $align) . '">';

        foreach ($social_media as $network_key) {
            if (isset($social_networks[$network_key])) {
                $network = $social_networks[$network_key];
                $link_action = '';

                if ($network_key == 'email') {
                    $url_template = str_replace(['{title}', '{url}'], ['\' + socialSharePageTitle + \'', '\' + socialSharepageLink + \''], $network['url']);
                    $link_action = 'onClick="window.location.href = \'' . $url_template . '\'; return false"';
                }
                else if (isset($network['popup']) && $network['popup']) {
                    $url_template = str_replace(['{title}', '{url}'], ['\' + socialSharePageTitle + \'', '\' + socialSharepageLink + \''], $network['url']);
                    $w = $network['popup']['width'];
                    $h = $network['popup']['height'];
                    $link_action = 'onClick="window.open(\'' . $url_template . '\', \'' . $network['label'] . '\', \'width=' . $w . ',height=' . $h . ',left=\'+(screen.availWidth/2-' . ($w / 2) . ')+\',top=\'+(screen.availHeight/2-' . ($h / 2) . ')+\'\'); return false;"';
                }
                else {
                    $url_template = str_replace(['{title}', '{url}'], ['\' + socialSharePageTitle + \'', '\' + socialSharepageLink + \''], $network['url']);
                    $link_action = 'onClick="window.open(\'' . $url_template . '\'); return false;"';
                }

                $output .= '<li class="fon-social-share-' . htmlspecialchars($network_key) . '">';
                $output .= '<a ' . $link_action . ' style="--fon-link-color:' . $social_networks[$network_key]['color']['normal'] . ';--fon-hover-color:' . $social_networks[$network_key]['color']['hover'] . ';--fon-active-color:' . $social_networks[$network_key]['color']['hover'] . ';" ' . ($widget_style == 'dropdown' ? 'class="dropdown-item"' : '') . '>';
                $output .= '<i class="' . htmlspecialchars($network['icon']) . ' fa-fw" aria-hidden="true" title="' . htmlspecialchars($network['label']) . '"></i>';

                if ($show_label) {
                    $output .= '<span class="fon-social-share-title ms-1">' . htmlspecialchars($network['label']) . '</span>';
                }

                $output .= '</a>';
                $output .= '</li>';
            }
        }

        $output .= '</ul>';

        if ($widget_style == 'dropdown') {
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function special_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetProducts($content, $moduleId, $pageData, $row, 'special');
    }

    private function tabs_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $align = '';
        if (isset($content->direction) && $content->direction == 'horizontal') {
            if (isset($content->align) && $content->align == 'right') {
                $align = 'justify-content-end';
            }
            else if (isset($content->align) && $content->align == 'center') {
                $align = 'justify-content-center';
            }
            else if (isset($content->align) && $content->align == 'justify') {
                $align = 'nav-justified';
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-tabs-widget ' . ($content->dark_container == 'yes' ? 'dark-container' : '') . ' ' . $content->direction . ' style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        if (isset($content->items) && is_array($content->items)) {
            $output .= '<ul class="nav nav-tabs widget-tabs ' . $align . '">';

            foreach ($content->items as $tbkey => $tbitem) {
                $title = (isset($tbitem->tab_title->{$this->lang}) && $tbitem->tab_title->{$this->lang} ? $tbitem->tab_title->{$this->lang} : array_values((array) $tbitem->tab_title)[0] ?? '');
                $subtitle = (isset($tbitem->tab_subtitle->{$this->lang}) && $tbitem->tab_subtitle->{$this->lang} ? $tbitem->tab_subtitle->{$this->lang} : array_values((array) $tbitem->tab_subtitle)[0] ?? '');

                if ($title) {
                    $output .= '<li class="nav-item">';
                    $output .= '<a class="nav-link widget-nav-link ' . ($tbkey == 0 ? 'active' : '') . '" data-bs-toggle="tab" href="#' . $moduleId . '-tab-' . $tbkey . '">';
                    if (isset($content->show_icon) && $content->show_icon == 'yes') {
                        $output .= '<i class="' . $tbitem->tab_icon . ' fa-fw ' . (isset($content->show_subtitle) && $content->show_subtitle == 'yes' && $subtitle ? 'subtitle' : '') . '"></i>';
                    }

                    $output .= '<span class="tab-titles">';
                    $output .= "\t" . '<span class="tab-title">' . $title . '</span>';
                    if (isset($content->show_subtitle) && $content->show_subtitle == 'yes' && $subtitle) {
                        $output .= '<span class="tab-subtitle">' . $subtitle . '</span>';
                    }

                    $output .= '</span>';
                    $output .= '</a>';
                    $output .= '</li>';
                }
            }

            $output .= '</ul>';
            $output .= '<div class="tab-content">';

            foreach ($content->items as $tckey => $tcitem) {
                $tabContent = (isset($tcitem->tab_content->{$this->lang}) && $tcitem->tab_content->{$this->lang} ? $tcitem->tab_content->{$this->lang} : array_values((array) $tcitem->tab_content)[0] ?? '');
                $output .= '<div id="' . $moduleId . '-tab-' . $tckey . '" class="tab-pane fade ' . ($tckey == 0 ? 'active show' : '') . '">';

                if ($tabContent) {
                    $output .= $tabContent;
                }

                $output .= '</div>';
            }

            $output .= '</div>';
        }

        $output .= '</div>';
        return $output;
    }

    private function team_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';

        if (isset($content->image_overlay_type)) {
            $style .= '#' . $widgetId . ' .team{';

            if ($content->image_overlay_type == 'color') {
                $style .= '--bs-bg-overlay-color: ' . $content->image_color_overlay . ';';
            }
            else {
                $style .= self::parseGradient($content->image_gradient_overlay, 'bg-overlay');
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $carouselData = '';
        $columns = [];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-row="' . $content->use_row . '" data-rows="' . htmlspecialchars(Utility::jencode($content->row, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel team-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl : '');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-team-widget overlay-' . $content->image_overlay_type . ' style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content ' . $containerClass . '" ' . $carouselData . '>';
        if (isset($content->items) && is_array($content->items)) {
            foreach ($content->items as $item) {
                if ($item->team_image) {
                    $item->team_image = static::assetLinkDetermine($item->team_image);
                }
                else {
                    $item->team_image = $lazyPlaceholder;
                }

                $imageDimensions = static::getImageDimensions($item->team_image, $pageData['badress']);

                if (!$isCarousel) {
                    $output .= '<div class="col">';
                }

                if (self::isJSON($item->team_socials)) {
                    $item->team_socials = Utility::jdecode($item->team_socials);
                }
                $team_position = (isset($item->team_position->{$this->lang}) && $item->team_position->{$this->lang} ? $item->team_position->{$this->lang} : array_values((array) $item->team_position)[0] ?? '');
                include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'team' . DS . 'style_' . $content->widget_style . '.php';

                if (!$isCarousel) {
                    $output .= '</div>';
                }
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function testimonial_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $source = (isset($content->source) && $content->source ? $content->source : 'manuel');
        $show_form = (isset($content->show_form) && $content->show_form == 'yes' ? true : false);
        $form_style = (isset($content->form_style) && $content->form_style ? $content->form_style : 'modal');
        $form_title = (isset($content->form_title) && isset($content->form_title->{$this->lang}) && $content->form_title->{$this->lang} ? $content->form_title->{$this->lang} : (isset($content->form_title) ? array_values((array) $content->form_title)[0] ?? '' : ''));
        $form_desc = (isset($content->form_desc) && isset($content->form_desc->{$this->lang}) && $content->form_desc->{$this->lang} ? $content->form_desc->{$this->lang} : (isset($content->form_desc) ? array_values((array) $content->form_desc)[0] ?? '' : ''));
        $form_button = (isset($content->form_button) && isset($content->form_button->{$this->lang}) && $content->form_button->{$this->lang} ? $content->form_button->{$this->lang} : (isset($content->form_button) ? array_values((array) $content->form_button)[0] ?? '' : ''));
        $form_position = (isset($content->form_position) && $content->form_position ? $content->form_position : 'after');
        $limit = (isset($content->limit) && $content->limit ? $content->limit : 8);
        $feedbackConfig = ___('blocks/customer-feedback');
        $form_action = Controllers::$init->CRLink('cfeedback-send');

        if ($source == 'wisecp') {
            $contentItems = self::getTestimonials($limit);
            $content->items = [];

            if ($contentItems) {
                foreach ($contentItems as $contentItem) {
                    $tci = new stdClass();
                    $tci->testimonial_author = $contentItem['full_name'];
                    $tci->testimonial_avatar = ($contentItem['image'] ? 'resources/uploads/customer-feedback/' . $contentItem['image'] : '');
                    $tci->testimonial_position = new stdClass();
                    $tci->testimonial_position->{$this->lang} = $contentItem['company_name'];
                    $tci->testimonial_message = new stdClass();
                    $tci->testimonial_message->{$this->lang} = $contentItem['message'];
                    $tci->testimonial_star = 5;
                    $tci->testimonial_star_style = 'google';
                    $content->items[] = $tci;
                }
            }
        }

        $carouselData = '';
        $columns = [];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-row="' . $content->use_row . '" data-rows="' . htmlspecialchars(Utility::jencode($content->row, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel testimonial-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl : '');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-testimonial-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        if (($source == 'wisecp') && $show_form && $form_style != 'inline' && $form_position == 'before') {
            $output .= '<p class="text-center"><button class="btn btn-default" type="button" data-bs-toggle="' . $form_style . '" data-bs-target="#' . $widgetId . '-feedback-form" ' . ($form_style == 'collapse' ? 'aria-expanded="false" aria-controls="collapseExample"' : '') . '><i class="fa-solid fa-comment"></i> ' . $form_button . '</button></p>';
        }

        $output .= '<div class="fon-widget-content ' . $containerClass . '" ' . $carouselData . '>';
        if (isset($content->items) && is_array($content->items)) {
            $even = true;

            foreach ($content->items as $item) {
                $testimonial_position = (isset($item->testimonial_position->{$this->lang}) && $item->testimonial_position->{$this->lang} ? $item->testimonial_position->{$this->lang} : array_values((array) $item->testimonial_position)[0] ?? '');
                $testimonial_message = (isset($item->testimonial_message->{$this->lang}) && $item->testimonial_message->{$this->lang} ? $item->testimonial_message->{$this->lang} : array_values((array) $item->testimonial_message)[0] ?? '');

                if ($content->display_avatar == 'yes') {
                    if ($item->testimonial_avatar) {
                        $item->testimonial_avatar = static::assetLinkDetermine($item->testimonial_avatar);
                    }
                    else {
                        $item->testimonial_avatar = $lazyPlaceholder;
                    }

                    $imageDimensions = static::getImageDimensions($item->testimonial_avatar, $pageData['badress']);
                }

                if (!$isCarousel) {
                    $output .= '<div class="col">';
                }

                include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'testimonial' . DS . 'style_' . $content->widget_style . '.php';

                if (!$isCarousel) {
                    $output .= '</div>';
                }

                $even = !$even;
            }
        }

        $output .= '</div>';
        if (($source == 'wisecp') && $show_form && $form_style != 'inline' && $form_position == 'after') {
            $output .= '<p class="text-center"><button class="btn btn-default" type="button" data-bs-toggle="' . $form_style . '" data-bs-target="#' . $widgetId . '-feedback-form" ' . ($form_style == 'collapse' ? 'aria-expanded="false" aria-controls="collapseExample"' : '') . '><i class="fa-solid fa-comment"></i> ' . $form_button . '</button></p>';
        }

        $output .= '</div>';
        if (($source == 'wisecp') && $show_form) {
            $captcha_status = (Config::get('options/captcha/status') == 1) && Config::get('options/captcha/customer-feedback') == 1;
            if (!$captcha_status && Config::get('options/BotShield/status')) {
                if (!class_exists('BotShield')) {
                    Helper::Load('BotShield');
                }

                $captcha_status = BotShield::is_blocked('customer-feedback');
            }

            if ($captcha_status) {
                if (!class_exists('Captcha')) {
                    Helper::Load('Captcha');
                }

                $feedbackCaptcha = Helper::get('Captcha');
            }

            $output .= '<div id="' . $widgetId . '-feedback-form" class="' . $form_style . '" ' . ($form_style == 'modal' ? 'tabindex="-1" aria-labelledby="' . $widgetId . 'ModalLabel" aria-hidden="true"' : '') . '>';

            if ($form_style == 'modal') {
                $output .= '<div class="modal-dialog modal-dialog-centered">';
                $output .= '<div class="modal-content">';
                $output .= '<div class="modal-header">';
                $output .= '<h3 class="modal-title fs-5" id="' . $widgetId . 'ModalLabel">' . $form_title . '</h3>';
                $output .= '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>';
                $output .= '</div>';
            }

            $output .= '<div class="modal-body ' . ($form_style != 'modal' ? 'rounded-4 bg-theme-light p-3 p-lg-4' : '') . '">';
            if (($form_style != 'modal') && $form_title) {
                $output .= '<h3 class="text-center my-3">' . $form_title . '</h3>';
            }

            if ($form_desc) {
                $output .= '<p class="text-center">' . $form_desc . '</p>';
            }

            $output .= '<form action="' . $form_action . '" method="POST" id="' . $widgetId . 'FeedbackForm" enctype="multipart/form-data" class="cFeedBackForm">';
            $output .= Validation::get_csrf_token('cfeedback');
            $output .= '<div class="row g-3 mb-3">';
            $output .= '<div class="col-12 col-lg-' . ($form_style == 'modal' ? '6' : '4') . '">';
            $output .= '<input type="text" class="form-control" name="full_name" placeholder="' . __('website/cfeedback/form-fullname') . '" aria-label="' . __('website/cfeedback/form-fullname') . '" id="' . $widgetId . '-full-name">';
            $output .= '</div>';
            $output .= '<div class="col-12 col-lg-' . ($form_style == 'modal' ? '6' : '4') . '">';
            $output .= '<input type="text" class="form-control" name="company_name" placeholder="' . __('website/cfeedback/form-company_name') . '" aria-label="' . __('website/cfeedback/form-company_name') . '" id="' . $widgetId . '-company-name">';
            $output .= '</div>';
            $output .= '<div class="col-12 col-lg-' . ($form_style == 'modal' ? '12' : '4') . '">';
            $output .= '<input type="text" class="form-control" name="email" placeholder="' . __('website/cfeedback/form-email') . '" aria-label="' . __('website/cfeedback/form-email') . '"  id="' . $widgetId . '-email">';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '<div class="mb-3">';
            $output .= '<textarea class="form-contol w-100" rows="5" style="resize: none;" maxlength="425" name="message" placeholder="' . __('website/cfeedback/form-message') . '" id="' . $widgetId . '-message"></textarea>';
            $output .= '</div>';
            $output .= '<div class="mb-3">';
            $output .= '<label for="' . $widgetId . '-file" class="form-label">' . __('website/cfeedback/form-image') . '</label>';
            $output .= '<input class="form-control" type="file"  name="image" id="' . $widgetId . '-file" accept=".jpg,.jpeg,.png">';
            $output .= '</div>';
            if (isset($feedbackCaptcha) && $feedbackCaptcha) {
                $output .= '<div class="input-group mb-3">';
                $output .= '<span class="input-group-text p-0 bg-white">' . $feedbackCaptcha->getOutput() . '</span>';

                if ($feedbackCaptcha->input) {
                    $output .= '<input id="requiredinput" name="' . $feedbackCaptcha->input_name . '" type="text"  class="form-control form-control-lg" aria-label="' . ___('needs/form-captcha-label') . '" placeholder="' . ___('needs/form-captcha-label') . '">';
                }

                $output .= '</div>';
            }

            $output .= '<p class="text-end">';
            $output .= '<a class="btn btn-success" id="' . $widgetId . 'FeedbackForm_submit" href="javascript:void(0);"><i class="fa-solid fa-paper-plane"></i> ' . $form_button . '</a>';
            $output .= '</p>';
            $output .= '<div id="' . $widgetId . 'FeedbackForm_output" class="text-danger fw-bold" style="display:none"></div>';
            $output .= '</form>';
            $output .= '<div id="' . $widgetId . 'FeeadbackForm_Successful" style="display: none">';
            $output .= '<div class="text-center my-5">';
            $output .= '<i class="fa-solid fa-check-circle fa-5x mb-3 text-success"></i>';
            $output .= '<h4 class="text-success fw-bold">' . __('website/cfeedback/successful-text1') . '</h4>';
            $output .= '<h5>' . __('website/cfeedback/successful-text2') . '</h5>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '</div>';

            if ($form_style == 'modal') {
                $output .= '</div>';
                $output .= '</div>';
            }

            $output .= '</div>';
            $output .= '<script type="text/javascript">' . "\n" . '                            $(document).ready(function(){' . "\n" . '                                $("#' . $widgetId . 'FeedbackForm_submit").on("click",function(){' . "\n" . '                                    MioAjaxElement($(this),{' . "\n" . '                                        waiting_text: \'' . __('website/others/button1-pending') . '\',' . "\n" . '                                        progress_text: \'' . __('website/others/button1-upload') . '\',' . "\n" . '                                        result:"' . $moduleId . 'feedback_result",' . "\n" . '                                    });' . "\n" . '                                });' . "\n" . '                                $("#' . $widgetId . '-feedback-form").on("shown.bs.collapse", function () {' . "\n" . '                                    this.scrollIntoView({ behavior: "smooth", block: "start" });' . "\n" . '                                });' . "\n" . '                            });' . "\n" . '                            function ' . $moduleId . 'feedback_result(result) {';

            if (isset($feedbackCaptcha)) {
                $output .= $feedbackCaptcha->submit_after_js();
            }

            $output .= 'if(result != ""){' . "\n" . '                                    var solve = getJson(result);' . "\n" . '                                    if(solve !== false){' . "\n" . '                                        if(solve.status == "error"){' . "\n" . '                                            if(solve.for != undefined && solve.for != ""){' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm "+solve.for).focus();' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm "+solve.for).addClass("is-invalid");' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm "+solve.for).change(function(){' . "\n" . '                                                    $(this).removeClass("is-invalid");' . "\n" . '                                                });' . "\n" . '                                            }' . "\n" . '    ' . "\n" . '                                            if(solve.message != undefined && solve.message != ""){' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm_output").fadeIn(500).html(solve.message);' . "\n" . '                                            }else{' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm_output").fadeOut(500).html("");' . "\n" . '                                            }' . "\n" . '                                        }else if(solve.status == "successful"){' . "\n" . '                                            $("#' . $widgetId . 'FeedbackForm_output").fadeOut(500).html("");' . "\n" . '                                            $("#' . $widgetId . 'FeedbackForm").slideUp(200,function(){' . "\n" . '                                                $("#' . $widgetId . 'FeeadbackForm_Successful").slideDown(200);' . "\n" . '                                            });' . "\n" . '                                        }' . "\n" . '                                    }else{' . "\n" . '                                        console.log(result);' . "\n" . '                                    }' . "\n" . '                                }' . "\n" . '                            }' . "\n" . '                        </script>';
        }

        return $output;
    }

    private function text_html_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $name_widget = (isset($content->name_widget) && isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : (isset($content->name_widget) ? array_values((array) $content->name_widget)[0] ?? '' : ''));
        $content_text = (isset($content->content) && isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : (isset($content->content) ? array_values((array) $content->content)[0] ?? '' : ''));
        $show_name = (isset($content->show_name) && $content->show_name == 'yes' ? true : false);
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $title_color = (isset($content->title_color) && $content->title_color ? $content->title_color : '');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : []);
        $title_margin = (isset($content->title_margin) && $content->title_margin ? $content->title_margin : (object) ['xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => '']);
        $column_count = (isset($content->column_count) && $content->column_count ? $content->column_count : []);
        $column_gap = (isset($content->column_gap) && $content->column_gap ? $content->column_gap : []);
        $content_truncation = (isset($content->content_truncation) && $content->content_truncation == 'yes' ? true : false);
        $truncation_max_word = (isset($content->truncation_max_word) && $content->truncation_max_word ? $content->truncation_max_word : 50);
        $truncation_action_color = (isset($content->truncation_action_color) && $content->truncation_action_color ? $content->truncation_action_color : '#0000ff');
        $truncation_action_font = (isset($content->truncation_action_font) && $content->truncation_action_font ? $content->truncation_action_font : []);
        $truncation_action_text = (isset($content->truncation_action_text) && isset($content->truncation_action_text->{$this->lang}) && $content->truncation_action_text->{$this->lang} ? $content->truncation_action_text->{$this->lang} : (isset($content->truncation_action_text) ? array_values((array) $content->truncation_action_text)[0] ?? '' : ''));
        $dropcap = (isset($content->dropcap) && $content->dropcap == 'yes' ? true : false);
        $dropcap_color = (isset($content->dropcap_color) && $content->dropcap_color ? $content->dropcap_color : '');
        $dropcap_size = (isset($content->dropcap_size) && $content->dropcap_size ? $content->dropcap_size : []);
        $widget_content_classes = '';

        if ($column_count) {
            $widget_content_classes .= ' fon-widget-content-column';
        }

        if ($dropcap) {
            $widget_content_classes .= ' fon-widget-content-drop-cap';
        }

        $style = '';
        if ($show_name && $name_widget) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';

            if ($title_color) {
                $style .= 'color: ' . $title_color . ';';
            }

            if ($title_font) {
                $style .= self::parseFontProperties($title_font);
            }

            $style .= '}';
        }

        if ($title_margin) {
            $titleMarginResponsiveItems = [
                '.fon-widget-title' => [
                ['type' => 'margin-bottom', 'unit' => 'px', 'value' => $title_margin]
            ]
            ];
            $style .= self::parseResponsiveItems($titleMarginResponsiveItems, $widgetId);
        }
        if ($column_count || $column_gap || $dropcap) {
            if ($column_count || $column_gap) {
                $widget_content_classes .= ' fon-widget-content-column';
                $columnResponsiveItems = [
                    '.fon-widget-content-column' => [
                    ['type' => 'column-count', 'unit' => false, 'value' => $column_count],
                    ['type' => 'column-gap', 'unit' => 'px', 'value' => $column_gap]
                ]
                ];
                $style .= self::parseResponsiveItems($columnResponsiveItems, $widgetId);
            }

            if ($dropcap) {
                $widget_content_classes .= ' fon-widget-content-drop-cap';
                $style .= '#' . $widgetId . ' .fon-widget-content-drop-cap:first-letter,#' . $widgetId . ' .fon-widget-content-drop-cap>*:first-child:first-letter{';
                $style .= 'color: ' . $dropcap_color . ';';
                $style .= '}';
                $dropcapResponsiveItems = [
                    '.fon-widget-content-drop-cap:first-letter,.fon-widget-content-drop-cap>*:first-child:first-letter' => [
                    ['type' => 'font-size', 'unit' => 'px', 'value' => $dropcap_size]
                ]
                ];
                $style .= self::parseResponsiveItems($dropcapResponsiveItems, $widgetId);
            }
        }

        if ($content_truncation) {
            $style .= '#' . $widgetId . ' .fon-widget-content-truncation-show{';
            $style .= 'color: ' . $truncation_action_color . ';';

            if ($truncation_action_font) {
                $style .= self::parseFontProperties($truncation_action_font);
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-text-html-widget ' . $content->fon_class . '">';
        if ($show_name && $name_widget) {
            $output .= '<' . $heading_selector . ' class="fon-widget-title">';
            $output .= self::getPriceHolders($name_widget);
            $output .= '</' . $heading_selector . '>';
        }

        $content_text = self::getPriceHolders($content_text);
        $plain_text = html_entity_decode($content_text, ENT_QUOTES | ENT_HTML5);
        $plain_text = strip_tags($plain_text);

        if (trim(str_replace([' ', ' '], '', $plain_text)) === '') {
            $content_text = '';
        }

        if ($content_text) {
            $output .= '<div class="fon-widget-content' . $widget_content_classes . '">';
            $text_block_text = $content_text;
            if ($content_truncation && !empty($truncation_max_word) && (int) $truncation_max_word < (int) self::wordCount($plain_text)) {
                $arrayString = explode(' ', $content_text);
                $text_block_text = implode(' ', array_slice($arrayString, 0, (int) $truncation_max_word));
                $text_block_text .= '<template class="fon-widget-content-full-text">' . $content_text . '</template>';
                $text_block_text .= '<div class="fon-widget-content-btn-container fon-widget-content-truncation-show"><div role="button" class="fon-widget-content-btn-show-more"><i class="fa-solid fa-plus"></i> ' . $truncation_action_text . '</div></div>';
            }

            $output .= $text_block_text;
            $output .= '</div>';
        }

        $output .= '</div>';
        return $output;
    }

    private function timeline_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        if (in_array($content->widget_style, ['5'])) {
            $this->addAsset('slick');
        }
        $mediaType = (isset($content->media_type) && $content->media_type ? $content->media_type : 'icon');
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-timeline-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content ' . (in_array($content->widget_style, ['default', '1']) ? 'row' : '') . ' py-4">';
        if (isset($content->items) && is_array($content->items)) {
            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'timeline' . DS . 'style_' . $content->widget_style . '.php';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function vector_map_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $map_type = (isset($content->map_type) && $content->map_type ? $content->map_type : 'world');
        $show_zooms = (isset($content->show_zooms) && $content->show_zooms == 'yes' ? 'true' : 'false');
        $region_fill = (isset($content->region_fill) && $content->region_fill ? $content->region_fill : '#d1d5db');
        $region_stroke = (isset($content->region_stroke) && $content->region_stroke ? $content->region_stroke : '#e5e7eb');
        $region_stroke_width = (isset($content->region_stroke_width) && $content->region_stroke_width ? $content->region_stroke_width : 1);
        $markerItems = (isset($content->items) && $content->items && is_array($content->items) ? $content->items : []);
        $marker_stroke = (isset($content->marker_stroke) && $content->marker_stroke ? $content->marker_stroke : '#ffffff');
        $marker_label = (isset($content->marker_label) && $content->marker_label ? $content->marker_label : 13);
        $marker_radius = (isset($content->marker_radius) && $content->marker_radius ? $content->marker_radius : 6);
        $marker_stroke_width = (isset($content->marker_stroke_width) && $content->marker_stroke_width ? $content->marker_stroke_width : 5);
        $hover_marker_radius = $marker_radius + 3;
        $hover_marker_stroke_width = $marker_stroke_width + 3;
        $show_tooltip = (isset($content->show_tooltip) && $content->show_tooltip == 'yes' ? 'true' : 'false');
        $tooltip_bg = (isset($content->tooltip_bg) && $content->tooltip_bg ? $content->tooltip_bg : '#010101');
        $tooltip_color = (isset($content->tooltip_color) && $content->tooltip_color ? $content->tooltip_color : '#ffffff');
        $show_lines = (isset($content->show_lines) && $content->show_lines == 'yes' ? true : false);
        $animate_lines = (isset($content->animate_lines) && $content->animate_lines == 'yes' ? 'true' : 'false');
        $curvature_lines = (isset($content->curvature_lines) && $content->curvature_lines == 'yes' ? true : false);
        $line_curvature = (isset($content->line_curvature) && $content->line_curvature != '' ? $content->line_curvature : -0.7);
        $line_stroke = (isset($content->line_stroke) && $content->line_stroke ? $content->line_stroke : '#818187');
        $line_stroke_width = (isset($content->line_stroke_width) && $content->line_stroke_width ? $content->line_stroke_width : 1);
        $defaultMarkerFillNormal = '#3b82f6';
        $defaultMarkerFillHover = '#ff5050';
        if (isset($content->marker_fill) && is_object($content->marker_fill)) {
            $marker_fill_normal = (!empty($content->marker_fill->normal) ? $content->marker_fill->normal : $defaultMarkerFillNormal);
            $marker_fill_hover = (!empty($content->marker_fill->hover) ? $content->marker_fill->hover : $defaultMarkerFillHover);
        }
        else if (isset($content->marker_fill) && is_string($content->marker_fill) && !empty($content->marker_fill)) {
            $marker_fill_normal = $content->marker_fill;
            $marker_fill_hover = $defaultMarkerFillHover;
        }
        else {
            $marker_fill_normal = $defaultMarkerFillNormal;
            $marker_fill_hover = $defaultMarkerFillHover;
        }

        $markers = [];
        $lines = [];

        if ($markerItems) {
            foreach ($markerItems as $mKey => $marker) {
                $marker_name = (isset($marker->name) && $marker->name ? $marker->name : '');
                $marker_coords = (isset($marker->coords) && $marker->coords ? $marker->coords : [0, 0]);
                $marker_coords = (is_string($marker_coords) ? explode(',', $marker_coords) : $marker_coords);
                $marker_lineto = (isset($marker->lineto) && $marker->lineto ? $marker->lineto : '');
                $marker_tooltip = (isset($marker->tooltip) && isset($marker->tooltip->{$this->lang}) && $marker->tooltip->{$this->lang} ? $marker->tooltip->{$this->lang} : (isset($marker->tooltip) ? array_values((array) $marker->tooltip)[0] ?? '' : ''));
                $markers[$mKey] = ['name' => $marker->name ?? '', 'coords' => $marker_coords];

                if ($marker_tooltip) {
                    $markers[$mKey]['tooltip'] = $marker_tooltip;
                }
                if ($marker_lineto && !empty($marker_name)) {
                    $lines[] = ['from' => $marker_name, 'to' => $marker_lineto];
                }
            }
        }

        $markersJson = json_encode($markers);
        $linesJson = ($show_lines && $lines ? 'lines: ' . json_encode($lines) . ',' : '');
        $curvature = ($show_lines && $lines && $curvature_lines ? 'curvature: ' . $line_curvature . ',' : '');
        $this->addAsset('jsvectormap');
        $style = '';
        $responsiveItems = [
            '#' . $widgetId . '-map' => [
            ['type' => 'height', 'unit' => 'px', 'value' => $content->map_height]
        ]
        ];
        $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-vector-map-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content position-relative">';
        $output .= '<div class="fon-vector-map-container" id="' . $widgetId . '-map">';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        $js = '<script defer src="' . $pageData['tadress'] . 'js/maps/' . $map_type . '.js"></script>' . PHP_EOL;
        $js .= '<script>' . "\n" . 'window.addEventListener("load", function() {' . "\n" . '     setTimeout(function() {' . "\n" . '        var markers' . $moduleId . ' = ' . $markersJson . ';' . "\n" . '        window.map' . $moduleId . ' = new jsVectorMap({' . "\n" . '            selector: document.querySelector("#' . $widgetId . '-map"),' . "\n" . '            map: "' . $map_type . '",' . "\n\t\t\t" . 'backgroundColor: "transparent",' . "\n" . '            showTooltip: ' . $show_tooltip . ',' . "\n\t\t\t" . 'zoomOnScroll: false,' . "\n" . '            zoomButtons: ' . $show_zooms . ',' . "\n\t\t\t" . 'onLoaded(map) {' . "\n" . '                document.querySelectorAll(".jvm-marker, .jvm-label").forEach(i => {' . "\n" . '                    i.classList.add("animated");' . "\n\t\t\t\t" . '});' . "\n" . '                window.addEventListener("resize", () => map.updateSize());' . "\n" . '                setTimeout(() => map.updateSize(), 700);' . "\n\t\t\t" . '},' . "\n\t\t\t" . 'regionStyle: {' . "\n\t\t\t\t" . 'initial: {' . "\n" . '                    fill: "' . $region_fill . '",' . "\n" . '                    stroke: "' . $region_stroke . '",' . "\n" . '                    strokeWidth: ' . $region_stroke_width . ',' . "\n\t\t\t\t\t" . 'fillOpacity: 1,' . "\n\t\t\t\t\t" . 'fillRule:"evenodd"' . "\n\t\t\t\t" . '},' . "\n\t\t\t" . '},' . "\n" . '            markers: markers' . $moduleId . ',' . "\n" . '            ' . $linesJson . "\n\t\t\t" . 'markerStyle: {' . "\n\t\t\t\t" . 'initial: {' . "\n" . '                    r: ' . $marker_radius . ',' . "\n" . '                    fill: "' . $marker_fill_normal . '",' . "\n" . '                    stroke: "' . $marker_stroke . '",' . "\n" . '                    strokeWidth: ' . $marker_stroke_width . ',' . "\n" . '                    strokeOpacity: 0.5' . "\n\t\t\t\t" . ' },' . "\n" . '                hover: {' . "\n" . '                    r: ' . $hover_marker_radius . ',' . "\n" . '                    fill: "' . $marker_fill_hover . '",' . "\n" . '                    strokeWidth: ' . $hover_marker_stroke_width . ',' . "\n" . '                }' . "\n\t\t\t" . '},' . "\n\t\t\t" . 'markerLabelStyle: {' . "\n\t\t\t\t" . 'initial: {' . "\n" . '                    fontSize: ' . $marker_label . ',' . "\n" . '                    fontWeight: 600,' . "\n" . '                    fill: "#35373e",' . "\n\t\t\t\t" . '},' . "\n\t\t\t" . '},' . "\n\t\t\t" . 'labels: {' . "\n" . '                markers: {' . "\n" . '                    render: function (marker) {' . "\n" . '                        return marker.name;' . "\n" . '                    },' . "\n" . '                },' . "\n" . '            },' . "\n" . '            lineStyle: {' . "\n" . '                strokeDasharray: "3 3 3",' . "\n" . '                animation: ' . $animate_lines . ',' . "\n" . '                stroke: "' . $line_stroke . '",' . "\n" . '                strokeWidth: ' . $line_stroke_width . ',' . "\n" . '                ' . $curvature . "\n\t\t\t" . '},' . "\n" . '            onMarkerTooltipShow(event, tooltip, index) {' . "\n" . '                let getMarker = markers' . $moduleId . '[index];' . "\n" . '                if(getMarker && getMarker.tooltip){' . "\n" . '                    let markerHTML = \'<h5 class="fs-15">\' + getMarker.name +\'</h5><p class="mb-0 small">\'+ getMarker.tooltip + \'</p>\';' . "\n" . '                    tooltip.text(markerHTML,true);' . "\n\t\t\t\t" . '}' . "\n" . '                tooltip.css({ ' . "\n" . '                    backgroundColor: "' . $tooltip_bg . '", ' . "\n" . '                    color: "' . $tooltip_color . '" ' . "\n" . '                });' . "\n" . '            },' . "\n" . '            onRegionTooltipShow(event, tooltip, index) {' . "\n" . '                tooltip.css({ ' . "\n" . '                    backgroundColor: "' . $tooltip_bg . '", ' . "\n" . '                    color: "' . $tooltip_color . '" ' . "\n" . '                });' . "\n" . '            }' . "\n" . '        });' . "\n" . '    }, 1500);' . "\n" . '});' . "\n" . '</script>';
        $this->addScript('footer', $pageData['page'], $js);
        return $output;
    }

    private function video_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $nameWidget = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        $style = '';
        if (($content->name_widget_status == 'yes') && $nameWidget) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';

            if ($content->title_color) {
                $style .= 'color: ' . $content->title_color . ';';
            }

            if ($content->title_margin->top) {
                $style .= 'margin-top: ' . $content->title_margin->top . 'px;';
            }

            if ($content->title_margin->bottom) {
                $style .= 'margin-bottom: ' . $content->title_margin->bottom . 'px;';
            }

            if ($content->title_font) {
                $style .= self::parseFontProperties($content->title_font);
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $src = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-video-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        if (($content->name_widget_status == 'yes') && $nameWidget) {
            $output .= '<' . $content->heading_selector . ' class="fon-widget-title">';
            $output .= $nameWidget;
            $output .= '</' . $content->heading_selector . '>';
        }

        if ($content->video_source == '2') {
            if ($content->mp4_video) {
                $show_control = (isset($content->show_control) && $content->show_control == 'yes' ? 1 : 0);
                $video_loop = (isset($content->video_loop) && $content->video_loop == 'yes' ? 1 : 0);
                $autoplay_video = (isset($content->autoplay_video) && $content->autoplay_video == 'yes' ? 1 : 0);
                $video_mute = (isset($content->video_mute) && $content->video_mute == 'yes' ? 1 : 0);
                $video_poster = '';

                if (is_object($content->video_poster)) {
                    $video_poster = (isset($content->video_poster->{$this->lang}) && $content->video_poster->{$this->lang} ? $content->video_poster->{$this->lang} : array_values((array) $content->video_poster)[0] ?? '');
                }
                else if (is_string($content->video_poster)) {
                    $video_poster = $content->video_poster;
                }

                $video_poster = ($video_poster ? static::assetLinkDetermine($video_poster) : $lazyPlaceholder);
                $mp4_video = '';

                if (is_object($content->mp4_video)) {
                    $mp4_video = (isset($content->mp4_video->{$this->lang}) && $content->mp4_video->{$this->lang} ? $content->mp4_video->{$this->lang} : array_values((array) $content->mp4_video)[0] ?? '');
                }
                else if (is_string($content->mp4_video)) {
                    $mp4_video = $content->mp4_video;
                }

                $mp4_video = static::assetLinkDetermine($mp4_video);
                $output .= '<div class="fon-widget-video-local-video-wrap">';
                $output .= '<video class="fon-widget-video-local-source"' . ($video_loop != 0 ? ' loop' : '') . '' . ($autoplay_video != 0 ? ' autoplay' : '') . '' . ($show_control != 0 ? ' controls' : '') . '' . ($video_mute ? ' muted' : '') . ' ' . ($video_poster ? 'poster="' . $video_poster . '"' : '') . ' controlsList="nodownload" playsinline>';
                $output .= '<source src="' . $mp4_video . '" type="video/mp4">';
                $output .= '</video>';
                $output .= '</div>';
            }
        }
        else {
            if ($content->video_url) {
                $videoUrl = '';

                if (is_object($content->video_url)) {
                    $videoUrl = (isset($content->video_url->{$this->lang}) && $content->video_url->{$this->lang} ? $content->video_url->{$this->lang} : array_values((array) $content->video_url)[0] ?? '');
                }
                else if (is_string($content->video_url)) {
                    $videoUrl = $content->video_url;
                }

                $video = parse_url($videoUrl);
                $video_title = '';
                $aspect_ratio = '16by9';

                if ($content->video_source == '0') {
                    $no_cookie = (isset($content->no_cookie) && $content->no_cookie == 'yes' ? 1 : 0);
                    $show_rel_video = (isset($content->show_rel_video) && $content->show_rel_video == 'yes' ? '&rel=0' : '&rel=1');
                    $youtube_no_cookie = ($no_cookie ? '-nocookie' : '');
                    $youtube_shorts = (isset($content->youtube_shorts) && $content->youtube_shorts == 'yes' ? 1 : 0);
                    $aspect_ratio = (isset($content->aspect_ratio) && $content->aspect_ratio && $youtube_shorts ? $content->aspect_ratio : '16by9');

                    switch ($video['host']) {
                    case 'www.youtu.be':
                    case 'youtu.be':
                        $id = trim($video['path'], '/');
                        $src = '//www.youtube' . $youtube_no_cookie . '.com/embed/' . $id . '?iv_load_policy=3' . $show_rel_video;
                        $video_title = (isset($content->video_title->{$this->lang}) && $content->video_title->{$this->lang} ? $content->video_title->{$this->lang} : $this->language['widget_video_default_title']);
                        break;
                    case 'www.youtube.com':
                    case 'youtube.com':
                        parse_str($video['query'], $query);
                        $id = ($youtube_shorts ? trim($video['path'], '/shorts/') : $query['v']);
                        $src = '//www.youtube' . $youtube_no_cookie . '.com/embed/' . $id . '?iv_load_policy=3' . $show_rel_video;
                        $video_title = (isset($content->video_title->{$this->lang}) && $content->video_title->{$this->lang} ? $content->video_title->{$this->lang} : $this->language['widget_video_default_title']);
                        break;
                    }
                }
                else if ($content->video_source == '1') {
                    $id = trim($video['path'], '/');
                    $initialSrc = '//player.vimeo.com/video/' . $id;
                    $vimeo_show_author = (isset($content->vimeo_show_author) && $content->vimeo_show_author == 'yes' ? 'byline=1' : 'byline=0');
                    $vimeo_mute_video = (isset($content->vimeo_mute_video) && $content->vimeo_mute_video == 'yes' ? 'muted=1' : 'muted=0');
                    $vimeo_show_video_title = (isset($content->vimeo_show_video_title) && $content->vimeo_show_video_title == 'yes' ? 'title=1' : 'title=0');
                    $vimeo_show_author_profile = (isset($content->vimeo_show_author_profile) && $content->vimeo_show_author_profile == 'yes' ? 'portrait=1' : 'portrait=0');
                    $embeddedParameter = [$vimeo_mute_video, $vimeo_show_author, $vimeo_show_author_profile, $vimeo_show_video_title];
                    $embeddedString = '';
                    $separator = '&';

                    foreach ($embeddedParameter as $key => $value) {
                        $embeddedString .= (0 < $key ? $separator . $value : $value);
                    }

                    $src = $initialSrc . '?' . $embeddedString;
                }
            }

            $output .= '<div class="fon-video-block fon-embed-responsive fon-embed-responsive-' . $aspect_ratio . '">';
            $output .= '<iframe class="fon-embed-responsive-item" src="' . $src . '" ' . ($video_title ? 'title="' . $video_title . '"' : '') . ' allow="accelerometer" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>';
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function getWidgetProducts(object $content, string|int $moduleId, array $pageData, object $row, string $widgetName): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }
        if (($content->column->xl <= 3) && $content->use_carousel == 'yes') {
            $style .= '@media(min-width:1200px){';
            $style .= '#' . $widgetId . '-tabContent .tab-pane .fon-content-carousel{';
            $style .= 'max-width: 992px;';
            $style .= 'margin-left: auto;';
            $style .= 'margin-right: auto;';
            $style .= '}';
            $style .= '}';
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $carouselData = '';

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-row="no" data-rows="' . htmlspecialchars(Utility::jencode(['xl' => 1, 'lg' => 1, 'md' => 1, 'sm' => 1, 'xs' => 1]), ENT_QUOTES, 'UTF-8') . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '"';
        }

        $widgetStyle = 'default';
        $widgetThemeStyle = Config::get('theme/package_style');
        if (($widgetThemeStyle == '0') || !$widgetThemeStyle) {
            $widgetThemeStyle = 'default';
        }
        if ($content && isset($content->widget_style)) {
            $widgetStyle = $content->widget_style;
        }
        $widgetData = ['pageData' => $pageData, 'widget_name' => $widgetName, 'widget_content' => $content, 'carouselData' => $carouselData, 'currency_symbols' => self::getCurrencySymbols(), 'isWidget' => ($content ? true : false), 'widgetStyle' => $widgetStyle, 'widgetId' => $widgetId, 'row' => $row, 'showCoupon' => (isset($content->show_coupon) && $content->show_coupon == 'yes' ? true : false)];
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-' . $widgetName . '-widget ' . $content->fon_class . ' pricing-widget-style-' . $widgetStyle . '">';
        if (isset($pageData['items']) && $pageData['items'] && $widgetName == $content->page_type && $content->source == 'none') {
            $products = $this->getProductPackages(array_merge($widgetData, $pageData));
            $output .= $products;
        }
        else {
            $output .= '<div class="fon-widget-content">';
            $widgetItems = $this->getWidgetItems('products', $content->source, $widgetName, $content->limit);

            if ($widgetItems) {
                if ($widgetItems['type'] == 'cats') {
                    if (is_array($widgetItems['cats']) && 1 < count($widgetItems['cats'])) {
                        $output .= '<ul class="product-group-tabs nav nav-pills mb-5 justify-content-center" id="' . $widgetId . '-tab" role="tablist">';
                        $i = 0;

                        foreach ($widgetItems['cats'] as $catId => $cat) {
                            if (!empty($widgetItems['items'][$catId])) {
                                $output .= '<li class="nav-item"  role="presentation">';
                                $output .= '<a class="nav-link ' . ($i == 0 ? 'active' : '') . '" id="product-tab-' . $catId . '" data-bs-toggle="tab" href="#product-tab-content-' . $catId . '" role="tab" aria-controls="product-tab-content-' . $catId . '" aria-selected="' . ($i == 0 ? 'true' : 'false') . '">';
                                if (isset($cat['options']['icon']) && $cat['options']['icon']) {
                                    $output .= '<i class="' . $cat['options']['icon'] . '"></i> ';
                                }
                                else if (isset($cat['icon']) && $cat['icon']) {
                                    $img_path = 'resources' . DS . 'uploads' . DS . 'category-icon' . DS . $cat['icon'];

                                    if (file_exists($img_path)) {
                                        $output .= '<img class="d-inline me-2" src="' . static::assetLinkDetermine($img_path) . '" width="25" height="25" alt="' . $cat['title'] . '"> ';
                                    }
                                }

                                $output .= $cat['title'];
                                $output .= '</a>';
                                $output .= '</li>';
                                ++$i;
                            }
                        }

                        $output .= '</ul>';
                    }

                    $output .= '<div class="tab-content product-group-tabs-content" id="' . $widgetId . '-tabContent">';
                    $i = 0;

                    foreach ($widgetItems['items'] as $catId => $items) {
                        if (!empty($widgetItems['items'][$catId])) {
                            if (is_array($widgetItems['cats']) && 1 < count($widgetItems['cats'])) {
                                $output .= '<div class="tab-pane fade ' . ($i == 0 ? 'show active' : '') . '" id="product-tab-content-' . $catId . '" role="tabpanel" aria-labelledby="product-tab-' . $catId . '" tabindex="0">';
                            }

                            $products = $this->getPackagesList($widgetItems['items'][$catId], $widgetItems['cats'][$catId], $widgetData);
                            $output .= $products;
                            if (isset($content->show_all_link) && $content->show_all_link == 'yes') {
                                $output .= '<p class="text-center my-2">' . __('theme/all-products-link', ['{group_link}' => self::parseCanonicalUrl(Controllers::$init->CRLink('products', [$widgetItems['cats'][$catId]['route']])), '{group_title}' => $widgetItems['cats'][$catId]['title']]) . '</p>';
                            }
                            if (is_array($widgetItems['cats']) && 1 < count($widgetItems['cats'])) {
                                $output .= '</div>';
                            }

                            ++$i;
                        }
                    }

                    $output .= '</div>';
                }
                else {
                    foreach ($widgetItems['items'] as $item_key => $item) {
                        if ($item['type'] != 'sms') {
                            $category = $this->getCategory($item['category'], 'products', $item['type']);

                            if ($category) {
                                $widgetItems['items'][$item_key]['category'] = $category;
                            }
                        }
                    }

                    $products = $this->getPackagesList($widgetItems['items'], [], $widgetData);
                    $output .= $products;
                    if (isset($content->show_all_link) && $content->show_all_link == 'yes' && $widgetName != 'special') {
                        $output .= '<p class="text-center my-2">' . __('theme/all-products-link', ['{group_link}' => self::parseCanonicalUrl(Controllers::$init->CRLink('products', [$widgetName])), '{group_title}' => $widgetName]) . '</p>';
                    }
                }
            }

            $output .= '</div>';
        }

        $output .= '</div>';
        return $output;
    }

    private function getWidgetPages(object $content, string|int $moduleId, array $pageData, string $widgetName): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $carouselData = '';

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-row="' . $content->use_row . '" data-rows="' . htmlspecialchars(Utility::jencode($content->row, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '"  id="carousel-' . $widgetId . '"';
        }

        $widgetData = ['name' => $widgetName, 'content' => $content, 'currency_symbols' => self::getCurrencySymbols(), 'carouselData' => $carouselData, 'isWidget' => ($content ? true : false), 'badress' => $pageData['badress']];
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-' . $widgetName . '-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $widgetItems = $this->getWidgetItems('pages', $content->sources, $widgetName, $content->limit);
        $oneCategoryForAllLink = [];

        if ($widgetItems) {
            if ($widgetItems['type'] == 'cats') {
                if (1 < count($widgetItems['cats'] ?? [])) {
                    $output .= '<ul class="product-group-tabs nav nav-pills mb-3 justify-content-center" id="' . $widgetId . '-tab" role="tablist">';
                    $i = 0;

                    foreach ($widgetItems['cats'] as $catId => $cat) {
                        $output .= '<li class="nav-item"  role="presentation">';
                        $output .= '<a class="nav-link ' . ($i == 0 ? 'active' : '') . '" id="product-tab-' . $catId . '" data-bs-toggle="tab" href="#product-tab-content-' . $catId . '" role="tab" aria-controls="product-tab-content-' . $catId . '" aria-selected="' . ($i == 0 ? 'true' : 'false') . '">';
                        if (isset($cat['options']['icon']) && $cat['options']['icon']) {
                            $output .= '<i class="' . $cat['options']['icon'] . '"></i> ';
                        }
                        else if (isset($cat['icon']) && $cat['icon']) {
                            $output .= '<img class="d-inline me-2" src="' . $cat['icon'] . '" width="25" height="25" alt="' . $cat['title'] . '"> ';
                        }

                        $output .= $cat['title'];
                        $output .= '</a>';
                        $output .= '</li>';
                        ++$i;
                    }

                    $output .= '</ul>';
                }

                $output .= '<div class="tab-content product-group-tabs-content" id="' . $widgetId . '-tabContent">';
                $i = 0;

                foreach ($widgetItems['items'] as $catId => $items) {
                    if (1 < count($widgetItems['cats'] ?? [])) {
                        $output .= '<div class="tab-pane fade ' . ($i == 0 ? 'show active' : '') . '" id="product-tab-content-' . $catId . '" role="tabpanel" aria-labelledby="product-tab-' . $catId . '" tabindex="0">';
                    }

                    $oneCategoryForAllLink = $widgetData['category'] = $widgetItems['cats'][$catId];
                    $pages = $this->getPageList($widgetItems['items'][$catId], $widgetData);
                    $output .= $pages;

                    if (1 < count($widgetItems['cats'] ?? [])) {
                        $output .= '</div>';
                    }

                    ++$i;
                }

                $output .= '</div>';
            }
            else {
                foreach ($widgetItems['items'] as $item_key => $item) {
                    if ($item['type'] != 'news') {
                        $oneCategoryForAllLink = $category = $this->getCategory($item['category'], $item['type']);

                        if ($category) {
                            $widgetItems['items'][$item_key]['category'] = $category;
                        }
                    }
                }

                $pages = $this->getPageList($widgetItems['items'], $widgetData);
                $output .= $pages;
            }
        }

        $output .= '</div>';
        if (isset($content->show_all_link) && $content->show_all_link == 'yes') {
            $CRLinkType = ($widgetName == 'software' ? 'softwares' : $widgetName);
            $allLink = Controllers::$init->CRLink($CRLinkType);
            if (($widgetItems['type'] == 'cats') && count($widgetItems['cats']) == 1) {
                $allLink = self::parseCanonicalUrl(Controllers::$init->CRLink($CRLinkType . '_category', [$oneCategoryForAllLink['route']]));
            }

            $output .= '<p class="text-center">' . __('theme/all-' . $widgetName . '-link', ['{page_link}' => $allLink]) . '</p>';
        }

        $output .= '</div>';
        return $output;
    }

    private function getWidgetItems(string $type, array|string $source, string $kind = '', int $limit = 10): array
    {
        $sourceItems = ($source != 'none' ? explode(': ', $source) : []);
        $sourceType = ($sourceItems ? $sourceItems[0] : '');
        $sourceIds = (($source != 'none') && $sourceItems ? explode(',', $sourceItems[1]) : $source);
        $result = ['type' => $sourceType];

        if ($sourceType == 'cats') {
            foreach ($sourceIds as $sourceId) {
                if ($sourceId == 'none') {
                    $result['cats'][$sourceId] = [];
                    $result['items'][$sourceId] = ($type == 'products' ? $this->getProducts($kind, $sourceId, $limit, true) : $this->getPages($kind, $sourceId, $limit, true));
                }
                else {
                    $category = ($type == 'products' ? $this->getCategory($sourceId, $type) : $this->getCategory($sourceId, $kind));

                    if ($category) {
                        $result['cats'][$category['id']] = $category;
                        $result['items'][$category['id']] = ($type == 'products' ? $this->getProducts($kind, $category['id'], $limit, true) : $this->getPages($kind, $category['id'], $limit, true));
                    }
                }
            }
        }
        else {
            $result['items'] = ($type == 'products' ? $this->getProducts($kind, $sourceIds, $limit, true) : $this->getPages($kind, $sourceIds, $limit, true));
        }

        return $result;
    }

    private function getPageList(array $list, array $data): string
    {
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $output = '';

        if ($list) {
            if ($data['carouselData']) {
                $containerClass = 'fon-content-carousel ' . $data['name'] . '-carousel';
            }
            else {
                $containerClass = 'row row-cols-' . $data['content']->column->xs . ' row-cols-sm-' . $data['content']->column->sm . ' row-cols-md-' . $data['content']->column->md . ' row-cols-lg-' . $data['content']->column->lg . ' row-cols-xl-' . $data['content']->column->xl;
            }

            $output .= '<div class="' . $containerClass . ' ' . $data['name'] . '-style-' . $data['content']->widget_style . ' ' . $data['name'] . '-items-container" ' . $data['carouselData'] . '>';

            foreach ($list as $item) {
                if (isset($data['category']) && is_int($item['category'])) {
                    $item['category'] = $data['category'];
                }

                $item['route'] = self::getItemLink($item['type'], $item['route'], false);

                if ($item['cover_image']) {
                    if ($item['type'] == 'software') {
                        $image_path = 'resources' . DS . 'uploads' . DS . $item['type'] . DS . $item['cover_image'];
                    }
                    else {
                        $image_path = 'resources' . DS . 'uploads' . DS . $item['type'] . DS . 'thumb' . DS . $item['cover_image'];
                    }
                }
                else if ($item['type'] == 'software') {
                    $image_path = 'resources' . DS . 'uploads' . DS . $item['type'] . DS . 'list-image-default.jpg';
                }
                else {
                    $image_path = 'resources' . DS . 'uploads' . DS . $item['type'] . DS . 'default.jpg';
                }

                $imageDimensions = NULL;

                if (file_exists($image_path)) {
                    $item['cover_image'] = $item['image'] = static::assetLinkDetermine($image_path);
                    $imageDimensions = static::getImageDimensions($image_path, $data['badress']);
                }

                $item['short_title'] = Utility::short_text(Filter::html_clear($item['title']), 0, 50, true);
                $item['short_content'] = Utility::short_text(Filter::html_clear($item['content']), 0, $data['content']->intro_text_limit ?? 100, true);
                $item['ctime'] = ($data['isWidget'] ? DateManager::format(Config::get('options/date-format'), $item['ctime']) : $item['ctime']);

                if ($item['type'] != 'news') {
                    $item['category_name'] = (isset($item['category']['title']) && $item['category']['title'] ? $item['category']['title'] : '');
                    $item['category_route'] = (isset($item['category']['route']) && $item['category']['route'] ? self::getItemLink($item['type'], $item['category']['route'], true) : '');
                }

                if ($item['type'] == 'software') {
                    if (isset($item['prices']) && $item['prices']) {
                        $item['price'] = self::calculatePrices($item['prices'], $data['currency_symbols'], $item['override_usrcurrency'], $item['type']);
                    }

                    $item['popular'] = false;
                    if (isset($item['options']['popular']) && $item['options']['popular']) {
                        $item['popular'] = true;
                    }

                    $item['buy_link'] = Controllers::$init->CRLink('order-steps', ['software', $item['id']]);
                    if (isset($item['options']['external_link']) && $item['options']['external_link'] != '') {
                        $item['buy_link'] = $item['options']['external_link'];
                    }
                    else if (isset($item['optionsl']['external_link']) && $item['optionsl']['external_link'] != '') {
                        $item['buy_link'] = $item['optionsl']['external_link'];
                    }
                }
                else if (($item['type'] == 'references') || $item['type'] == 'reference') {
                    $options = (isset($item['options']) && $item['options'] ? Utility::jdecode($item['options'], true) : []);
                    $item['category_name'] = (isset($item['category']['title']) && $item['category']['title'] ? $item['category']['title'] : '');
                    $item['category_route'] = (isset($item['category']['route']) && $item['category']['route'] ? self::getItemLink($item['type'], $item['category']['route'], true) : '');
                    $item['website'] = (isset($options['website']) ? $options['website'] : false);
                    $item['image'] = $item['cover_image'];
                }
                $output .= '<div class="col ' . $item['type'] . ' style-' . $data['content']->widget_style . ' ' . (isset($item['popular']) && $item['popular'] ? 'popular' : '') . '">';

                if ($data['carouselData']) {
                    $output .= '<div class="fon-content-carousel-item">';
                }

                include __DIR__ . DS . 'builder' . DS . 'page-styles' . DS . $item['type'] . DS . 'style_' . $data['content']->widget_style . '.php';

                if ($data['carouselData']) {
                    $output .= '</div>';
                }

                $output .= '</div>';
            }

            $output .= '</div>';
        }

        return $output;
    }

    public function getProductPackages(array $pageData, bool $isGsd = false, bool $forSelection = false): mixed
    {
        $output = '';
        $selectedCategory = [];
        $category = $pageData['items']['category'];
        $category2 = $pageData['items']['category2'];
        $showCategory = $pageData['items']['showCategory'];
        if (isset($pageData['items']) && $pageData['items']) {
            if (isset($pageData['widget_content']->show_cat_info) && $pageData['widget_content']->show_cat_info == 'yes') {
                $pageTitle = '';
                $pageDescription = '';

                if (isset($pageData['page'])) {
                    switch ($pageData['page']) {
                    case 'hosting':
                        $pageTitle = ___('constants/category-hosting/title');
                        $pageDescription = ___('constants/category-hosting/sub_title');
                        break;
                    case 'server':
                        $pageTitle = ___('constants/category-server/title');
                        $pageDescription = ___('constants/category-server/sub_title');
                        break;
                    case 'sms':
                        $pageTitle = ___('constants/category-sms/title');
                        $pageDescription = ___('constants/category-sms/sub_title');
                        break;
                    case 'software':
                        $pageTitle = ___('constants/category-software/title');
                        $pageDescription = ___('constants/category-software/sub_title');
                        break;
                    case 'special':
                        $pageTitle = ___('constants/category-software/title');
                        $pageDescription = ___('constants/category-software/sub_title');
                        break;
                    }
                }

                if (0 < $pageData['items']['showCategory']['id']) {
                    $pageTitle = $pageData['items']['showCategory']['title'];
                    $pageDescription = $pageData['items']['showCategory']['sub_title'];
                }

                $output .= '<div class="fon-section-title text-center">';
                $output .= '<h2 class="fon-section-title-heading">' . $pageTitle . '</h2>';
                $output .= '<p class="fon-section-title-subheading">' . $pageDescription . '</p>';
                $output .= '</div>';
            }
        }

        if (!$category2) {
            $list = $pageData['functions']['get_list']($showCategory['id'], $showCategory['kind']);
            $gsd = ['list' => $list, 'cat' => $showCategory['id']];
            $output .= $this->getPackagesList($list, $showCategory, $pageData);
        }

        $categories = $pageData['functions']['get_categories']($category['id'], $category['kind']);

        if ($categories) {
            $catSize = count($categories);
            $category_products = [];
            $categories_list = [];
            $selection = ($category2 ? $showCategory : false);
            $showCategoryList = true;
            if ($pageData['isWidget'] && isset($pageData['widget_content']->show_other_cats)) {
                if ($pageData['widget_content']->show_other_cats == 'no') {
                    $showCategoryList = false;
                }
            }
            $output .= '<ul class="product-group-tabs nav nav-pills mb-4 justify-content-center ' . (($catSize == 1) || !$showCategoryList ? 'd-none' : '') . '" role="tablist">';

            foreach ($categories as $k => $cat) {
                $list = $pageData['functions']['get_list']($cat['id'], $cat['kind']);
                $subs = $pageData['functions']['get_categories']($cat['id'], $cat['kind']);
                $category_products[$cat['id']] = $list;
                $categories_list[$cat['id']] = $subs;
                if (!$list && !$subs) {
                    continue;
                }

                $selected = false;

                if ($list) {
                    $cat['route'] = $pageData['functions']['category_tab_route']($cat['route']);
                }
                else {
                    $cat['route'] = Controllers::$init->CRLink('products', [$cat['route']]);
                }

                if ($category['id']) {
                    if (!$selection && $k == 0) {
                        $selection = $cat;
                    }
                    if ($selection && $cat['id'] == $selection['id']) {
                        $selected = true;
                    }
                }
                else if ($category2 && $category2['id'] == $cat['id']) {
                    $selected = true;
                    $selection = $cat;
                }
                else if (!$selection && $category_products[$cat['id']] && $k == 0) {
                    $selected = true;
                    $selection = $cat;
                }
                else if (!$selection && $k == 0) {
                    $category = $cat;
                    $selected = true;
                    $selection = $cat;
                }

                $categoryTarget = $cat['route'];
                if (isset($pageData['row']->row_section_id) && $pageData['row']->row_section_id) {
                    $categoryTarget .= '#' . $pageData['row']->row_section_id;
                }
                else if (isset($pageData['row']->text_class_id) && $pageData['row']->text_class_id) {
                    $categoryTarget .= '#' . $pageData['row']->text_class_id;
                }

                $output .= '<li class="nav-item"  role="presentation"><a href="' . $categoryTarget . '" class="nav-link ' . ($selected ? 'active' : '') . '">';
                if (isset($cat['options']['icon']) && $cat['options']['icon']) {
                    $output .= '<i class="' . $cat['options']['icon'] . '"></i> ';
                }
                else if (isset($cat['icon']) && $cat['icon']) {
                    $output .= '<img class="d-inline me-2" src="' . $cat['icon'] . '" width="25" height="25" alt="' . $cat['title'] . '"> ';
                }

                $output .= $cat['title'];
                $output .= '</a></li>';
            }

            $output .= '</ul>';
        }
        if (isset($selection) && $selection) {
            if (isset($category_products[$selection['id']])) {
                $list = $category_products[$selection['id']];
                $selectedCategory = ['category' => $selection, 'products' => $list];
                $gsd = ['list' => $list, 'cat' => $selection['id']];
                $output .= $this->getPackagesList($list, $selection, $pageData);

                if ($category['id']) {
                    $categories = (isset($categories_list[$selection['id']]) ? $categories_list[$selection['id']] : false);

                    if ($categories) {
                        if ($pageData['page'] != 'hosting') {
                            $subCatSize = count($categories);
                        }

                        if (isset($subCatSize)) {
                            $output .= '<div class="fon-accordion-widget style-4">';
                            $output .= '<div class="accordion" id="subCatAccordion">';
                        }

                        foreach ($categories as $cK => $cat) {
                            $list = $pageData['functions']['get_list']($cat['id'], $cat['kind']);
                            $catIcon = ($cat['icon'] || isset($cat['options']['icon']) && $cat['options']['icon'] ? true : false);

                            if ($list) {
                                $gsd = ['list' => $list, 'cat' => $cat['id']];

                                if (isset($subCatSize)) {
                                    $output .= '<div class="accordion-item ' . ($catIcon ? 'with-icon' : 'no-icon') . '">';
                                    $output .= '<h5 class="accordion-header">';
                                    $output .= '<button class="accordion-button ' . ($cK == 0 ? '' : 'collapsed') . '" type="button" data-bs-toggle="collapse" data-bs-target="#subcat-' . $cat['kind'] . '-' . $cat['id'] . '" aria-expanded="' . ($cK == 0 ? 'true' : 'false') . '" aria-controls="subcat-' . $cat['kind'] . '-' . $cat['id'] . '">';

                                    if ($catIcon) {
                                        $output .= '<span class="accordion-icon me-1">';

                                        if ($cat['icon']) {
                                            $output .= '<img class="d-inline" src="' . $cat['icon'] . '" width="25" height="25" alt="' . $cat['title'] . '"> ';
                                        }
                                        else if (isset($cat['options']['icon']) && $cat['options']['icon']) {
                                            $output .= '<i class="' . $cat['options']['icon'] . '"></i> ';
                                        }

                                        $output .= '</span>';
                                    }
                                    else {
                                        $output .= '<span class="accordion-icon me-1"><i class="fa-solid fa-server"></i></span>';
                                    }

                                    $output .= $cat['title'];
                                    $output .= '</button>';
                                    $output .= '</h5>';
                                    $output .= '<div id="subcat-' . $cat['kind'] . '-' . $cat['id'] . '" class="accordion-collapse collapse ' . ($cK == 0 ? 'show' : '') . '" data-bs-parent="#subCatAccordion">';
                                    $output .= '<div class="accordion-body">';
                                }

                                $output .= $this->getPackagesList($list, $cat, $pageData);

                                if (isset($subCatSize)) {
                                    $output .= '</div>';
                                    $output .= '</div>';
                                    $output .= '</div>';
                                }
                            }
                        }

                        if (isset($subCatSize)) {
                            $output .= '</div>';
                            $output .= '</div>';
                        }
                    }
                }
            }
        }

        if ($isGsd) {
            return $gsd ?? [];
        }
        else if ($forSelection) {
            return $selectedCategory;
        }
        else {
            return $output;
        }
    }

    public function getPackagesList(array $list, array $cat, array $widgetData = []): string
    {
        Helper::Load('Image');
        $widgetData['currency_symbols'] = self::getCurrencySymbols();
        if (!isset($widgetData['currency_map']) || !is_array($widgetData['currency_map']) || !$widgetData['currency_map']) {
            $widgetData['currency_map'] = [];

            foreach (Money::getCurrencies() as $cr) {
                $widgetData['currency_map'][$cr['id']] = $cr['code'];
            }
        }
        if (!isset($widgetData['percent_formatter']) || !($widgetData['percent_formatter'] instanceof NumberFormatter)) {
            $localeLangCode = (Language::selected() == 'tr' ? 'tr_TR' : 'en_US');
            $widgetData['percent_formatter'] = new NumberFormatter($localeLangCode, NumberFormatter::PERCENT);
        }

        $output = '';
        $showDetailLink = (isset($widgetData['widget_content']->show_detail_link) && $widgetData['widget_content']->show_detail_link == 'yes' ? true : false);
        $detailLinkType = (isset($widgetData['widget_content']->detail_link_type) ? $widgetData['widget_content']->detail_link_type : 'category');

        if (isset($widgetData['widget_content']->detail_link)) {
            $detailLinkUrl = (isset($widgetData['widget_content']->detail_link->{$this->lang}) ? $widgetData['widget_content']->detail_link->{$this->lang} : array_values((array) $widgetData['widget_content']->detail_link)[0] ?? '');
        }
        else {
            $detailLinkUrl = '';
        }

        if (isset($widgetData['widget_content']->detail_link_text)) {
            $detailLinkText = (isset($widgetData['widget_content']->detail_link_text->{$this->lang}) ? $widgetData['widget_content']->detail_link_text->{$this->lang} : array_values((array) $widgetData['widget_content']->detail_link_text)[0] ?? '');
        }
        else {
            $detailLinkText = '';
        }
        $detailLinkTarget = (isset($widgetData['widget_content']->detail_link_target) && $widgetData['widget_content']->detail_link_target ? $widgetData['widget_content']->detail_link_target : '_self');
        $widgetStyle = $widgetData['widgetStyle'] ?? (Config::get('theme/package_style') == '0' ? 'default' : Config::get('theme/package_style'));
        $showCoupon = $widgetData['showCoupon'] ?? false;
        $show_price_type = (isset($widgetData['widget_content']->show_price_type) && $widgetData['widget_content']->show_price_type ? $widgetData['widget_content']->show_price_type : 'default');

        if ($show_price_type == 'yes') {
            $show_price_type = 'month_year';
        }

        $price_calc = $widgetData['widget_content']->price_calc ?? 'default';
        $show_free_label = !isset($widgetData['widget_content']->show_free_label) || $widgetData['widget_content']->show_free_label == 'yes';
        $free_label_text = self::getFieldMultilingualText($widgetData['widget_content']->free_label_text ?? NULL, $this->lang, __('theme/is_free'));
        if ($show_free_label && empty($free_label_text)) {
            $free_label_text = __('theme/is_free');
        }
        $card_button_action_on_free = (isset($widgetData['widget_content']->card_button_action_on_free) && $widgetData['widget_content']->card_button_action_on_free ? $widgetData['widget_content']->card_button_action_on_free : 'default');
        $enable_custom_card_button_label = isset($widgetData['widget_content']->enable_custom_card_button_label) && $widgetData['widget_content']->enable_custom_card_button_label == 'yes';
        $custom_card_button_label = self::getFieldMultilingualText($widgetData['widget_content']->custom_card_button_label ?? NULL, $this->lang, __('website/index/add-basket-button'));
        $productType = (isset($widgetData['widget_name']) ? $widgetData['widget_name'] : $widgetData['page'] ?? 'default');
        $containerId = ($widgetData['widgetId'] ? $widgetData['widgetId'] . ($cat ? '-' . $cat['id'] : '') : 'product-package-container-' . ($cat ? '-' . $cat['id'] : ''));
        $widgetType = ($widgetData['isWidget'] && isset($widgetData['widget_content']->display) ? $widgetData['widget_content']->display : (isset($cat['options']['list_template']) && $cat['options']['list_template'] == 2 ? 'table' : 'box'));
        $showLocation = (isset($widgetData['widget_content']->show_location) && $widgetData['widget_content']->show_location == 'yes' ? true : false);
        $showFirstLocation = (isset($widgetData['widget_content']->first_location) && $widgetData['widget_content']->first_location == 'yes' ? true : false);
        $showFilters = (isset($widgetData['widget_content']->show_filters) && $widgetData['widget_content']->show_filters == 'yes' ? true : false);
        $enabledFilters = (isset($widgetData['widget_content']->enabled_filters) && $widgetData['widget_content']->enabled_filters ? $widgetData['widget_content']->enabled_filters : ['processor', 'ram', 'disk-space', 'location']);

        if ($showLocation) {
            $showFilters = true;
        }

        $locations = [];
        $periods = [];
        $serverOptions = [];
        if (($cat['kind'] == 'server') || $productType == 'server') {
            $this->addAsset('flags');
        }

        if ($list) {
            if ($widgetType == 'table') {
                if ($cat['kind'] == 'special') {
                    $columns = (isset($cat['options_lang']['columns']) ? $cat['options_lang']['columns'] : []);
                }

                $output .= '<div class="horizontal-pricing-table-container">';
                if ((($show_price_type != 'default') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) || $showFilters && $productType == 'server') {
                    $output .= '<div class="pricing-filter-container text-center mb-' . ($show_price_type == 'all_select' ? '5' : '3') . ' ' . $show_price_type . ' d-flex ' . ($showFilters && $productType == 'server' ? 'flex-column' : '') . ' align-items-center justify-content-center gap-3">';
                    if (($show_price_type == 'month_year') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) {
                        $output .= '<div class="pricing-period-swithcer mb-0" data-id="' . $containerId . '"><input id="monthly-package-price' . $containerId . '" class="monthly-package-price" type="radio" name="switch' . $containerId . '" checked="checked"><input id="yearly-package-price' . $containerId . '" class="yearly-package-price" type="radio" name="switch' . $containerId . '"><label class="monthly-package-price-label" for="monthly-package-price' . $containerId . '">' . ___('date/period-month') . '</label><label class="yearly-package-price-label" for="yearly-package-price' . $containerId . '">' . ___('date/period-year') . '</label><span class="package-prices-highlighter"></span></div>';
                    }
                    else if (($show_price_type == 'all_filter') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) {
                        foreach ($list as $sk => $sp) {
                            foreach ($sp['prices'] as $spkey => $spprice) {
                                $periods[$spkey] = $spprice['time'] . ' ' . ___('date/period-' . $spprice['period']);
                            }
                        }
                        if ($periods && 1 < count($periods)) {
                            $output .= '<div class="pricing-period-filter" data-id="#' . $containerId . '">';
                            $i = 0;

                            foreach ($periods as $spkey => $spperiod) {
                                $output .= '<input id="package-filter-price-' . $containerId . '-' . $spkey . '" class="package-filter-price-' . $spkey . '" type="radio" name="switch' . $containerId . '" ' . ($i == 0 ? 'checked="checked"' : '') . '>';
                                $output .= '<label class="package-filter-price-label-' . $spkey . '" for="package-filter-price-' . $containerId . '-' . $spkey . '">' . $spperiod . '</label>';
                                ++$i;
                            }

                            $output .= '</div>';
                        }
                    }
                    if ($showFilters && $productType == 'server') {
                        $this->addAsset('select2');
                        $output .= '<div class="server-filter-container row g-2 align-items-center justify-content-center">';

                        foreach ($list as $sk => $sp) {
                            if (isset($sp['options'])) {
                                $serverOptions[] = $sp['options'];
                            }
                        }
                        if ($serverOptions && 1 < count($serverOptions)) {
                            $serverProcessors = [];
                            $serverRams = [];
                            $serverDisks = [];
                            $serverBandwidths = [];
                            $serverRaids = [];

                            foreach ($serverOptions as $pkg) {
                                if (isset($pkg['processor'])) {
                                    $serverProcessors[] = $pkg['processor'];
                                }

                                if (isset($pkg['ram'])) {
                                    $serverRams[] = $pkg['ram'];
                                }

                                if (isset($pkg['disk-space'])) {
                                    $serverDisks[] = $pkg['disk-space'];
                                }

                                if (isset($pkg['bandwidth'])) {
                                    $serverBandwidths[] = $pkg['bandwidth'];
                                }

                                if (isset($pkg['raid'])) {
                                    $serverRaids[] = $pkg['raid'];
                                }
                            }

                            $serverProcessors = array_unique($serverProcessors);
                            $serverRams = array_unique($serverRams);
                            $serverDisks = array_unique($serverDisks);
                            $serverBandwidths = array_unique($serverBandwidths);
                            $serverRaids = array_unique($serverRaids);
                            sort($serverProcessors);
                            sort($serverRams);
                            sort($serverDisks);
                            sort($serverBandwidths);
                            sort($serverRaids);
                            $filtersCounts = 0;
                            if ($serverProcessors && 1 < count($serverProcessors) && in_array('processor', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-processor" class="form-select select-filter processor-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-cpu-label="' . __('website/products/server-list-processor') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-processor') . '</option>';

                                foreach ($serverProcessors as $serverProcessor) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverProcessor)) . '">' . htmlspecialchars($serverProcessor) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverRams && 1 < count($serverRams) && in_array('ram', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-ram" class="form-select select-filter ram-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-ram-label="' . __('website/products/server-list-ram') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-ram') . '</option>';

                                foreach ($serverRams as $serverRam) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverRam)) . '">' . htmlspecialchars($serverRam) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverDisks && 1 < count($serverDisks) && in_array('disk-space', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-disk" class="form-select select-filter disk-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-disk-label="' . __('website/products/server-list-disk') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-disk') . '</option>';

                                foreach ($serverDisks as $serverDisk) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverDisk)) . '">' . htmlspecialchars($serverDisk) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverBandwidths && 1 < count($serverBandwidths) && in_array('bandwidth', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-bandwidth" class="form-select select-filter bandwidth-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-bandwidth-label="' . __('website/products/server-list-bandwidth') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-bandwidth') . '</option>';

                                foreach ($serverBandwidths as $serverBandwidth) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverBandwidth)) . '">' . htmlspecialchars($serverBandwidth) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverRaids && 1 < count($serverRaids) && in_array('raid', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-raid" class="form-select select-filter raid-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-raid-label="' . __('website/products/server-list-raid') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-raid') . '</option>';

                                foreach ($serverRaids as $serverRaid) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverRaid)) . '">' . htmlspecialchars($serverRaid) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }

                            foreach ($list as $sk => $sp) {
                                if (isset($sp['options_lang']['location']) && !in_array($sp['options_lang']['location'], $locations)) {
                                    $locations[] = $sp['options_lang']['location'];
                                }
                            }
                            if ($locations && 1 < count($locations) && in_array('location', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-location" class="form-select location-filter select-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-location-label="' . __('theme/server_location') . '">';

                                if (!$showFirstLocation) {
                                    $output .= '<option value="">' . __('theme/server_location') . '</option>';
                                }

                                foreach ($locations as $location) {
                                    $country = $code = NULL;

                                    if (strpos($location, '-') !== false) {
                                        $parts = explode('-', $location);
                                        $country = $parts[0];
                                        $code = end($parts);
                                    }
                                    else {
                                        $country = $location;
                                        $code = NULL;
                                    }

                                    if (!empty($code)) {
                                        $code = mb_convert_encoding((string) $code, 'UTF-8', 'UTF-8');
                                    }

                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($location)) . '" data-flag="' . strtolower(htmlspecialchars($code)) . '">' . $country . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($filtersCounts && 2 <= $filtersCounts) {
                                $output .= '<div class="col btn-clear-filters" style="display: none;"><button type="button" class="btn btn-danger"><i class="fa-solid fa-times" title="' . __('theme/clear_filters') . '"></i></button></div>';
                            }
                        }

                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }

                $output .= '<div id="' . $containerId . '" class="fon-pricing-tables">';
                $productCards = [];

                foreach ($list as $k => $product) {
                    $product['order_image'] = Image::picture('product', $product['id'], 'order');
                    $opt = $product['options'];
                    $optl = $product['options_lang'];
                    $p_n = 0;
                    $prices = (!isset($product['prices']) ? [] : $product['prices']);
                    $productPrice = self::calculatePrices($prices, $widgetData['currency_symbols'], $product['override_usrcurrency'], $productType, $show_price_type, $price_calc);
                    $columnCount = (isset($columns) && $columns ? 3 + count($columns) : 8);

                    if (!isset($product['buy_link'])) {
                        if (isset($optl['external_link']) && $optl['external_link'] != '') {
                            $buy_link = $optl['external_link'];
                        }
                        else if (isset($product['optionsl']['external_link']) && $product['optionsl']['external_link'] != '') {
                            $buy_link = $product['optionsl']['external_link'];
                        }
                        else if (isset($product['options']['external_link']) && $product['options']['external_link'] != '') {
                            $buy_link = $product['options']['external_link'];
                        }
                        else {
                            $buy_link = Controllers::$init->CRLink('order-steps', [($cat ? $cat['kind'] : $product['type']), $product['id']]);
                        }
                    }
                    else if (isset($optl['external_link']) && $optl['external_link'] != '') {
                        $buy_link = $optl['external_link'];
                    }
                    else if (isset($product['optionsl']['external_link']) && $product['optionsl']['external_link'] != '') {
                        $buy_link = $product['optionsl']['external_link'];
                    }
                    else if (isset($product['options']['external_link']) && $product['options']['external_link'] != '') {
                        $buy_link = $product['options']['external_link'];
                    }
                    else {
                        $buy_link = $product['buy_link'];
                    }

                    $buy_button_name = __('website/index/add-basket-button');
                    if (isset($optl['buy_button_name']) && $optl['buy_button_name'] != '') {
                        $buy_button_name = $optl['buy_button_name'];
                    }
                    else if (isset($product['optionsl']['buy_button_name']) && $product['optionsl']['buy_button_name'] != '') {
                        $buy_button_name = $product['optionsl']['buy_button_name'];
                    }
                    else if (isset($product['options']['buy_button_name']) && $product['options']['buy_button_name'] != '') {
                        $buy_button_name = $product['options']['buy_button_name'];
                    }
                    else if ($enable_custom_card_button_label && !empty($custom_card_button_label)) {
                        $buy_button_name = $custom_card_button_label;
                    }

                    $columnWidth = 100 / $columnCount;

                    if (!empty($cat)) {
                        $catTitle = $cat['title'];
                        $pattern = '/^(http:\\/\\/|https:\\/\\/)/';

                        if (preg_match($pattern, $cat['route'])) {
                            $catRoute = $cat['route'];
                        }
                        else {
                            $catRoute = Controllers::$init->CRLink('products', [$cat['route']]);
                        }
                    }
                    else if (is_array($product['category']) && $product['category']) {
                        $catTitle = $product['category']['title'];
                        $pattern = '/^(http:\\/\\/|https:\\/\\/)/';

                        if (preg_match($pattern, $product['category']['route'])) {
                            $catRoute = $product['category']['route'];
                        }
                        else {
                            $catRoute = Controllers::$init->CRLink('products', [$product['category']['route']]);
                        }
                    }
                    else {
                        $catRoute = '';
                        $catTitle = '';
                    }
                    if (isset($widgetData['items']) && $widgetData['items'] && 0 < (int) $widgetData['items']['showCategory']['id']) {
                        $catRoute = '';
                    }
                    if (isset($product['features']) && $product['features']) {
                        $productFeatures = (self::isJSON($product['features']) ? Utility::jdecode($product['features'], true) : $product['features']);
                    }

                    ob_start();
                    include __DIR__ . DS . 'builder' . DS . 'product-styles' . DS . 'table.php';
                    $productCards[] = ob_get_clean();
                }

                if ($productCards) {
                    $output .= implode('', $productCards);
                }

                unset($productCards);
                $output .= '</div>';
                $output .= '</div>';
            }
            else {
                $verticalAlign = (isset($widgetData['widget_content']->vertical_align) && $widgetData['widget_content']->vertical_align ? 'align-items-' . $widgetData['widget_content']->vertical_align : '');
                $containerClass = 'row row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-3 justify-content-center pricing-style-' . $widgetStyle . ' ' . $verticalAlign;

                if ($widgetData['isWidget']) {
                    if (isset($widgetData['carouselData']) && $widgetData['carouselData']) {
                        $containerClass = 'fon-content-carousel fon-products-carousel pricing-style-' . $widgetStyle . ' ' . $widgetData['widget_name'] . '-carousel ' . $verticalAlign;
                    }
                    else {
                        $containerClass = 'row row-cols-' . $widgetData['widget_content']->column->xs . ' row-cols-sm-' . $widgetData['widget_content']->column->sm . ' row-cols-md-' . $widgetData['widget_content']->column->md . ' row-cols-lg-' . $widgetData['widget_content']->column->lg . ' row-cols-xl-' . $widgetData['widget_content']->column->xl . ' justify-content-center pricing-style-' . $widgetStyle . ' ' . $verticalAlign;
                    }
                }

                $containerId = $widgetData['widgetId'] . ($cat ? '-' . $cat['id'] : '');
                if ((($show_price_type != 'default') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) || $showFilters && $productType == 'server') {
                    $output .= '<div class="pricing-filter-container text-center mb-' . ($show_price_type == 'all_select' ? '5' : '3') . ' ' . $show_price_type . ' d-flex ' . ($showFilters && $productType == 'server' ? 'flex-column' : '') . ' align-items-center justify-content-center gap-3">';
                    if (($show_price_type == 'month_year') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) {
                        $output .= '<div class="pricing-period-swithcer mb-0" data-id="' . $containerId . '"><input id="monthly-package-price' . $containerId . '" class="monthly-package-price" type="radio" name="switch' . $containerId . '" checked="checked"><input id="yearly-package-price' . $containerId . '" class="yearly-package-price" type="radio" name="switch' . $containerId . '"><label class="monthly-package-price-label" for="monthly-package-price' . $containerId . '">' . ___('date/period-month') . '</label><label class="yearly-package-price-label" for="yearly-package-price' . $containerId . '">' . ___('date/period-year') . '</label><span class="package-prices-highlighter"></span></div>';
                    }
                    else if (($show_price_type == 'all_filter') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) {
                        foreach ($list as $sk => $sp) {
                            foreach ($sp['prices'] as $spkey => $spprice) {
                                $periods[$spkey] = $spprice['time'] . ' ' . ___('date/period-' . $spprice['period']);
                            }
                        }
                        if ($periods && 1 < count($periods)) {
                            $output .= '<div class="pricing-period-filter" data-id="#' . $containerId . '">';
                            $i = 0;

                            foreach ($periods as $spkey => $spperiod) {
                                $output .= '<input id="package-filter-price-' . $containerId . '-' . $spkey . '" class="package-filter-price-' . $spkey . '" type="radio" name="switch' . $containerId . '" ' . ($i == 0 ? 'checked="checked"' : '') . '>';
                                $output .= '<label class="package-filter-price-label-' . $spkey . '" for="package-filter-price-' . $containerId . '-' . $spkey . '">' . $spperiod . '</label>';
                                ++$i;
                            }

                            $output .= '</div>';
                        }
                    }
                    if ($showFilters && $productType == 'server') {
                        $this->addAsset('select2');
                        $output .= '<div class="server-filter-container row g-2 align-items-center justify-content-center">';

                        foreach ($list as $sk => $sp) {
                            if (isset($sp['options'])) {
                                $serverOptions[] = $sp['options'];
                            }
                        }
                        if ($serverOptions && 1 < count($serverOptions)) {
                            $serverProcessors = [];
                            $serverRams = [];
                            $serverDisks = [];
                            $serverBandwidths = [];
                            $serverRaids = [];

                            foreach ($serverOptions as $pkg) {
                                if (isset($pkg['processor'])) {
                                    $serverProcessors[] = $pkg['processor'];
                                }

                                if (isset($pkg['ram'])) {
                                    $serverRams[] = $pkg['ram'];
                                }

                                if (isset($pkg['disk-space'])) {
                                    $serverDisks[] = $pkg['disk-space'];
                                }

                                if (isset($pkg['bandwidth'])) {
                                    $serverBandwidths[] = $pkg['bandwidth'];
                                }

                                if (isset($pkg['raid'])) {
                                    $serverRaids[] = $pkg['raid'];
                                }
                            }

                            $serverProcessors = array_unique($serverProcessors);
                            $serverRams = array_unique($serverRams);
                            $serverDisks = array_unique($serverDisks);
                            $serverBandwidths = array_unique($serverBandwidths);
                            $serverRaids = array_unique($serverRaids);
                            sort($serverProcessors);
                            sort($serverRams);
                            sort($serverDisks);
                            sort($serverBandwidths);
                            sort($serverRaids);
                            $filtersCounts = 0;
                            if ($serverProcessors && 1 < count($serverProcessors) && in_array('processor', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-processor" class="form-select select-filter processor-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-cpu-label="' . __('website/products/server-list-processor') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-processor') . '</option>';

                                foreach ($serverProcessors as $serverProcessor) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverProcessor)) . '">' . htmlspecialchars($serverProcessor) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverRams && 1 < count($serverRams) && in_array('ram', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-ram" class="form-select select-filter ram-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-ram-label="' . __('website/products/server-list-ram') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-ram') . '</option>';

                                foreach ($serverRams as $serverRam) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverRam)) . '">' . htmlspecialchars($serverRam) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverDisks && 1 < count($serverDisks) && in_array('disk-space', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-disk" class="form-select select-filter disk-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-disk-label="' . __('website/products/server-list-disk') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-disk') . '</option>';

                                foreach ($serverDisks as $serverDisk) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverDisk)) . '">' . htmlspecialchars($serverDisk) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverBandwidths && 1 < count($serverBandwidths) && in_array('bandwidth', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-bandwidth" class="form-select select-filter bandwidth-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-bandwidth-label="' . __('website/products/server-list-bandwidth') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-bandwidth') . '</option>';

                                foreach ($serverBandwidths as $serverBandwidth) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverBandwidth)) . '">' . htmlspecialchars($serverBandwidth) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverRaids && 1 < count($serverRaids) && in_array('raid', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-raid" class="form-select select-filter raid-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-raid-label="' . __('website/products/server-list-raid') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-raid') . '</option>';

                                foreach ($serverRaids as $serverRaid) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverRaid)) . '">' . htmlspecialchars($serverRaid) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }

                            foreach ($list as $sk => $sp) {
                                if (isset($sp['options_lang']['location']) && !in_array($sp['options_lang']['location'], $locations)) {
                                    $locations[] = $sp['options_lang']['location'];
                                }
                            }
                            if ($locations && 1 < count($locations) && in_array('location', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-location" class="form-select location-filter select-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-location-label="' . __('theme/server_location') . '">';

                                if (!$showFirstLocation) {
                                    $output .= '<option value="">' . __('theme/server_location') . '</option>';
                                }

                                foreach ($locations as $location) {
                                    $country = $code = NULL;

                                    if (strpos($location, '-') !== false) {
                                        $parts = explode('-', $location);
                                        $country = $parts[0];
                                        $code = end($parts);
                                    }
                                    else {
                                        $country = $location;
                                        $code = NULL;
                                    }

                                    if (!empty($code)) {
                                        $code = mb_convert_encoding((string) $code, 'UTF-8', 'UTF-8');
                                    }

                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($location)) . '" data-flag="' . strtolower(htmlspecialchars($code)) . '">' . $country . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($filtersCounts && 2 <= $filtersCounts) {
                                $output .= '<div class="col btn-clear-filters" style="display: none;"><button type="button" class="btn btn-danger"><i class="fa-solid fa-times" title="' . __('theme/clear_filters') . '"></i></button></div>';
                            }
                        }

                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }

                $output .= '<div class="' . $containerClass . ' fon-pricing-tables" ' . ($widgetData['carouselData'] ?? '') . ' id="' . $containerId . '">';
                $productCards = [];

                foreach ($list as $product) {
                    $product['order_image'] = Image::picture('product', $product['id'], 'order');
                    $popular = false;
                    $prices = (!isset($product['prices']) ? [] : $product['prices']);
                    $productPrice = self::calculatePrices($prices, $widgetData['currency_symbols'], $product['override_usrcurrency'], $productType, $show_price_type, $price_calc);
                    $categoryCoupon = [];
                    $productCoupon = [];

                    if ($cat) {
                        if ($cat['kind'] == 'special') {
                            $categortKind = $this->getCategory($cat['id'], 'products', 'special');
                            $categoryKindId = $categortKind['kind_id'] ?? ($categortKind['kind_id'] ?? 0);

                            if ($categoryKindId) {
                                $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$categoryKindId . '/' . $cat['id']]);
                            }
                            else {
                                $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$cat['id']]);
                            }

                            $productCoupon = $this->couponCheck('product', $product['type'], [$categoryKindId, $product['id']]);
                        }
                        else {
                            $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$cat['id']]);
                            $productCoupon = $this->couponCheck('product', $product['type'], [$cat['id'], $product['id']]);
                        }
                    }
                    else if (isset($product['category'])) {
                        $categoryId = (is_array($product['category']) ? $product['category']['id'] : $product['category']);

                        if ($cat['kind'] == 'special') {
                            $categortKind = $this->getCategory($categoryId, 'products', 'special');
                            $categoryKindId = $categortKind['kind_id'] ?? ($categortKind['kind_id'] ?? 0);

                            if ($categoryKindId) {
                                $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$categoryKindId . '/' . $cat['id']]);
                            }
                            else {
                                $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$cat['id']]);
                            }

                            $productCoupon = $this->couponCheck('product', $product['type'], [$categoryKindId, $product['id']]);
                        }
                        else {
                            $categoryCoupon = $this->couponCheck('category', $product['type'], [$categoryId]);
                            $productCoupon = $this->couponCheck('product', $product['type'], [$categoryId, $product['id']]);
                        }
                    }
                    else {
                        $categoryCoupon = $this->couponCheck('category', $product['type'], [0, $product['id']]);
                        $productCoupon = $this->couponCheck('product', $product['type'], [0, $product['id']]);
                    }
                    if (isset($product['options']['popular']) && $product['options']['popular']) {
                        $popular = true;
                    }

                    $features_output = '';
                    $slogan = '';
                    $packageIcon = '';

                    if ($product['features']) {
                        $productFeatures = (self::isJSON($product['features']) ? Utility::jdecode($product['features'], true) : $product['features']);
                        if (is_array($productFeatures) && isset($productFeatures['slogan'])) {
                            $slogan = $productFeatures['slogan'];
                        }
                        if (is_array($productFeatures) && isset($productFeatures['icon'])) {
                            $packageIcon = $productFeatures['icon'];
                        }

                        if ($product['type'] == 'server') {
                            $serverFeatures = [];
                            $server['features'] = ['processor', 'ram', 'disk-space', 'bandwidth', 'raid'];

                            foreach ($server['features'] as $key) {
                                if (isset($product['options'][$key])) {

                                    $serverFeatures[] = ['name' => match ($key) {
                                        'processor' => __('website/products/server-list-processor'),
                                        'ram' => __('website/products/server-list-ram'),
                                        'disk-space' => __('website/products/server-list-disk'),
                                        'bandwidth' => __('website/products/server-list-bandwidth'),
                                        'raid' => __('website/products/server-list-raid')
                                    }, 'desc' => '', 'icon' => match ($key) {
                                        'processor' => 'fa-solid fa-microchip',
                                        'ram' => 'fa-solid fa-memory',
                                        'disk-space' => 'fa-solid fa-hard-drive',
                                        'bandwidth' => 'fa-solid fa-gauge-high',
                                        'raid' => 'fa-solid fa-server'
                                    }, 'type' => 'text', 'text' => $product['options'][$key], 'exist' => true];
                                }
                            }

                            if (isset($product['options_lang']['location'])) {
                                $country = '-';
                                $code = NULL;

                                if ($product['options_lang']['location'] != '') {
                                    if (strpos($product['options_lang']['location'], '-') !== false) {
                                        $parts = explode('-', $product['options_lang']['location']);
                                        $country = $parts[0];
                                        $code = end($parts);
                                    }
                                    else {
                                        $country = $product['options_lang']['location'];
                                        $code = NULL;
                                    }
                                }

                                $serverFeatures[] = ['name' => __('website/products/server-list-location'), 'desc' => '', 'icon' => 'fa-solid fa-location-dot', 'type' => 'text', 'text' => ($code ? '<i class="flag flag-xs rounded-1 flag-country-' . strtolower($code) . ' me-1"></i>' . $country : $country), 'exist' => true];
                            }
                            if ($serverFeatures && is_array($productFeatures) && isset($productFeatures['features'])) {
                                $productFeatures['features'] = array_merge($serverFeatures, $productFeatures['features']);
                            }
                        }
                    }
                    else if ($product['type'] == 'server') {
                        $product['features'] = ['processor', 'ram', 'disk-space', 'bandwidth', 'raid'];
                        $productFeatures = [
                            'count'    => 6,
                            'features' => []
                        ];
                        if (isset($product['options']) && is_array($product['options'])) {
                            foreach ($product['features'] as $key) {
                                if (isset($product['options'][$key])) {

                                    $productFeatures['features'][] = ['name' => match ($key) {
                                        processor => __('website/products/server-list-processor'),
                                        ram => __('website/products/server-list-ram'),
                                        disk-space => __('website/products/server-list-disk'),
                                        bandwidth => __('website/products/server-list-bandwidth'),
                                        raid => __('website/products/server-list-raid')
                                    }, 'desc' => '', 'icon' => match ($key) {
                                        processor => 'fa-solid fa-microchip',
                                        ram => 'fa-solid fa-memory',
                                        disk-space => 'fa-solid fa-hard-drive',
                                        bandwidth => 'fa-solid fa-gauge-high',
                                        raid => 'fa-solid fa-server'
                                    }, 'type' => 'text', 'text' => $product['options'][$key], 'exist' => true];
                                }
                            }
                        }

                        if (isset($product['options_lang']['location'])) {
                            $country = '-';
                            $code = NULL;

                            if ($product['options_lang']['location'] != '') {
                                if (strpos($product['options_lang']['location'], '-') !== false) {
                                    $parts = explode('-', $product['options_lang']['location']);
                                    $country = $parts[0];
                                    $code = end($parts);
                                }
                                else {
                                    $country = $product['options_lang']['location'];
                                    $code = NULL;
                                }
                            }

                            $productFeatures['features'][] = ['name' => __('website/products/server-list-location'), 'desc' => '', 'icon' => 'fa-solid fa-location-dot', 'type' => 'text', 'text' => ($code ? '<i class="flag flag-xs rounded-1 flag-country-' . strtolower($code) . ' me-1"></i>' . $country : $country), 'exist' => true];
                        }
                    }

                    $optl = $product['options_lang'];

                    if (!isset($product['buy_link'])) {
                        if (isset($product['options']['external_link']) && $product['options']['external_link'] != '') {
                            $buy_link = $product['options']['external_link'];
                        }
                        else if (isset($product['optionsl']['external_link']) && $product['optionsl']['external_link'] != '') {
                            $buy_link = $product['optionsl']['external_link'];
                        }
                        else if (isset($optl['external_link']) && $optl['external_link'] != '') {
                            $buy_link = $optl['external_link'];
                        }
                        else {
                            $buy_link = Controllers::$init->CRLink('order-steps', [($cat ? $cat['kind'] : $product['type']), $product['id']]);
                        }
                    }
                    else if (isset($optl['external_link']) && $optl['external_link'] != '') {
                        $buy_link = $optl['external_link'];
                    }
                    else if (isset($product['optionsl']['external_link']) && $product['optionsl']['external_link'] != '') {
                        $buy_link = $product['optionsl']['external_link'];
                    }
                    else if (isset($product['options']['external_link']) && $product['options']['external_link'] != '') {
                        $buy_link = $product['options']['external_link'];
                    }
                    else {
                        $buy_link = $product['buy_link'];
                    }

                    $buy_button_name = __('website/index/add-basket-button');
                    if (isset($optl['buy_button_name']) && $optl['buy_button_name'] != '') {
                        $buy_button_name = $optl['buy_button_name'];
                    }
                    else if (isset($product['optionsl']['buy_button_name']) && $product['optionsl']['buy_button_name'] != '') {
                        $buy_button_name = $product['optionsl']['buy_button_name'];
                    }
                    else if (isset($product['options']['buy_button_name']) && $product['options']['buy_button_name'] != '') {
                        $buy_button_name = $product['options']['buy_button_name'];
                    }
                    else if ($enable_custom_card_button_label && !empty($custom_card_button_label)) {
                        $buy_button_name = $custom_card_button_label;
                    }

                    if (!empty($cat)) {
                        $catTitle = $cat['title'];
                        $pattern = '/^(http:\\/\\/|https:\\/\\/)/';

                        if (preg_match($pattern, $cat['route'])) {
                            $catRoute = $cat['route'];
                        }
                        else if (isset($widgetData['items']) && $widgetData['items'] && 0 < (int) $widgetData['items']['showCategory']['id'] && $widgetData['items']['showCategory']['id'] == $cat['id']) {
                            $catRoute = '';
                        }
                        else {
                            $catRoute = Controllers::$init->CRLink('products', [$cat['route']]);
                        }
                    }
                    else if (is_array($product['category']) && $product['category']) {
                        $catTitle = $product['category']['title'];
                        $pattern = '/^(http:\\/\\/|https:\\/\\/)/';

                        if (preg_match($pattern, $product['category']['route'])) {
                            $catRoute = $product['category']['route'];
                        }
                        else {
                            $catRoute = Controllers::$init->CRLink('products', [$product['category']['route']]);
                        }
                    }
                    else if (isset($widgetData['items']) && $widgetData['items'] && 0 < (int) $widgetData['items']['showCategory']['id']) {
                        $catRoute = '';
                    }
                    else {
                        $catRoute = '';
                        $catTitle = '';
                    }

                    ob_start();
                    include __DIR__ . DS . 'builder' . DS . 'product-styles' . DS . 'grid_' . $widgetStyle . '.php';
                    $productCards[] = ob_get_clean();
                }

                if ($productCards) {
                    $output .= implode('', $productCards);
                }

                unset($productCards);
                $output .= '</div>';
            }
        }

        return $output;
    }

    public function getPageContent(string $pageType, array $sourcePage): array
    {
        $cacheActive = false;
        $themeCache = Config::get('theme/cache_pages');
        $globalCache = Config::get('general/cache');
        if ($themeCache && $globalCache) {
            $cacheActive = true;
        }

        if ($cacheActive) {
            $cache = Controllers::$cache;
            $cache->setCache('fonbuilderpages');
            $cache->eraseExpired();
        }

        if ($cacheActive) {
            if (!$cache->isCached('page_' . $pageType . '_' . $sourcePage['id'])) {
                $page = static::pageContentQuery($pageType, $sourcePage['id'] ?? 0);
                $cache->store('page_' . $pageType . '_' . $sourcePage['id'], $page, '86400');
            }
            else {
                $page = $cache->retrieve('page_' . $pageType . '_' . $sourcePage['id']);
            }
        }
        else {
            $page = static::pageContentQuery($pageType, $sourcePage['id'] ?? 0);
        }
        if (!$page && in_array($pageType, ['hosting' => true, 'server' => true, 'sms' => true, 'special' => true])) {
            if ($cacheActive) {
                if (!$cache->isCached('page_' . $pageType . '_' . $sourcePage['parent'])) {
                    $page = static::pageContentQuery($pageType, $sourcePage['parent'] ?? 0);
                    $cache->store('page_' . $pageType . '_' . $sourcePage['parent'], $page, '86400');
                }
                else {
                    $page = $cache->retrieve('page_' . $pageType . '_' . $sourcePage['parent']);
                }
            }
            else {
                $page = static::pageContentQuery($pageType, $sourcePage['parent'] ?? 0);
            }

            if (!$page) {
                if ($cacheActive) {
                    if (!$cache->isCached('page_' . $pageType . '_0')) {
                        $page = static::pageContentQuery($pageType, 0);
                        $cache->store('page_' . $pageType . '_0', $page, '86400');
                    }
                    else {
                        $page = $cache->retrieve('page_' . $pageType . '_0');
                    }
                }
                else {
                    $page = static::pageContentQuery($pageType, 0);
                }
            }
        }

        $this->addAsset('builder');
        if (isset($page['page_style']) && $page['page_style']) {
            $pageType = ($pageType != 'page' ? $pageType : 'page-detail-normal');
            $this->addStyle($pageType, $page['page_style']);
        }
        $page['page_content'] = (isset($page['page_content']) && $page['page_content'] ? Utility::jdecode(html_entity_decode($page['page_content'], ENT_QUOTES, 'UTF-8')) : []);
        $page['page_options'] = (isset($page['page_options']) && $page['page_options'] ? Utility::jdecode(html_entity_decode($page['page_options'], ENT_QUOTES, 'UTF-8'), true) : []);
        return $page;
    }

    private static function pageContentQuery(string $pageType, ?int $pageId = 0): array
    {
        if (is_null($pageId) || !$pageId) {
            $pageId = 0;
        }

        $page_query = Models::$init->db->select('*');
        $page_query->from('fonpagebuilder');

        if ($pageType == 'custom') {
            $page_query->where('id', '=', (string) $pageId, '&&');
        }
        else {
            $page_query->where('type_id', '=', (string) $pageId, '&&');
        }

        $page_query->where('status', '=', '1', '&&');
        $page_query->where('type', '=', (string) $pageType);
        $page = ($page_query->build() ? $page_query->getAssoc() : []);
        return $page;
    }

    private function getProducts(string $kind = '', array|string $id = [], int $limit = 10, bool $widget = false): array
    {
        $select = ['p.id', 'p.type', 'p.type_id', 'p.category', 'p.rank', 'p.override_usrcurrency', 'p.options', 'pl.options AS options_lang', 'pl.options AS optionsl', 'pl.title', 'pl.features', 'c.options AS c_options', 'cl.options AS cl_options', 'i.name AS cover_image', 'CASE' . "\n" . '                WHEN stock = "" THEN 1' . "\n" . '                WHEN stock IS NULL THEN 1' . "\n" . '                ELSE stock' . "\n" . '                END AS haveStock'];
        $query = Models::$init->db->select(implode(',', $select))->from('products AS p');
        $query->join('LEFT', 'products_lang AS pl', 'pl.owner_id=p.id AND pl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'categories_lang AS cl', 'cl.owner_id=p.category AND cl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'pictures AS i', 'i.owner=\'product\' AND i.owner_id=p.id AND i.reason=\'order\'');

        if ($kind != 'sms') {
            $query->join('LEFT', 'categories AS c', 'p.category=c.id');
            $query->join('LEFT', 'categories_lang AS cl', 'cl.owner_id=p.category AND cl.lang=\'' . $this->lang . '\'');

            if ($id != 'none') {
                $query->where('c.id', 'IS NOT NULL', '', '&&');
            }
        }

        $query->where('pl.id', 'IS NOT NULL', '', '&&');

        if ($widget) {
            if (is_array($id)) {
                $query->where('p.id', 'IN (' . implode(', ', $id) . ')', '', '&&');
            }
            else if ($id != 'none') {
                $query->where('(');
                $query->where('p.category', '=', $id, '||');
                $query->where('FIND_IN_SET(' . $id . ',p.categories)', '', '');
                $query->where(')', '', '', '&&');
            }
            else {
                $query->where('p.category', '=', 0, '&&');
            }
        }
        else {
            $query->where('(');
            $query->where('FIND_IN_SET(p.category,\'' . $id . '\')', '', '', '||');
            $query->where('FIND_IN_SET(p.categories,\'' . $id . '\')', '', '', '');
            $query->where(')', '', '', '&&');
        }

        if ($kind) {
            $query->where('p.type', '=', $kind, '&&');
        }

        $query->where('p.status', '=', 'active', '&&');
        $query->where('p.visibility', '=', 'visible');
        $query->order_by('p.rank ASC');

        if ($limit) {
            $query->limit($limit);
        }

        $results = ($query->build() ? $query->fetch_assoc() : []);

        if ($results) {
            foreach ($results as $key => $result) {
                $results[$key]['prices'] = self::getPrices('products', $result['id'], $kind);
                $results[$key]['options'] = ($results[$key]['options'] ? json_decode($results[$key]['options'], true) : []);
                $results[$key]['optionsl'] = ($results[$key]['optionsl'] ? json_decode($results[$key]['optionsl'], true) : []);
                $results[$key]['options_lang'] = ($results[$key]['options_lang'] ? json_decode($results[$key]['options_lang'], true) : []);
            }
        }

        return $results;
    }

    private function getPages(string $type = '', array|string $id = [], int $limit = 10): array
    {
        $select = ['p.id', 'p.type', 'p.category', 'p.ctime', 'pl.route', 'pl.title', 'pl.content', 'p.options', 'p.override_usrcurrency', 'pl.options AS optionsl', 'i.name AS cover_image'];
        $query = Models::$init->db->select(implode(',', $select))->from('pages AS p');
        $query->join('LEFT', 'pages_lang AS pl', 'pl.owner_id=p.id AND pl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'pictures AS i', 'i.owner=\'page_' . $type . '\' AND i.owner_id=p.id AND i.reason=\'cover\'');
        $query->where('pl.id', 'IS NOT NULL', '', '&&');

        if (is_array($id)) {
            $query->where('p.id', 'IN (' . implode(', ', $id) . ')', '', '&&');
        }
        else if ($id != 'none') {
            $query->where('(');
            $query->where('p.category', '=', $id, '||');
            $query->where('FIND_IN_SET(' . $id . ',p.categories)', '', '');
            $query->where(')', '', '', '&&');
        }

        $query->where('p.type', '=', $type, '&&');
        $query->where('p.status', '=', 'active', '&&');
        $query->where('p.visibility', '=', 'visible');

        if ($type == 'software') {
            if (!is_array($id) && $id != 'none') {
                $query->order_by('p.rank ASC');
            }
            else {
                $query->order_by('p.id DESC');
            }
        }
        else if ($type == 'references') {
            $query->order_by('p.rank ASC,p.id DESC');
        }
        else {
            $query->order_by('p.id DESC');
        }

        $query->limit($limit);
        $results = ($query->build() ? $query->fetch_assoc() : []);

        if ($results) {
            foreach ($results as $key => $result) {
                if ($type == 'software') {
                    $results[$key]['prices'] = self::getPrices('softwares', $result['id'], 'software');
                }

                $results[$key]['options'] = ($results[$key]['options'] ? json_decode($results[$key]['options'], true) : []);
                $results[$key]['optionsl'] = ($results[$key]['optionsl'] ? json_decode($results[$key]['optionsl'], true) : []);
            }
        }

        return $results;
    }

    private function getCategory(int $id, string $type = 'products', string $kind = ''): array
    {
        $select = ['c.id', 'c.parent', 'c.kind', 'c.kind_id', 'c.options', 'cl.title', 'cl.sub_title', 'cl.route', 'cl.options AS optionsl', 'cl.options AS options_lang', 'cl.faq AS faqs', 'i.name AS background_image', '(SELECT name FROM ' . $this->db_prefix . 'pictures WHERE owner=\'category\' AND owner_id=c.id AND reason=\'icon\') AS icon'];
        $query = Models::$init->db->select(implode(',', $select))->from('categories AS c');
        $query->join('LEFT', 'categories_lang AS cl', 'cl.owner_id=c.id AND cl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'pictures AS i', 'i.owner=\'category\' AND i.owner_id=c.id AND i.reason=\'background-image\'');
        $query->where('cl.id', 'IS NOT NULL', '', '&&');
        $query->where('c.type', '=', $type, '&&');

        if ($kind) {
            $query->where('c.kind', '=', $kind, '&&');
        }

        $query->where('c.status', '=', 'active', '&&');
        $query->where('c.visibility', '=', 'visible', '&&');
        $query->where('c.id', '=', $id);
        $result = ($query->build() ? $query->getAssoc() : []);

        if ($result) {
            $result['options'] = ($result['options'] ? json_decode($result['options'], true) : []);
            $result['optionsl'] = ($result['optionsl'] ? json_decode($result['optionsl'], true) : []);
            $result['options_lang'] = ($result['options_lang'] ? json_decode($result['options_lang'], true) : []);
        }

        return $result;
    }

    private function getCategories(int $parent = 0, string $type = 'products', string $kind = ''): array
    {
        $select = ['c.id', 'c.parent', 'c.kind', 'c.options', 'cl.title', 'cl.sub_title', 'cl.route', 'cl.options AS optionsl', 'cl.options AS options_lang', 'i.name AS background_image', '(SELECT name FROM ' . $this->db_prefix . 'pictures WHERE owner=\'category\' AND owner_id=c.id AND reason=\'cover\') AS icon'];
        $query = Models::$init->db->select(implode(',', $select))->from('categories AS c');
        $query->join('LEFT', 'categories_lang AS cl', 'cl.owner_id=c.id AND cl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'pictures AS i', 'i.owner=\'category\' AND i.owner_id=c.id AND i.reason=\'background-image\'');
        $query->where('cl.id', 'IS NOT NULL', '', '&&');
        $query->where('c.type', '=', $type, '&&');

        if ($kind) {
            $query->where('c.kind', '=', $kind, '&&');
        }

        $query->where('c.status', '=', 'active', '&&');
        $query->where('c.visibility', '=', 'visible', '&&');
        if (($kind === 'server') && 0 < $parent) {
            $query->where('(SELECT id FROM ' . $this->db_prefix . 'products WHERE (category=c.id OR FIND_IN_SET(c.id,categories) OR FIND_IN_SET(category,(SELECT GROUP_CONCAT(id) FROM categories WHERE parent=c.id))) AND status=\'active\' AND visibility=\'visible\' LIMIT 1)', '', '', '&&');
        }

        $query->where('c.parent', '=', $parent);
        $results = ($query->build() ? $query->fetch_assoc() : []);

        if ($results) {
            foreach ($results as $key => $result) {
                $results[$key]['options'] = ($result['options'] ? json_decode($result['options'], true) : []);
                $results[$key]['optionsl'] = ($result['optionsl'] ? json_decode($result['optionsl'], true) : []);
                $results[$key]['options_lang'] = ($result['options_lang'] ? json_decode($result['options_lang'], true) : []);
            }
        }

        return $results;
    }

    private static function getPrices(string $owner, int $owner_id, string $kind): array
    {
        $type = ($kind == 'sms' ? 'sale' : 'periodicals');
        $query = Models::$init->db->select('*')->from('prices');
        $query->where('type', '=', $type, '&&');
        $query->where('owner', '=', $owner, '&&');
        $query->where('owner_id', '=', $owner_id);
        $query->order_by('rank ASC');
        return ($query->build() ? $query->fetch_assoc() : []);
    }

    public function couponCheck(string $type = 'category', string $kind = 'hosting', array $ids = []): array
    {
        $sth = Models::$init->db->select('*')->from('coupons');

        if ($type == 'category') {
            $categoryId = $ids[0];
            $sth->where('(');
            $sth->where('pservices', 'LIKE', '%category/' . $kind . '/' . $categoryId . '%', '||');

            if ($kind == 'special') {
                if (strpos($categoryId, '/') !== false) {
                    $parts = explode('/', $categoryId);
                    $groupId = $parts[0];
                    $sth->where('pservices', 'LIKE', '%allOf/' . $kind . '/' . $groupId . '%');
                }
                else {
                    $sth->where('pservices', 'LIKE', '%allOf/' . $kind . '/' . $categoryId . '%');
                }
            }
            else {
                $sth->where('pservices', 'LIKE', '%allOf/' . $kind . '%');
            }

            $sth->where(')', '', '', '&&');
        }
        else {
            $product_id = implode('/', $ids);
            $sth->where('pservices', 'LIKE', '%product/' . $kind . '/' . $product_id . '%', '&&');
        }

        $sth->where('status', '=', 'active', '&&');
        $sth->where('duedate', '>=', DateManager::Now());
        $sth->limit('1');
        $result = ($sth->build() ? $sth->getAssoc() : []);
        $coupon = [];
        $periodTypes = ['hour' => $this->language['coupon_hour'], 'day' => $this->language['coupon_day'], 'week' => $this->language['coupon_week'], 'month' => $this->language['coupon_month'], 'year' => $this->language['coupon_year']];

        if ($result) {
            if ($result['type'] == 'percentage') {
                $coupon['discount'] = '%' . $result['rate'];
            }
            else {
                $coupon['discount'] = Money::formatter_symbol($result['amount'], $result['currency']);
            }

            $periodtext = '';
            if ($result['period_type'] && $result['period_type'] != 'none') {
                if (1 < $result['period_duration']) {
                    $periodtext .= $result['period_duration'];
                }

                $periodtext .= $periodTypes[$result['period_type']];
                $coupon['period'] = $periodtext;
            }

            $coupon['code'] = $result['code'];
            $coupon['merge'] = $result['use_merge'];
        }

        return $coupon;
    }

    private function getTestimonials(int $limit = 4): array
    {
        $lang = Language::selected();
        $query = Models::$init->db->select('t1.*,t2.message,t3.name AS image')->from('customer_feedbacks AS t1');
        $query->join('LEFT', 'customer_feedbacks_lang AS t2', 't2.owner_id=t1.id AND t2.lang=\'' . $lang . '\'');
        $query->join('LEFT', 'pictures AS t3', 't1.id=t3.owner_id AND t3.owner=\'customer_feedback\' AND t3.reason=\'image\'');
        $query->where('t2.id', 'IS NOT NULL', '', '&&');
        $query->where('status', '=', 'approved');
        $query->order_by('t1.rank ASC,id DESC');
        $query->limit($limit);
        return ($query->build() ? $query->fetch_assoc() : []);
    }

    private static function getTldPrices(int $tldId = 0, string $priceType = 'register', string $order = 'p.rank ASC', int $limit = 0): array
    {
        $query = Models::$init->db->select()->from('prices AS p');
        $query->where('p.owner', '=', 'tld', '&&');
        $query->where('p.type', '=', $priceType, '&&');

        if ($tldId) {
            $query->where('p.owner_id', '=', $tldId);
        }

        $query->order_by($order);

        if ($limit) {
            $query->limit($limit);
        }

        $price = ($query->build() ? $query->getAssoc() : []);
        return $price;
    }

    public static function getCurrencySymbols(string $code = ''): array
    {
        $currency_symbols = [];

        foreach (Money::getCurrencies() as $currency) {
            if ($code) {
                if ($code == 'format') {
                    $currency_symbols[$currency['code']] = $currency['format'];
                }
                else {
                    $currency_symbols[] = $currency['code'];
                }
            }
            else {
                $symbol = ($currency['prefix'] != '' ? trim($currency['prefix']) : trim($currency['suffix']));

                if (!$symbol) {
                    $symbol = $currency['code'];
                }

                $currency_symbols[] = $symbol;
            }
        }

        return $currency_symbols;
    }

    public static function currencySymbol(string $amount, array $currency_symbols): string
    {
        $symbol_position = '';
        $symbol = '';
        $split_amount = explode(' ', $amount);

        if (in_array(current($split_amount), $currency_symbols)) {
            $symbol_position = 'left';
            $symbol = current($split_amount);
            array_shift($split_amount);
            $amount = implode(' ', $split_amount);
        }
        else if (in_array(end($split_amount), $currency_symbols)) {
            $symbol_position = 'right';
            $symbol = end($split_amount);
            array_pop($split_amount);
            $amount = implode(' ', $split_amount);
        }

        if ($symbol_position == 'left') {
            $priceFormatted = '<sup class="currency-symbol ' . $symbol_position . '">' . $symbol . '</sup>' . $amount;
        }
        else {
            $priceFormatted = $amount . '<sup class="currency-symbol ' . $symbol_position . '">' . $symbol . '</sup>';
        }

        return $priceFormatted;
    }

    public static function calculatePrices(array $prices, array $currency_symbols, int|bool $override_usrcurrency = 0, string $type = 'default', string|bool $show_price_type = '', string $price_calc = 'default'): array
    {
        if ((($show_price_type == 'yes') || $show_price_type == 'month_year') && in_array($type, ['hosting' => true, 'server' => true, 'special' => true])) {
            $productPrices = self::getPriceInfo($prices, $price_calc);
            if ($productPrices && 0 < $productPrices['price']) {
                $cid = $productPrices['cid'];
                $amount = $productPrices['price'];
                $price = Money::formatter_symbol($amount, $cid, !$override_usrcurrency);
                $priceRaw = self::parsePrice($price);
                $price = self::currencySymbol($price, $currency_symbols);
                $amountYearly = $productPrices['yearly'];
                $priceYearly = Money::formatter_symbol($amountYearly, $cid, !$override_usrcurrency);
                $priceRawYearly = self::parsePrice($priceYearly);
                $priceYearly = self::currencySymbol($priceYearly, $currency_symbols);
                $special = false;
                $specialYearly = false;
                if ($productPrices['discount'] && 0 < (float) $productPrices['discount']) {
                    $specialAmount = (float) $amount / (1 - ((float) $productPrices['discount'] / 100));
                    $special = Money::formatter_symbol($specialAmount, $cid, !$override_usrcurrency);
                    $specialRaw = self::parsePrice($special);
                    $special = self::currencySymbol($special, $currency_symbols);
                    $specialAmountYearly = (float) $amountYearly / (1 - ((float) $productPrices['discount'] / 100));
                    $specialYearly = Money::formatter_symbol($specialAmountYearly, $cid, !$override_usrcurrency);
                    $specialRawYearly = self::parsePrice($specialYearly);
                    $specialYearly = self::currencySymbol($specialYearly, $currency_symbols);
                }
            }

            if ($productPrices) {
                $period = View::period(1, $productPrices['period']);
            }

            $productPrice = ['price' => $price ?? '', 'priceRaw' => $priceRaw ?? '', 'special' => $special ?? '', 'specialRaw' => $specialRaw ?? '', 'priceY' => $priceYearly ?? '', 'priceRawY' => $priceRawYearly ?? '', 'specialY' => $specialYearly ?? '', 'specialRawY' => $specialRawYearly ?? '', 'period' => $period ?? '', 'discount' => (float) $productPrices['discount'], 'prices' => $prices, 'prices_periodically' => $productPrices, 'show_monthly' => $show_price_type, 'monthly_calc' => $price_calc, 'show_price_type' => $show_price_type, 'time' => $productPrices['time']];
            return $productPrice;
        }
        else if ((($show_price_type == 'all_filter') || $show_price_type == 'all_select') && in_array($type, ['hosting' => true, 'server' => true, 'special' => true])) {
            $productPrices = ['price_list' => $prices, 'price_type' => $show_price_type];

            if ($prices) {
                foreach ($prices as $price) {
                    if (0 < $price['amount']) {
                        $cid = $price['cid'];
                        $amount = $price['amount'];
                        $productPrice = Money::formatter_symbol($amount, $cid, !$override_usrcurrency);
                        $productPriceRaw = self::parsePrice($productPrice);
                        $productPrice = self::currencySymbol($productPrice, $currency_symbols);
                        $productSpecial = false;
                        if ($price['discount'] && 0 < (float) $price['discount']) {
                            $productSpecialAmount = (float) $amount / (1 - ((float) $price['discount'] / 100));
                            $productSpecial = Money::formatter_symbol($productSpecialAmount, $cid, !$override_usrcurrency);
                            $productSpecialRaw = self::parsePrice($productSpecial);
                            $productSpecial = self::currencySymbol($productSpecial, $currency_symbols);
                        }
                    }

                    $period = View::period($price['time'], $price['period']);
                    $productPrices['filter_prices'][] = ['price' => $productPrice ?? '', 'priceRaw' => $productPriceRaw ?? '', 'special' => $productSpecial ?? '', 'specialRaw' => $productSpecialRaw ?? '', 'period' => $period ?? '', 'period_key' => $price['time'] . '_' . $price['period'], 'discount' => (float) $price['discount'], 'show_price_type' => $show_price_type, 'time' => $price['time']];
                }
            }

            return $productPrices;
        }
        if (isset($prices[0]) && 0 < $prices[0]['amount']) {
            $cid = $prices[0]['cid'];
            $amount = $prices[0]['amount'];
            $price = Money::formatter_symbol($amount, $cid, !$override_usrcurrency);
            $priceRaw = self::parsePrice($price);
            $price = self::currencySymbol($price, $currency_symbols);
            $special = false;
            if ($prices[0]['discount'] && 0 < (float) $prices[0]['discount']) {
                $specialAmount = (float) $amount / (1 - ((float) $prices[0]['discount'] / 100));
                $special = Money::formatter_symbol($specialAmount, $cid, !$override_usrcurrency);
                $specialRaw = self::parsePrice($special);
                $special = self::currencySymbol($special, $currency_symbols);
            }
        }

        if (isset($prices[0])) {
            $period = View::period($prices[0]['time'], $prices[0]['period']);
        }

        $productPrice = ['price' => $price ?? '', 'priceRaw' => $priceRaw ?? '', 'special' => $special ?? '', 'specialRaw' => $specialRaw ?? '', 'period' => $period ?? '', 'discount' => (float) $prices[0]['discount'], 'show_monthly' => 0, 'monthly_calc' => 'default', 'show_price_type' => $show_price_type, 'time' => $prices[0]['time']];
        return $productPrice;
    }

    private static function getPriceInfo(array $prices, string $price_calc = 'default'): array
    {
        $nonePrices = [];
        $monthlyPrices = [];
        $yearlyPrices = [];
        $otherPrices = [];

        foreach ($prices as $price) {
            switch ($price['period']) {
            case 'none':
                $nonePrices[] = $price;
                break;
            case 'month':
                $monthlyPrices[] = $price;
                break;
            case 'year':
                $yearlyPrices[] = $price;
                break;
            default:
                $otherPrices[] = $price;
                break;
            }
        }

        $priceInfo = ['price' => '', 'monthly' => '', 'yearly' => '', 'period' => (isset($prices[0]['period']) ? $prices[0]['period'] : ''), 'cid' => (isset($prices[0]['cid']) ? $prices[0]['cid'] : ''), 'discount' => (isset($prices[0]['discount']) ? $prices[0]['discount'] : ''), 'time' => (isset($prices[0]['time']) ? $prices[0]['time'] : '')];

        if (!empty($nonePrices)) {
            $priceInfo['price'] = $nonePrices[0]['amount'];
            $priceInfo['monthly'] = $nonePrices[0]['amount'];
            $priceInfo['yearly'] = $nonePrices[0]['amount'];
            $priceInfo['period'] = $nonePrices[0]['period'];
            $priceInfo['cid'] = $nonePrices[0]['cid'];
            $priceInfo['discount'] = $nonePrices[0]['discount'];
            $priceInfo['time'] = $nonePrices[0]['time'];
            return $priceInfo;
        }
        if (empty($monthlyPrices) && empty($yearlyPrices)) {
            $firstPrice = $prices[0];
            $priceInfo['price'] = $firstPrice['amount'];
            $priceInfo['monthly'] = $firstPrice['amount'];
            $priceInfo['yearly'] = $firstPrice['amount'];
            $priceInfo['period'] = $nonePrices[0]['period'];
            $priceInfo['cid'] = $firstPrice['cid'];
            $priceInfo['discount'] = $firstPrice['discount'];
            $priceInfo['time'] = $firstPrice['time'];
            return $priceInfo;
        }

        if (!empty($monthlyPrices)) {
            $monthlyPrice = array_filter($monthlyPrices, function($p) {
                return $p['time'] == 1;
            });

            if (!empty($monthlyPrice)) {
                $monthlyPrice = reset($monthlyPrice);
                $priceInfo['monthly'] = $monthlyPrice['amount'];
                $priceInfo['period'] = 'month';
                $priceInfo['cid'] = $monthlyPrice['cid'];
                $priceInfo['discount'] = $monthlyPrice['discount'];
                $priceInfo['time'] = $monthlyPrice['time'];
            }
            else {
                usort($monthlyPrices, function($a, $b) {
                    return $a['time'] <=> $b['time'];
                });
                $monthlyPrice = $monthlyPrices[0];
                $priceInfo['monthly'] = number_format($monthlyPrice['amount'] / $monthlyPrice['time'], 5, '.', '');
                $priceInfo['period'] = 'month';
                $priceInfo['cid'] = $monthlyPrice['cid'];
                $priceInfo['discount'] = $monthlyPrice['discount'];
                $priceInfo['time'] = $monthlyPrice['time'];
            }
        }

        if (!empty($yearlyPrices)) {
            if ($price_calc === 'heighest_year') {
                usort($yearlyPrices, function($a, $b) {
                    return $b['time'] <=> $a['time'];
                });
            }
            else {
                usort($yearlyPrices, function($a, $b) {
                    return $a['time'] <=> $b['time'];
                });
            }

            $yearlyPrice = $yearlyPrices[0];
            $yearlyPrice = $yearlyPrices[0];
            $priceInfo['yearly'] = number_format($yearlyPrice['amount'] / $yearlyPrice['time'], 5, '.', '');
            $priceInfo['cid'] = $yearlyPrice['cid'];
            $priceInfo['discount'] = $yearlyPrice['discount'];
            $priceInfo['time'] = $yearlyPrice['time'];
        }
        if (empty($priceInfo['monthly']) && !empty($priceInfo['yearly'])) {
            if ($price_calc === 'heighest_year') {
                usort($yearlyPrices, function($a, $b) {
                    return $b['time'] <=> $a['time'];
                });
            }
            else {
                usort($yearlyPrices, function($a, $b) {
                    return $a['time'] <=> $b['time'];
                });
            }

            $yearlyPrice = $yearlyPrices[0];
            $priceInfo['monthly'] = number_format($yearlyPrice['amount'] / ($yearlyPrice['time'] * 12), 5, '.', '');
            $priceInfo['period'] = 'month';
            $priceInfo['time'] = $yearlyPrice['time'];
        }
        if (empty($priceInfo['yearly']) && !empty($priceInfo['monthly'])) {
            $priceInfo['yearly'] = number_format($priceInfo['monthly'] * 12, 5, '.', '');
            $priceInfo['period'] = 'month';
            $priceInfo['time'] = 1;
        }

        $priceInfo['price'] = $priceInfo['monthly'] ?: $priceInfo['yearly'];
        return $priceInfo;
    }

    public static function parsePrice(string $price): string
    {
        $priceKey = $parsedPrice = $price;
        $priceCode = '';
        $prefix = '';
        $suffix = '';

        foreach (Money::getCurrencies() as $currency) {
            $price = str_ireplace([$currency['prefix'], $currency['suffix'], $currency['code']], '', $price);
            if (($currency['prefix'] && strpos($priceKey, $currency['prefix']) !== false) || $currency['suffix'] && strpos($priceKey, $currency['suffix']) !== false || $currency['code'] && strpos($priceKey, $currency['code']) !== false) {
                $priceCode = $currency['code'];
                $prefix = $currency['prefix'];
                $suffix = $currency['suffix'];
            }

            $search = [$currency['prefix'], $currency['suffix'], $currency['code']];
            $price = str_replace($search, '', $price);
            $price = trim($price);
            $parsedPrice = Money::parseDecimal($price);
        }

        $returnPrice = '';

        if ($prefix) {
            $returnPrice .= '<sup class="currency-symbol">' . trim($prefix) . '</sup>';
        }

        if (is_array($parsedPrice)) {
            $returnPrice .= $parsedPrice['amount'];

            if (0 < (int) $parsedPrice['decimal']) {
                $returnPrice .= '<sup class="currency-decimal">.' . $parsedPrice['decimal'] . '</sup>';
            }
        }
        else {
            $returnPrice .= $parsedPrice;
        }

        if ($suffix) {
            $returnPrice .= '<sup class="currency-symbol">' . trim($suffix) . '</sup>';
        }
        if (!$prefix && !$suffix) {
            $returnPrice .= '<sup class="currency-symbol"> ' . $priceCode . '</sup>';
        }

        return $returnPrice;
    }

    public static function isJSON(mixed $value): bool
    {
        if (!is_string($value) || trim($value) === '') {
            return false;
        }

        json_decode($value);
        return json_last_error() === JSON_ERROR_NONE;
    }

    public static function unicodeFix(string $string): string
    {
        return preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function(array $matches): string {
            return mb_chr(hexdec($matches[1]), 'UTF-8');
        }, $string);
    }

    private function getItemLink(string $type, string $route, bool $cat = false): string
    {
        $link = '';

        switch ($type) {
        case 'articles':
            $link = ($cat ? Controllers::$init->CRLink('articles_category', [$route]) : Controllers::$init->CRLink('articles_detail', [$route]));
            break;
        case 'references':
            $link = ($cat ? Controllers::$init->CRLink('references_category', [$route]) : Controllers::$init->CRLink('references_detail', [$route]));
            break;
        case 'software':
            $link = ($cat ? Controllers::$init->CRLink('softwares_cat', [$route]) : Controllers::$init->CRLink('software_detail', [$route]));
            break;
        case 'news':
            $link = ($cat ? '' : Controllers::$init->CRLink('news_detail', [$route]));
            break;
        }

        return $link;
    }

    private function checkLink(string $input_link, bool $checkInternal = false): string|bool
    {
        $isInternal = false;

        if (preg_match('/^(http:\\/\\/|https:\\/\\/)/', $input_link)) {
            $fixed_link = $input_link;
        }
        else if (preg_match('/^(www\\.)?[\\w\\-]+\\.[a-z]{2,6}(\\/[\\w\\-\\/]*)?$/i', $input_link)) {
            $fixed_link = 'https://' . $input_link;
        }
        else {
            $isInternal = true;
            $fixed_link = APP_URI . '/' . ltrim($input_link, '/');
        }

        return ($checkInternal ? $isInternal : $fixed_link);
    }

    public function getAssets(): array
    {
        return $this->assets;
    }

    public function getStyles(string $page): array|string
    {
        return $this->styles[$page] ?? '';
    }

    public function getScripts(string $page, string $position = 'footer'): string
    {
        $scripts = '';
        if (isset($this->scripts[$position]) && isset($this->scripts[$position][$page])) {
            $scripts .= $this->scripts[$position][$page];
        }

        return $scripts;
    }

    public function getHeaderCodes(string $page): string
    {
        if (isset($this->headerCodes[$page])) {
            return $this->headerCodes[$page];
        }

        return '';
    }

    public function registerWidgetAsset(mixed $asset): void
    {
        $this->addAsset($asset);
    }

    public function registerWidgetStyle(string $page, string $style): void
    {
        if (($page == '') || $style == '') {
            return;
        }

        $this->addStyle($page, $style);
    }

    public function registerWidgetScript(string $position, string $page, string $script): void
    {
        if (($position == '') || $page == '' || $script == '') {
            return;
        }

        $this->addScript($position, $page, $script);
    }

    private function addAsset(mixed $asset): void
    {
        if (is_array($asset)) {
            foreach ($asset as $item) {
                if (!in_array($item, $this->assets)) {
                    $this->assets[] = $item;
                }
            }
        }
        else if (!in_array($asset, $this->assets)) {
            $this->assets[] = $asset;
        }
    }

    private function addScript(string $position, string $page, string $script): void
    {
        if (isset($this->scripts[$position][$page])) {
            $this->scripts[$position][$page] .= $script;
        }
        else {
            $this->scripts[$position][$page] = $script;
        }
    }

    private function addStyle(string $page, string $style): void
    {
        if (isset($this->styles[$page])) {
            $this->styles[$page] .= $style;
        }
        else {
            $this->styles[$page] = $style;
        }
    }

    private function addHeaderCode(string $page, string $code): void
    {
        if (isset($this->headerCodes[$page])) {
            $this->headerCodes[$page] .= $code;
        }
        else {
            $this->headerCodes[$page] = $code;
        }
    }

    private function parseButtons(array $items, string|int $moduleId, array $pageData, object|string|null $align = NULL): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $buttonCount = count($items);
        $style = '';

        if (!is_object($align)) {
            $rawAlign = (is_string($align) ? trim($align) : '');

            $textAlign = match ($rawAlign) {
                left => 'start',
                center => 'center',
                right => 'end',
                default => 'center'
            };
            $align = new stdClass();
            $align->xs = $align->sm = $align->md = $align->lg = $align->xl = $textAlign;
        }

        $hasBlockButton = false;

        foreach ($items as $item) {
            if (isset($item->block_button) && $item->block_button === 'yes') {
                $hasBlockButton = true;
            }
            else {
            }
        }

        $alignClass = ($align ? 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl : 'text-center');
        $groupClass = (1 < $buttonCount ? 'fon-widget-button-group' : 'fon-button-wrapper');
        $gridClass = ($hasBlockButton ? ' d-grid' : '');
        $output = '';
        $output .= '<div class="' . $alignClass . ' ' . $groupClass . $gridClass . '">';

        foreach ($items as $key => $item) {
            $button_style = ($item->button_style ?? '') ?: 'default';
            $button_custom_style = ($item->button_custom_style ?? '') ?: 'default';
            $button_type = ($item->button_type ?? '') ?: 'default';
            $button_shape = ($item->button_shape ?? '') ?: 'round';
            $button_size = (isset($item->button_size) && $item->button_size !== 'default' ? $item->button_size : '');
            $button_rel = $item->button_rel ?? [];
            $scroll_button = isset($item->scroll_button) && $item->scroll_button === 'yes';
            $button_target = ($item->button_target ?? '') ?: '_self';
            $class = '';
            $class .= (($button_style === 'outline') && $button_type !== 'custom' ? '-' . $button_style : '');
            $class .= ($button_type ? '-' . $button_type : '');
            $class .= (($button_style === 'gradient') && $button_type !== 'custom' ? ' btn-style-' . $button_style : '');
            $class .= ($button_size ? ' btn-' . $button_size : '');
            $class .= ($button_shape !== 'round' ? ' btn-' . $button_shape : '');
            $rawLink = $item->button_link ?? '';
            $link = (isset($rawLink->{$this->lang}) && $rawLink->{$this->lang} ? $rawLink->{$this->lang} : array_values((array) $rawLink)[0] ?? '');
            $isInternal = false;

            if ($link) {
                $isInternal = self::checkLink($link, true);
            }

            $attribs = 'id="btn-' . ($moduleId . $key) . '"';
            if (!empty($button_rel) && !$scroll_button) {
                $attribs .= ' rel="' . implode(' ', (array) $button_rel) . '"';
            }

            $attribs .= ' target="' . $button_target . '"';
            if ($scroll_button && $isInternal) {
                $class .= ' fon-scroll-button';
            }

            $rawText = $item->button_text ?? '';
            $text = (isset($rawText->{$this->lang}) && $rawText->{$this->lang} ? $rawText->{$this->lang} : array_values((array) $rawText)[0] ?? '');
            $show_icon = isset($item->show_button_icon) && $item->show_button_icon === 'yes';
            $icon = $item->button_icon ?? '';
            $icon_position = $item->button_icon_position ?? 'left';
            if ($show_icon && $icon) {
                $iconTag = '<i class="' . $icon . '" aria-hidden="true"></i>';
                $text = ($icon_position === 'left' ? $iconTag . ' ' . $text : $text . ' ' . $iconTag);
            }

            $hrefTag = (!empty($link) ? 'href="' . $link . '"' : '');
            $output .= '<a ' . $hrefTag . ' ' . $attribs . ' class="btn btn' . $class . '">' . $text . '</a>';
            $fontProperties = (isset($item->button_font) ? self::parseFontProperties($item->button_font) : '');
            if (($button_type === 'custom') || $button_type === 'link' || $button_size === 'custom' || $fontProperties) {
                $style .= '#btn-' . ($moduleId . $key) . '{';
                $style .= $fontProperties;
                if (($button_type === 'custom') || $button_type === 'link') {
                    $style .= (isset($item->button_color_normal) && $item->button_color_normal ? '--bs-btn-color:' . $item->button_color_normal . ';' : '');
                    $style .= (isset($item->button_color_hover) && $item->button_color_hover ? '--bs-btn-hover-color:' . $item->button_color_hover . ';' : '');
                }

                if ($button_type === 'custom') {
                    if ($button_custom_style === 'default') {
                        if (isset($item->button_background_normal) && $item->button_background_normal) {
                            $style .= '--bs-btn-bg:' . $item->button_background_normal . ';';
                        }
                        if (isset($item->button_background_hover) && $item->button_background_hover) {
                            $style .= '--bs-btn-hover-bg:' . $item->button_background_hover . ';';
                        }
                        if (isset($item->button_border_normal) && $item->button_border_normal) {
                            $style .= '--bs-btn-border-color:' . $item->button_border_normal . ';';
                        }
                        else if (isset($item->button_background_normal)) {
                            $style .= '--bs-btn-border-color:' . $item->button_background_normal . ';';
                        }
                        if (isset($item->button_border_hover) && $item->button_border_hover) {
                            $style .= '--bs-btn-hover-border-color:' . $item->button_border_hover . ';';
                        }
                        else if (isset($item->button_background_hover)) {
                            $style .= '--bs-btn-hover-border-color:' . $item->button_background_hover . ';';
                        }
                    }
                    else if ($button_custom_style === 'gradient') {
                        $style .= '--bs-btn-border-width:0;';
                        $style .= (isset($item->button_gradient_normal) && $item->button_gradient_normal ? self::parseGradient($item->button_gradient_normal, 'normal') : '');
                        $style .= (isset($item->button_gradient_hover) && $item->button_gradient_hover ? self::parseGradient($item->button_gradient_hover, 'hover') : '');
                        $style .= 'background-image: var(--bs-normal-gradient);';
                    }
                }

                $style .= '}';
                if (($button_type === 'custom') && $button_custom_style === 'gradient') {
                    $style .= '#btn-' . ($moduleId . $key) . ':hover{';
                    if (isset($item->button_gradient_hover) && $item->button_gradient_hover) {
                        $style .= 'background-image: var(--bs-hover-gradient);';
                    }

                    $style .= '}';
                }
                if (($button_size === 'custom') && isset($item->button_padding)) {
                    $responsiveItems = [];
                    $responsiveItems['#btn-' . $moduleId . $key][] = ['type' => 'padding', 'value' => $item->button_padding];
                    $style .= self::parseResponsiveItems($responsiveItems);
                }
            }
        }

        $output .= '</div>';

        if ($style) {
            $pageName = $pageData['page'] ?? 'index';
            $this->addStyle($pageName, $style);
        }

        return $output;
    }

    private function parseButton(object $item, string|int $moduleId, array $pageData, array $btnProperties = []): string
    {
        $style = '';
        $buttonId = $btnProperties['id'] ?? ('fon-btn-' . $moduleId . '-' . bin2hex(random_bytes(3)));
        $attribs = ' id="' . $buttonId . '"';
        $button_style = ($item->button_style ?? '') ?: 'default';
        $button_custom_style = ($item->button_custom_style ?? '') ?: 'default';
        $button_type = ($item->button_type ?? '') ?: 'default';
        $button_shape = ($item->button_shape ?? '') ?: 'rounded';
        $button_size = (isset($item->button_size) && $item->button_size !== 'default' ? $item->button_size : '');
        $link = $item->button_link ?? '';

        if (is_object($link)) {
            $link = (isset($link->{$this->lang}) && $link->{$this->lang} ? $link->{$this->lang} : array_values((array) $link)[0] ?? '');
        }

        $rawText = $item->button_text ?? '';
        $text = (isset($rawText->{$this->lang}) && $rawText->{$this->lang} ? $rawText->{$this->lang} : array_values((array) $rawText)[0] ?? '');
        $show_icon = isset($item->show_button_icon) && $item->show_button_icon === 'yes';
        $icon = $item->button_icon ?? '';
        $icon_position = $item->button_icon_position ?? 'left';
        $scrollButton = isset($item->scroll_button) && $item->scroll_button === 'yes';
        $button_rel = (array) ($item->button_rel ?? []);
        $button_target = ($item->button_target ?? '') ?: '_self';
        $class = '';
        $class .= (($button_style === 'outline') && $button_type !== 'custom' ? '-' . $button_style : '');
        $class .= ($button_type ? '-' . $button_type : '');
        $class .= (($button_style === 'gradient') && $button_type !== 'custom' ? ' btn-style-' . $button_style : '');
        $class .= ($button_size && $button_size !== 'custom' ? ' btn-' . $button_size : '');
        $class .= ($button_shape !== 'round' ? ' btn-' . $button_shape : '');
        $class .= (isset($item->block_button) && $item->block_button === 'yes' ? ' btn-block' : '');

        if (!empty($btnProperties)) {
            if (!empty($btnProperties['class'])) {
                $class .= ' ' . $btnProperties['class'];
            }
            if (isset($btnProperties['disabled']) && $btnProperties['disabled'] === 'true') {
                $class .= ' disabled';
            }

            if (!empty($btnProperties['attributes'])) {
                $attribs .= ' ' . $btnProperties['attributes'];
            }
        }

        $isInternal = false;
        if ($link && is_string($link)) {
            $isInternal = self::checkLink($link, true);
        }
        if ($scrollButton && $isInternal) {
            $class .= '  fon-scroll-button';
        }

        if (!empty($button_rel)) {
            $attribs .= ' rel="' . implode(' ', $button_rel) . '"';
        }

        if ($button_target) {
            $attribs .= ' target="' . $button_target . '"';
        }
        if ($show_icon && $icon) {
            $iconTag = '<i class="' . $icon . '" aria-hidden="true"></i>';
            $text = ($icon_position === 'left' ? $iconTag . ' ' . $text : $text . ' ' . $iconTag);
        }
        if (!empty($btnProperties['data']) && is_array($btnProperties['data'])) {
            foreach ($btnProperties['data'] as $bdk => $btnData) {
                $formattedData = (is_array($btnData) ? htmlspecialchars(json_encode($btnData, JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8') : htmlspecialchars((string) $btnData, ENT_QUOTES, 'UTF-8'));
                $attribs .= ' data-' . $bdk . '=\'' . $formattedData . '\'';
            }
        }

        $output = '';

        if (!empty($btnProperties['is_btn'])) {
            $output .= '<button class="btn btn' . $class . '" ' . $attribs;

            if (!empty($btnProperties['type'])) {
                $output .= ' type="' . $btnProperties['type'] . '"';
            }
            if (isset($btnProperties['disabled']) && $btnProperties['disabled']) {
                $output .= ' aria-disabled="' . $btnProperties['disabled'] . '"';
            }

            $output .= '>' . $text . '</button>';
        }
        else {
            $hrefTag = (!empty($link) ? 'href="' . $link . '"' : '');
            $output .= '<a ' . $hrefTag . ' ' . $attribs . ' class="btn btn' . $class . '">' . $text . '</a>';
        }
        $fontProperties = (isset($item->button_font) && $item->button_font ? self::parseFontProperties($item->button_font) : '');
        if (($button_type === 'custom') || $button_type === 'link' || $button_size === 'custom' || $fontProperties) {
            $style .= '#' . $buttonId . '{';
            $style .= $fontProperties;
            if (($button_type === 'custom') || $button_type === 'link') {
                $style .= (isset($item->button_color_normal) && $item->button_color_normal ? '--bs-btn-color:' . $item->button_color_normal . ';' : '');
                $style .= (isset($item->button_color_hover) && $item->button_color_hover ? '--bs-btn-hover-color:' . $item->button_color_hover . ';' : '');
            }

            if ($button_type === 'custom') {
                if ($button_custom_style === 'default') {
                    if (isset($item->button_background_normal) && $item->button_background_normal) {
                        $style .= '--bs-btn-bg:' . $item->button_background_normal . ';';
                    }
                    if (isset($item->button_background_hover) && $item->button_background_hover) {
                        $style .= '--bs-btn-hover-bg:' . $item->button_background_hover . ';';
                    }
                    if (isset($item->button_border_normal) && $item->button_border_normal) {
                        $style .= '--bs-btn-border-color:' . $item->button_border_normal . ';';
                    }
                    else if (isset($item->button_background_normal)) {
                        $style .= '--bs-btn-border-color:' . $item->button_background_normal . ';';
                    }
                    if (isset($item->button_border_hover) && $item->button_border_hover) {
                        $style .= '--bs-btn-hover-border-color:' . $item->button_border_hover . ';';
                    }
                    else if (isset($item->button_background_hover)) {
                        $style .= '--bs-btn-hover-border-color:' . $item->button_background_hover . ';';
                    }
                }
                else if ($button_custom_style === 'gradient') {
                    $style .= '--bs-btn-border-width:0;';
                    $style .= (isset($item->button_gradient_normal) && $item->button_gradient_normal ? self::parseGradient($item->button_gradient_normal, 'normal') : '');
                    $style .= (isset($item->button_gradient_hover) && $item->button_gradient_hover ? self::parseGradient($item->button_gradient_hover, 'hover') : '');
                    $style .= 'background-image: var(--bs-normal-gradient);';
                }
            }

            $style .= '}';
            if (($button_type === 'custom') && $button_custom_style === 'gradient') {
                $style .= '#' . $buttonId . ':hover{';
                if (isset($item->button_gradient_hover) && $item->button_gradient_hover) {
                    $style .= 'background-image: var(--bs-hover-gradient);';
                }

                $style .= '}';
            }
            if (($button_size === 'custom') && isset($item->button_padding)) {
                $responsiveItems = [];
                $responsiveItems['#' . $buttonId][] = ['type' => 'padding', 'value' => $item->button_padding];
                $style .= self::parseResponsiveItems($responsiveItems);
            }
        }

        if ($style) {
            $pageName = $pageData['page'] ?? 'index';
            $this->addStyle($pageName, $style);
        }

        return $output;
    }

    public static function parseFontProperties(object $properties, bool $align = true): string
    {
        $style = [];

        if ($properties) {
            foreach ($properties as $key => $property) {
                if (is_object($property)) {
                    if ($key == 'font-style') {
                        if (isset($property->underline) && $property->underline) {
                            $style[] = 'text-decoration:underline!important';
                        }
                        if (isset($property->italic) && $property->italic) {
                            $style[] = 'font-style:italic!important';
                        }
                        if (isset($property->uppercase) && $property->uppercase) {
                            $style[] = 'text-transform:uppercase!important';
                        }
                    }
                    else if ($key == 'text-align') {
                        if ($align) {
                            if (isset($property->left) && $property->left) {
                                $style[] = $key . ':left!important';
                            }
                            else if (isset($property->center) && $property->center) {
                                $style[] = $key . ':center!important';
                            }
                            else if (isset($property->right) && $property->right) {
                                $style[] = $key . ':right!important';
                            }
                        }
                    }
                    else if (isset($property->value) && $property->value) {
                        $style[] = $key . ':' . $property->value . $property->unit . '!important';
                    }
                }
                else if ($property) {
                    $style[] = $key . ':' . $property . '!important';
                }
            }
        }

        if ($style) {
            return implode(';', $style) . ';';
        }

        return '';
    }

    public static function parseResponsiveItems(array $responsiveItems = [], string $widgetId = ''): string
    {
        $style = '';
        $breakpoints = [];
        $mediaQueries = ['xxl' => '1400px', 'xl' => '1200px', 'lg' => '1199.98px', 'md' => '991.98px', 'sm' => '767.98px', 'xs' => '575.98px'];

        if ($responsiveItems) {
            foreach ($responsiveItems as $selector => $items) {
                foreach ($items as $item) {
                    $itemBreakPoints = $item['value'] ?? (object) [];

                    if ($itemBreakPoints) {
                        foreach ($itemBreakPoints as $itemBreakPoint => $breakPointvalue) {
                            if (($breakPointvalue !== '') && $breakPointvalue !== null) {
                                $breakpoints[$itemBreakPoint][$selector][] = ['type' => $item['type'], 'unit' => $item['unit'] ?? '', 'value' => $breakPointvalue];
                            }
                        }
                    }
                }
            }
        }

        if ($breakpoints) {
            $largestKey = NULL;

            if (isset($breakpoints['xxl'])) {
                $largestKey = 'xxl';
            }
            else if (isset($breakpoints['xl'])) {
                $largestKey = 'xl';
            }
            if ($largestKey && isset($breakpoints[$largestKey])) {
                foreach ($breakpoints[$largestKey] as $selector => $breakpointItem) {
                    if ($widgetId) {
                        $style .= '#' . $widgetId . ' ';
                    }

                    $style .= $selector . '{';

                    foreach ($breakpointItem as $item) {
                        $style .= $item['type'] . ': ' . $item['value'] . $item['unit'] . ';';
                    }

                    $style .= '}';
                }
            }

            $orderedBreakpoints = array_keys($mediaQueries);

            foreach ($orderedBreakpoints as $breakpoint) {
                if ($breakpoint == $largestKey) {
                    continue;
                }

                if (isset($breakpoints[$breakpoint])) {
                    $style .= '@media(max-width:' . $mediaQueries[$breakpoint] . '){';

                    foreach ($breakpoints[$breakpoint] as $selector => $breakpointItem) {
                        if ($widgetId) {
                            $style .= '#' . $widgetId . ' ';
                        }

                        $style .= $selector . '{';

                        foreach ($breakpointItem as $item) {
                            $style .= $item['type'] . ': ' . $item['value'] . $item['unit'] . ';';
                        }

                        $style .= '}';
                    }

                    $style .= '}';
                }
            }
        }

        return $style;
    }

    private static function parseGradient(object $gradient, string $bs_gradient = ''): string
    {
        $style = '';
        if (!empty($gradient->sc) && !empty($gradient->ec)) {
            $gradientType = $gradient->gt ?? 'linear';
            $startColorPos = $gradient->scp ?? 0;
            $endColorPos = $gradient->ecp ?? 100;
            $style .= ($bs_gradient !== '' ? '--bs-' . $bs_gradient . '-gradient: ' : 'background-image: ');

            $gradientDetails = match ($gradientType) {
                linear => ($gradient->lga ?? 180) . 'deg',
                radial => 'at ' . str_replace('_', ' ', $gradient->rga ?? 'center'),
                default => '180deg'
            };
            $style .= $gradientType . '-gradient(' . $gradientDetails . ', ' . $gradient->sc . ' ' . $startColorPos . '%, ' . $gradient->ec . ' ' . $endColorPos . '%);';
        }

        return $style;
    }

    public static function validateAndNormalizeColor(string $colorInput): array
    {
        if (preg_match('/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6,8})$/', $colorInput)) {
            if ((strlen($colorInput) === 4) || strlen($colorInput) === 5) {
                $hexColor = '#' . str_repeat($colorInput[1], 2) . str_repeat($colorInput[2], 2) . str_repeat($colorInput[3], 2);

                if (strlen($colorInput) === 5) {
                    $hexColor .= str_repeat($colorInput[4], 2);
                }
            }
            else {
                $hexColor = strtolower($colorInput);
            }

            if (strlen($hexColor) === 9) {
                $alpha = substr($hexColor, -2);
                $hexColor = substr($hexColor, 0, 7);
            }
            else {
                $alpha = 'FF';
            }

            return ['color' => self::hexToRgb($hexColor), 'alpha' => round(hexdec($alpha) / 255, 2)];
        }

        if (preg_match('/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*([\\d.]+))?\\)/i', $colorInput, $matches)) {
            $red = (int) $matches[1];
            $green = (int) $matches[2];
            $blue = (int) $matches[3];
            $alpha = (isset($matches[4]) ? (float) $matches[4] : 1);
            return ['color' => $red . ',' . $green . ',' . $blue, 'alpha' => strval($alpha)];
        }

        if (preg_match('/hsla?\\((\\d+),\\s*(\\d+)%?,\\s*(\\d+)%?(?:,\\s*([\\d.]+))?\\)/i', $colorInput, $matches)) {
            $hue = (int) $matches[1];
            $saturation = (int) $matches[2];
            $lightness = (int) $matches[3];
            $alpha = (isset($matches[4]) ? (float) $matches[4] : 1);
            $rgb = self::hslToRgb([$hue, $saturation, $lightness]);
            return ['color' => $rgb, 'alpha' => $alpha];
        }

        return ['color' => $colorInput, 'alpha' => 1];
    }

    public static function hexToRgb(string $hexColor): string
    {
        $hexColor = ltrim($hexColor, '#');
        $r = hexdec(substr($hexColor, 0, 2));
        $g = hexdec(substr($hexColor, 2, 2));
        $b = hexdec(substr($hexColor, 4, 2));
        return $r . ',' . $g . ',' . $b;
    }

    public static function rgbToHex(array $rgbArray): string
    {
        list($r, $g, $b) = $rgbArray;
        return sprintf('#%02X%02X%02X', $r, $g, $b);
    }

    public static function rgbToHsl(array $rgbArray): string
    {
        list($r, $g, $b) = $rgbArray;
        $r /= 255;
        $g /= 255;
        $b /= 255;
        $max = max($r, $g, $b);
        $min = min($r, $g, $b);
        $h = $s = $l = ($max + $min) / 2;

        if ($max === $min) {
            $h = $s = 0;
        }
        else {
            $d = $max - $min;
            $s = (0.5 < $l ? $d / (2 - $max - $min) : $d / ($max + $min));

            switch ($max) {
            case $r:
                $h = (($g - $b) / $d) + ($g < $b ? 6 : 0);
                break;
            case $g:
                $h = (($b - $r) / $d) + 2;
                break;
            default:
                $h = (($r - $g) / $d) + 4;
                break;
            }

            $h /= 6;
        }

        $h = round($h * 360, 2);
        $s = round($s * 100, 2);
        $l = round($l * 100, 2);
        return $h . ' ' . $s . '%';
    }

    public static function hslToRgb(array $hslArray): string
    {
        list($h, $s, $l) = $hslArray;
        $h /= 360;
        $s /= 100;
        $l /= 100;

        if ($s == 0) {
            $r = $g = $b = $l;
        }
        else {
            $func = function($p, $q, $t) {
                if ($t < 0) {
                    $t += 1;
                }

                if (1 < $t) {
                    $t -= 1;
                }

                if ($t < 0.16666666666666666) {
                    return $p + ($t * (($q - $p) * 6));
                }

                if ($t < 0.5) {
                    return $q;
                }

                if ($t < 0.6666666666666666) {
                    return $p + (($q - $p) * (0.6666666666666666 - $t) * 6);
                }

                return $p;
            };
            $q = ($l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($l * $s));
            $p = ($l * 2) - $q;
            $r = $func($p, $q, $h + 0.3333333333333333);
            $g = $func($p, $q, $h);
            $b = $func($p, $q, $h - 0.3333333333333333);
        }

        $r = (int) round($r * 255);
        $g = (int) round($g * 255);
        $b = (int) round($b * 255);
        return $r . ',' . $g . ',' . $b;
    }

    public static function hexToHsl(string $hexColor): string
    {
        $rgbArray = self::hexToRgb($hexColor);
        $rgbArray = explode(',', $rgbArray);
        return self::rgbToHsl($rgbArray);
    }

    public static function hslToHex(array $hslArray): string
    {
        $rgbArray = self::hslToRgb($hslArray);
        $rgbArray = explode(',', $rgbArray);
        return self::rgbToHex($rgbArray);
    }

    public static function assetLinkDetermine(string $src, bool $isImage = true): string
    {
        if (strpos($src, 'http://') !== false || strpos($src, 'https://') !== false) {
            if (defined('APP_URI') && strpos($src, APP_URI) === false) {
                return $src;
            }
        }

        $path = parse_url($src, PHP_URL_PATH);

        if ($path) {
            $src = $path;
        }

        $cleanSrc = ltrim($src, '/');

        if (empty($cleanSrc)) {
            return '';
        }

        $asset_src = '';

        if ($isImage) {
            $info = pathinfo($cleanSrc);
            $directory = $info['dirname'];

            if ($directory === '.') {
                $directory = '';
            }

            if ($directory) {
                $directory = trim($directory, '/') . '/';
            }
            else {
                $directory = '/';
            }

            $asset_src = Utility::image_link_determiner($info['basename'], $directory);
        }
        else {
            $asset_src = '/' . $cleanSrc;
        }

        return $asset_src;
    }

    public function get_css_url(): string
    {
        return Controllers::$init->CRLink('templates/website/' . $this->name . '/css/fononline.min.css', false, 'none') . '?version=' . License::get_version();
    }

    public static function getHeaderMenu(array $list = [], bool $children = false, array $opt = [], int $childCount = 0): string
    {
        $menuFontSize = Config::get('theme/fonts/menu/size');
        $menuFontWeight = Config::get('theme/fonts/menu/weight');
        $mobile = isset($opt['mobile']) && $opt['mobile'];
        $output = '';

        if ($children) {
            $output .= '<ul class="' . (0 < $childCount ? 'child-' . $childCount : '') . ' ' . ($mobile ? 'inner' : '') . '">';
        }

        $i = $childCount;

        foreach ($list as $menu) {
            $mega = false;
            $tag = false;

            if (isset($menu['extra']['mega']['header_' . $opt['header_type']])) {
                $mega = $menu['extra']['mega']['header_' . $opt['header_type']];
            }

            if (isset($menu['extra']['tag'])) {
                $tag = $menu['extra']['tag'];
            }

            $menuClass = '';
            $menuWidth = '';

            if (!$children) {
                if ($mega) {
                    $menuClass = 'megamenuli';

                    if ($menu['icon']) {
                        if (!str_contains($menu['icon'], 'fa-')) {
                            if ($menu['icon'] == 'full') {
                                $menuClass .= ' full-width';
                            }
                            else {
                                $menuClass .= ' position-relative';
                                $menuWidth = $menu['icon'] . 'px';
                            }
                        }
                    }
                }
                else if ($menu['children']) {
                    $menuClass = 'flatmenuli';
                }
            }
            if ($menu['children'] || $mega) {
                $menu['link'] = 'javascript:void 0;';
            }
            $output .= '<li class="nav-item ' . $menuClass . ' ' . ($menu['children'] || $mega ? 'has-child' : '') . '">';
            $output .= '<a href="' . $menu['link'] . '" ' . ($menu['target'] ? ' target="_blank"' : '') . ' class="nav-link ' . ($mobile && $menu['children'] || $mega ? 'toggle' : '') . '" style="font-size:' . $menuFontSize . 'px;font-weight:' . $menuFontWeight . ';">';

            if ($tag) {
                $output .= '<span class="menu_tag" ' . ($tag['color'] != '' ? 'style="--menu-tag-background:' . $tag['color'] . ';"' : '') . '>' . self::getPriceHolders($tag['name']) . '</span>';
            }

            $output .= (isset($opt['span']) ? '<span class="menu-title">' : '');
            $output .= ($menu['icon'] && !$menuWidth ? '<i class="' . $menu['icon'] . '" aria-hidden="true"></i> ' : '');
            $output .= $menu['title'];
            $output .= (isset($opt['span']) ? '</span>' : '');
            $output .= ($menu['children'] || $mega ? ' <i class="fa-solid fa-angle-down"></i>' : '');
            $output .= '</a>';
            if (!$children && $mega) {
                $output .= '<div class="megamenu-container ' . ($mobile ? 'inner' : '') . ' ' . ($menuWidth ? 'has-width' : '') . '" ' . ($menuWidth ? 'style="width:' . $menuWidth . '; left:50%; transform:translateX(-' . ($menu['icon'] / 2) . 'px)"' : '') . '>';
                $output .= '<div class="container">';
                $output .= '<ul class="megamenu p-0">';
                $mega = self::getPriceHolders($mega);
                $output .= Utility::text_replace($mega, ['{SITE_URL}' => APP_URI . '/', '{TEMPLATE_URL}' => $opt['template_address']]);
                $output .= '</ul>';
                $output .= '</div>';
                $output .= '</div>';
            }
            if ($menu['children'] && !$mega) {
                ++$i;
                $output .= static::getHeaderMenu($menu['children'], true, $opt, $i);
            }

            $output .= '</li>' . PHP_EOL;
        }

        $output .= ($children ? '</ul>' . PHP_EOL : '');
        return $output;
    }

    public static function getFooterMenu(array $list = [], bool $children = false, array $opt = []): string
    {
        $footerMenu = '';

        foreach ($list as $menu) {
            if (!$children) {
                $footerMenu .= '<div class="col footer-menu-links">';
                $footerMenu .= '<div class="dropdown">';
            }
            else {
                $footerMenu .= '<li>';
            }

            $footerMenu .= '<a';
            $footerMenu .= (!$children ? ' class="dropdown-toggle" role="button" data-bs-toggle="dropdown" ' : ' class="dropdown-item" ');

            if ($menu['link'] != '') {
                $footerMenu .= ' href="' . $menu['link'] . '"';
                $footerMenu .= ($menu['target'] ? ' target="_blank"' : '');
            }

            $footerMenu .= '>';
            $footerMenu .= (!$children ? '<h3 class="footer-menu-header">' : '');
            $footerMenu .= (!empty($menu['icon']) ? '<i class="' . $menu['icon'] . '" aria-hidden="true"></i>' : '');
            $footerMenu .= $menu['title'];
            $footerMenu .= (!$children ? '</h3>' : '');
            $footerMenu .= '</a>';

            if ($children) {
                $footerMenu .= '</li>';
            }

            if ($menu['children']) {
                $footerMenu .= '<ul class="dropdown-menu footer-menu-list mb-4 mb-lg-0">';
                $footerMenu .= static::getFooterMenu($menu['children'], true, $opt);
                $footerMenu .= '</ul>';
            }

            if (!$children) {
                $footerMenu .= '</div>';
                $footerMenu .= '</div>';
            }
        }

        return $footerMenu;
    }

    public static function getClientAreaMenu(array $list = [], bool $children = false, array $opt = []): string
    {
        $pname = $opt['pname'] ?? '';
        $gtype = $opt['gtype'] ?? '';
        $acheader_info = $opt['acheader_info'] ?? '';
        $menu_links = $opt['menu_links'] ?? '';
        $visibility_ticket = $opt['visibility_ticket'] ?? '';
        $visibility_invoice = $opt['visibility_invoice'] ?? '';
        $domain_total = $opt['domain_total'] ?? 0;
        $software_total = $opt['software_total'] ?? 0;
        $sms_total = $opt['sms_total'] ?? 0;
        $hosting_total = $opt['hosting_total'] ?? 0;
        $server_total = $opt['server_total'] ?? 0;
        $special_total = $opt['special_total'] ?? 0;
        $special_list = $opt['special_list'] ?? [];
        $category = $opt['category'] ?? [];
        $ul_active = (isset($opt['active']) ? $opt['active'] : false);
        $pagebuilder = $opt['pagebuilder'] ?? false;
        $output = '';

        if ($children) {
            $output .= '<ul';
            $output .= ' class="inner list-group list-group-flush ' . ($ul_active ? ' show' : '') . '"';

            if ($ul_active) {
                $output .= ' style="display:block;"';
            }

            $output .= '>';
        }

        foreach ($list as $menu) {
            if ($menu['id'] == 'FonPageBuilder') {
                continue;
            }
            if (($menu['page'] == 'ca-tickets') && !$visibility_ticket) {
                continue;
            }
            if (($menu['page'] == 'ca-invoices') && !$visibility_invoice) {
                continue;
            }
            if ($menu['onlyCa'] && !$acheader_info) {
                continue;
            }
            if (($menu['page'] == 'create-account') && $acheader_info) {
                continue;
            }
            if (($menu['page'] == 'login-account') && $acheader_info) {
                continue;
            }
            if (($menu['page'] == 'product-group/domain') && !Config::get('options/pg-activation/domain')) {
                continue;
            }
            if (($menu['page'] == 'product-group/hosting') && !Config::get('options/pg-activation/hosting')) {
                continue;
            }
            if (($menu['page'] == 'product-group/server') && !Config::get('options/pg-activation/server')) {
                continue;
            }
            if (($menu['page'] == 'product-group/software') && !Config::get('options/pg-activation/software')) {
                continue;
            }
            if (($menu['page'] == 'product-group/sms') && !Config::get('options/pg-activation/sms')) {
                continue;
            }
            if ((($menu['page'] == 'product-group/international-sms') || $menu['page'] == 'ca-intl-sms') && !Config::get('options/pg-activation/international-sms')) {
                continue;
            }
            if (($menu['page'] == 'ca-affiliate') && !Config::get('options/affiliate/status')) {
                continue;
            }
            if (($menu['page'] == 'ca-reseller') && !Config::get('options/dealership/status')) {
                continue;
            }
            if (($menu['page'] == 'ca-reseller') && !Config::get('options/dealership/view-without-membership') && isset($acheader_info['dealership']['status']) && $acheader_info['dealership']['status'] == 'inactive') {
                continue;
            }
            if (($menu['page'] == 'ca-domains') && !Config::get('options/pg-activation/domain') && $domain_total < 1) {
                continue;
            }
            if (($menu['page'] == 'ca-orders') && !$menu['children']) {
                if (0 < $hosting_total) {
                    $menu['children'][] = [
                        'id'       => 'hosting',
                        'parent'   => $menu['id'],
                        'icon'     => '',
                        'rank'     => 0,
                        'target'   => 0,
                        'status'   => 'active',
                        'page'     => 'ca-order-group',
                        'onlyCa'   => 1,
                        'link'     => $menu_links['menu-2-2'],
                        'title'    => __('website/account/sidebar-menu-2-sub-hosting'),
                        'children' => []
                    ];
                }

                if (0 < $server_total) {
                    $menu['children'][] = [
                        'id'       => 'server',
                        'parent'   => $menu['id'],
                        'icon'     => '',
                        'rank'     => 0,
                        'target'   => 0,
                        'status'   => 'active',
                        'page'     => 'ca-order-group',
                        'onlyCa'   => 1,
                        'link'     => $menu_links['menu-2-3'],
                        'title'    => __('website/account/sidebar-menu-2-sub-server'),
                        'children' => []
                    ];
                }

                if (0 < $software_total) {
                    $menu['children'][] = [
                        'id'       => 'software',
                        'parent'   => $menu['id'],
                        'icon'     => '',
                        'rank'     => 0,
                        'target'   => 0,
                        'status'   => 'active',
                        'page'     => 'ca-order-group',
                        'onlyCa'   => 1,
                        'link'     => $menu_links['menu-2-0'],
                        'title'    => __('website/account/sidebar-menu-2-sub-software'),
                        'children' => []
                    ];
                }

                if (0 < $sms_total) {
                    $menu['children'][] = [
                        'id'       => 'sms',
                        'parent'   => $menu['id'],
                        'icon'     => '',
                        'rank'     => 0,
                        'target'   => 0,
                        'status'   => 'active',
                        'page'     => 'ca-order-group',
                        'onlyCa'   => 1,
                        'link'     => $menu_links['menu-2-1'],
                        'title'    => __('website/account/sidebar-menu-2-sub-sms'),
                        'children' => []
                    ];
                }
                if ((0 < $special_total) && $special_list) {
                    foreach ($special_list as $group) {
                        if ($group['parent'] != 0) {
                            continue;
                        }

                        $menu['children'][] = [
                            'id'       => 'special-' . $group['id'],
                            'parent'   => $menu['id'],
                            'icon'     => '',
                            'rank'     => 0,
                            'target'   => 0,
                            'status'   => 'active',
                            'page'     => 'ca-order-group',
                            'onlyCa'   => 1,
                            'link'     => $menu_links['menu-2-4'] . '?category=' . $group['id'],
                            'title'    => $group['name'],
                            'children' => []
                        ];
                    }
                }
            }
            else if (($menu['page'] == 'ca-addons') && !$menu['children']) {
                $addons = Modules::Load('Addons', 'All', true, true);

                if ($addons) {
                    $addon_menus = [];

                    foreach ($addons as $k => $v) {
                        if (!isset($v['config']['show_on_clientArea']) || !$v['config']['show_on_clientArea']) {
                            continue;
                        }

                        $addon_menus[] = [
                            'id'       => $k,
                            'parent'   => 0,
                            'icon'     => $menu['icon'],
                            'rank'     => 0,
                            'target'   => 0,
                            'status'   => 'active',
                            'page'     => 'addon',
                            'onlyCa'   => 1,
                            'link'     => Utility::link_determiner('addon/' . $k . '/client'),
                            'title'    => $v['lang']['meta']['name'],
                            'children' => []
                        ];
                    }

                    if ($addon_menus) {
                        $output .= self::getClientAreaMenu($addon_menus, false, $opt);
                    }
                }

                continue;
            }

            $active = false;
            if ((($pname == 'account_dashboard') && $menu['page'] == 'ca-dashboard') || ($pname == 'account_tickets') && $menu['page'] == 'ca-tickets' || ($pname == 'account_products') && $gtype == 'domain' && $menu['page'] == 'ca-domains' || ($pname == 'account_products') && $gtype != 'domain' && $menu['page'] == 'ca-orders' || ($pname == 'account_sms') && $menu['page'] == 'ca-intl-sms' || ($pname == 'account_invoices') && $menu['page'] == 'ca-invoices' || ($pname == 'account_info') && $menu['page'] == 'ca-ac-information' || ($pname == 'account_messages') && $menu['page'] == 'ca-messages' || ($menu['page'] == 'ca-order-group') && $category && ('special-' . $category['id']) == $menu['id'] || ($menu['page'] == 'ca-order-group') && $gtype == $menu['id'] || ($menu['page'] == 'addon') && $pname == $menu['id'] || ($menu['page'] == 'ca-affiliate') && $pname == 'affiliate' || ($menu['page'] == 'ca-reseller') && $pname == 'reseller') {
                $active = true;
            }

            if ($menu['children']) {
                $menu['link'] = 'javascript:void 0;';
            }

            $output .= '<li  class="list-group-item ' . ($children ? 'py-0 px-3' : 'p-0');

            if (stristr($menu['icon'], 'shopping-cart')) {
                $output .= ' neworderbtn';
            }

            $output .= '">';
            $output .= '<a href="' . $menu['link'] . '"';

            if ($menu['target']) {
                $output .= ' target="_blank"';
            }

            $output .= ' class="toggle d-flex align-items-center justify-content-between py-2"';

            if ($active) {
                $output .= ' data-id="active"';
            }

            $output .= '>';
            $output .= '<span>';
            $output .= ($menu['icon'] ? '<i class="' . $menu['icon'] . ' rounded bg-theme-light p-2 fa-fw" aria-hidden="true" style="width: 30px;height:30px"></i> ' : '');
            $output .= (!$menu['icon'] && $children ? '<i class="fa fa-angle-right fa-fw" aria-hidden="true"></i> ' : '');
            $output .= $menu['title'];
            $output .= '</span>';

            if ($menu['children']) {
                $output .= '<i class="fa-solid fa-angle-down"></i>';
            }

            $output .= '</a>';

            if ($menu['children']) {
                $_opt = $opt;
                $_opt['active'] = $active;
                $output .= self::getClientAreaMenu($menu['children'], true, $_opt);
            }

            $output .= '</li>' . PHP_EOL;
        }

        $output .= ($children ? '</ul>' . PHP_EOL : '');
        return $output;
    }

    public static function getThemeCustomStyles(): string
    {
        $configFonts = Config::get('theme/fonts');
        $themeFonts = [];
        $themeColors = self::getThemeColors();
        $fontSelectors = ['body', 'menu', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'custom'];
        $output = '';
        $baseFontSize = $configFonts['body']['size'] ?? 16;

        if ($configFonts) {
            if ($configFonts['source'] == 'google') {
                $fontHost = $configFonts['host'] ?? 'cloud';

                foreach ($configFonts as $fontKey => $themeFont) {
                    if (in_array($fontKey, $fontSelectors)) {
                        if (($fontKey == 'custom') && !$themeFont['selectors']) {
                            continue;
                        }

                        $themeFonts[] = $themeFont['family'] . ':' . $themeFont['variants'];
                    }
                }

                if ($themeFonts) {
                    $themeFonts = array_unique($themeFonts);
                    $cssFilePath = self::downloadGoogleFont($themeFonts, $fontHost);

                    if ($cssFilePath) {
                        if ($fontHost == 'cloud') {
                            $output .= '<link rel="preconnect" href="https://fonts.googleapis.com">';
                            $output .= '<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>';
                            $output .= '<link rel="dns-prefetch" href="https://fonts.gstatic.com">';
                        }

                        $output .= '<link href="' . $cssFilePath . '" rel="stylesheet" media="print" onload="this.media=\'all\'">' . PHP_EOL;
                        $output .= '<noscript><link href="' . $cssFilePath . '" rel="stylesheet"></noscript>' . PHP_EOL;
                    }
                }
            }
            else if ($configFonts['local']) {
                $cssFiles = explode(',', $configFonts['local']);

                foreach ($cssFiles as $cssFile) {
                    $output .= '<link href="' . trim($cssFile) . '" rel="stylesheet" media="print" onload="this.media=\'all\'">' . PHP_EOL;
                    $output .= '<noscript><link href="' . trim($cssFile) . '" rel="stylesheet"></noscript>' . PHP_EOL;
                }
            }
        }

        $output .= '<style>';
        $output .= 'html {';
        $output .= 'font-size:' . $configFonts['body']['size'] . 'px;';
        $output .= '}';
        $output .= ':root {';
        $output .= '--theme-primary: #' . $themeColors['theme-primary']['color'] . ';';
        $output .= '--theme-primary-rgb : ' . $themeColors['theme-primary']['rgb'] . ';';
        $output .= '--theme-primary-hsl : ' . $themeColors['theme-primary']['hsl'] . ';';
        $output .= '--theme-secondary: #' . $themeColors['theme-secondary']['color'] . ';';
        $output .= '--theme-secondary-rgb : ' . $themeColors['theme-secondary']['rgb'] . ';';
        $output .= '--theme-secondary-hsl : ' . $themeColors['theme-secondary']['hsl'] . ';';
        $output .= '--text-color: #' . $themeColors['text-color']['color'] . ';';
        $output .= '--text-color-rgb: ' . $themeColors['text-color']['rgb'] . ';';
        $output .= '--text-color-hsl: ' . $themeColors['text-color']['hsl'] . ';';
        $output .= '--link-color: #' . $themeColors['link-color']['color'] . ';';
        $output .= '--link-color-rgb: ' . $themeColors['link-color']['rgb'] . ';';
        $output .= '--link-color-hsl: ' . $themeColors['link-color']['hsl'] . ';';
        $output .= '--link-color-hover: #' . $themeColors['link-color-hover']['color'] . ';';
        $output .= '--link-color-hover-rgb: ' . $themeColors['link-color-hover']['rgb'] . ';';
        $output .= '--link-color-hover-hsl: ' . $themeColors['link-color-hover']['hsl'] . ';';
        $output .= '--link-color-active: #' . $themeColors['link-color-active']['color'] . ';';
        $output .= '--link-color-active-rgb: ' . $themeColors['link-color-active']['rgb'] . ';';
        $output .= '--link-color-active-hsl: ' . $themeColors['link-color-active']['hsl'] . ';';

        if ($configFonts['source'] == 'google') {
            $output .= '--body-font-family:"' . $configFonts['body']['family'] . '", ' . $configFonts['body']['category'] . ';';
            $output .= '--body-font-weight:' . $configFonts['body']['weight'] . ';';
            $output .= '--menu-font-family:"' . $configFonts['menu']['family'] . '", ' . $configFonts['menu']['category'] . ';';
            $output .= '--menu-font-weight:' . $configFonts['menu']['weight'] . ';';
            $output .= '--h1-font-family:"' . $configFonts['h1']['family'] . '", ' . $configFonts['h1']['category'] . ';';
            $output .= '--h1-font-weight:' . $configFonts['h1']['weight'] . ';';
            $output .= '--h2-font-family:"' . $configFonts['h2']['family'] . '", ' . $configFonts['h2']['category'] . ';';
            $output .= '--h2-font-weight:' . $configFonts['h2']['weight'] . ';';
            $output .= '--h3-font-family:"' . $configFonts['h3']['family'] . '", ' . $configFonts['h3']['category'] . ';';
            $output .= '--h3-font-weight:' . $configFonts['h3']['weight'] . ';';
            $output .= '--h4-font-family:"' . $configFonts['h4']['family'] . '", ' . $configFonts['h4']['category'] . ';';
            $output .= '--h4-font-weight:' . $configFonts['h4']['weight'] . ';';
            $output .= '--h5-font-family:"' . $configFonts['h5']['family'] . '", ' . $configFonts['h5']['category'] . ';';
            $output .= '--h5-font-weight:' . $configFonts['h5']['weight'] . ';';
            $output .= '--h6-font-family:"' . $configFonts['h6']['family'] . '", ' . $configFonts['h6']['category'] . ';';
            $output .= '--h6-font-weight:' . $configFonts['h6']['weight'] . ';';
        }

        $output .= '--body-font-size:' . round($configFonts['body']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--menu-font-size:' . round($configFonts['menu']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h1-font-size:' . round($configFonts['h1']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h2-font-size:' . round($configFonts['h2']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h3-font-size:' . round($configFonts['h3']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h4-font-size:' . round($configFonts['h4']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h5-font-size:' . round($configFonts['h5']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h6-font-size:' . round($configFonts['h6']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '}';
        if (($configFonts['source'] == 'google') && isset($configFonts['custom']['selector']) && $configFonts['custom']['selector']) {
            $output .= $configFonts['custom']['selector'] . '{';

            if ($configFonts['custom']['family']) {
                $output .= 'font-family:"' . $configFonts['custom']['family'] . '", ' . $configFonts['custom']['category'] . ';';
                $output .= 'font-size:' . round($configFonts['custom']['size'] / $baseFontSize, 2) . 'rem;';
                $output .= 'font-weight:' . $configFonts['custom']['weight'] . ';';
            }

            $output .= '}';
        }

        $output .= '</style>';
        return $output;
    }

    private static function downloadGoogleFont(array $fonts, string $host = 'cloud'): string
    {
        $outputDir = View::$init->get_template_dir() . 'fonts/google-fonts';
        $outputLink = View::$init->get_template_url() . Config::get('theme/name') . '/fonts/google-fonts';

        if ($host != 'cloud') {
            if (!is_dir($outputDir)) {
                mkdir($outputDir, 511, true);
            }
        }

        $fontName = [];
        $fontUrl = [];

        foreach ($fonts as $font) {
            list($name, $variants) = explode(':', $font);
            $fontName[] = strtolower(str_replace(' ', '_', $name));
            $variants = str_replace(',', ';', $variants);
            $fontUrl[] = 'family=' . urlencode($name) . ':wght@' . $variants;
        }

        $sanitizedFontFamily = implode('_', $fontName);
        $fontUrl = implode('&', $fontUrl);
        $cssFilePath = $outputDir . '/' . $sanitizedFontFamily . '.css';
        $cssFileLink = $outputLink . '/' . $sanitizedFontFamily . '.css';

        if ($host != 'cloud') {
            if (file_exists($cssFilePath)) {
                return $cssFileLink;
            }
        }

        $fontUrl = 'https://fonts.googleapis.com/css2?' . $fontUrl . '&display=swap';

        if ($host == 'cloud') {
            return $fontUrl;
        }

        $cssContent = file_get_contents($fontUrl);

        if (!$cssContent) {
            Modules::save_log('Addons', 'FonPageBuilder', 'themeDownloadGoogleFont', $fontUrl, $cssContent, '');
            return '';
        }

        preg_match_all('/url\\((https:\\/\\/fonts\\.gstatic\\.com\\/s\\/[^)]+)\\)/', $cssContent, $matches);

        foreach ($matches[1] as $fontFileUrl) {
            $filePath = $outputDir . '/' . basename($fontFileUrl);

            if (!file_exists($filePath)) {
                file_put_contents($filePath, file_get_contents($fontFileUrl));
            }

            $cssContent = str_replace($fontFileUrl, basename($fontFileUrl), $cssContent);
        }

        file_put_contents($cssFilePath, $cssContent);
        return $cssFileLink;
    }

    private static function getThemeColors(): array
    {
        $themePrimary = Config::get('theme/color1');
        $themeSecondary = Config::get('theme/color2');
        $themeTextColor = Config::get('theme/text-color');
        $themeLinkColor = Config::get('theme/link_color');
        $themeLinkColorHover = Config::get('theme/link_color_hover');
        $themeLinkColorActive = Config::get('theme/link_color_active');
        $themeColors = [
            'theme-primary'     => ['color' => $themePrimary, 'rgb' => self::hexToRgb($themePrimary), 'hsl' => self::hexToHsl($themePrimary)],
            'theme-secondary'   => ['color' => $themeSecondary, 'rgb' => self::hexToRgb($themeSecondary), 'hsl' => self::hexToHsl($themeSecondary)],
            'text-color'        => ['color' => $themeTextColor, 'rgb' => self::hexToRgb($themeTextColor), 'hsl' => self::hexToHsl($themeTextColor)],
            'link-color'        => ['color' => $themeLinkColor, 'rgb' => self::hexToRgb($themeLinkColor), 'hsl' => self::hexToHsl($themeLinkColor)],
            'link-color-hover'  => ['color' => $themeLinkColorHover, 'rgb' => self::hexToRgb($themeLinkColorHover), 'hsl' => self::hexToHsl($themeLinkColorHover)],
            'link-color-active' => ['color' => $themeLinkColorActive, 'rgb' => self::hexToRgb($themeLinkColorActive), 'hsl' => self::hexToHsl($themeLinkColorActive)]
        ];
        return $themeColors;
    }

    public static function getRandomColors(): string
    {
        $colors = ['#FF5733', '#33FF57', '#3357FF', '#FF33A6', '#33FFF6', '#5733FF', '#FF8C33', '#33FF8C', '#FF3333', '#33A1FF', '#FF9933', '#33FF99', '#FF33FF', '#FF6633', '#CC33FF', '#FF33CC', '#FFB533', '#640D5F', '#D91656', '#EE66A6', '#FF6600', '#4379F2', '#117554', '#624E88', '#C96868', '#16423C', '#161D6F', '#C7253E', '#7A1CAC', '#4E31AA', '#921A40', '#FF8225', '#36C2CE', '#F4CE14', '#1679AB', '#C80036', '#AF47D2', '#C738BD', '#D8AE7E', 'var(--theme-primary)', 'var(--theme-secondary)', 'var(--text-color)', 'var(--link-color)', 'var(--link-color-hover)', 'var(--link-color-active)'];
        return $colors[array_rand($colors)];
    }

    public function addHeroStyle(array $pageData, array $hero, string $section_id): void
    {
        if ($hero && $section_id != '') {
            $heroStyle = '';
            $heroStyle .= $section_id . '{';
            if (isset($hero['background']) && $hero['background']) {
                if ($hero['background']['type'] == 'image') {
                    $heroStyle .= ($hero['background']['image'] ? 'background-image:url(' . self::assetLinkDetermine($hero['background']['image']) . ')!important;' : '');
                    $heroStyle .= ($hero['background']['position'] ? 'background-position:' . $hero['background']['position'] . '!important;' : '');
                    $heroStyle .= ($hero['background']['size'] ? 'background-size:' . $hero['background']['size'] . '!important;' : '');
                    $heroStyle .= ($hero['background']['repeat'] ? 'background-repeat:' . $hero['background']['repeat'] . '!important;' : '');
                    $heroStyle .= ($hero['background']['attachment'] ? 'background-attachment:' . $hero['background']['attachment'] . '!important;' : '');
                    $heroStyle .= ($hero['background']['color'] ? 'background-color:' . $hero['background']['color'] . '!important;' : '');
                }
                else if ($hero['background']['type'] == 'gradient') {
                    $heroStyle .= ($hero['background']['gradient']['final'] ? 'background-image:' . $hero['background']['gradient']['final'] . '!important;' : '');
                }
                else if ($hero['background']['type'] == 'color') {
                    $heroStyle .= ($hero['background']['color'] ? 'background-color:' . $hero['background']['color'] . '!important;' : '');
                }
            }

            $heroStyle .= ($hero['padding'] ? 'padding:' . $hero['padding'] . ';' : '');
            $heroStyle .= '}';
            $heroStyle .= $section_id . ' .fon-hero-content{';
            $heroStyle .= ($hero['text_color'] ? 'color:' . $hero['text_color'] . ';' : '');
            $heroStyle .= '}';
            if (isset($hero['heading_color']) && $hero['heading_color'] != '') {
                $heroStyle .= $section_id . ' .fon-hero-content h1 ,' . $section_id . ' .fon-hero-content h2,' . $section_id . ' .fon-hero-content h3,' . $section_id . ' h4,' . $section_id . ' .fon-hero-content h5,' . $section_id . ' .fon-hero-content h6{color:' . $hero['heading_color'] . '!important;}';
            }
            if (isset($hero['link_color']) && $hero['link_color'] != '') {
                $heroStyle .= $section_id . '.fon-hero-content a:not(.btn){color:' . $hero['link_color'] . '!important;}';
            }
            if (isset($hero['link_hover_color']) && $hero['link_hover_color'] != '') {
                $heroStyle .= $section_id . ' .fon-hero-content a:not(.btn):hover{color:' . $hero['link_hover_color'] . '!important;}';
            }
            if (isset($hero['overlay']) && $hero['overlay']) {
                if (($hero['overlay']['type'] == 'solid') && $hero['overlay']['color']) {
                    $heroStyle .= $section_id . ' .fon-background-overlay{background-color:' . $hero['overlay']['color'] . ';}';
                }
                else if (($hero['overlay']['type'] == 'gradient') && $hero['overlay']['gradient']['final']) {
                    $heroStyle .= $section_id . ' .fon-background-overlay{background-image:' . $hero['overlay']['gradient']['final'] . ';}';
                }
            }
        }

        if ($heroStyle) {
            $this->addStyle($pageData['page'], $heroStyle);
        }
    }

    public static function generateColumnDisplayClassess(object $col): string
    {
        $columnStyle = '';
        $hiddenClass = [];
        if (isset($col->xl_col_display) && $col->xl_col_display) {
            $hiddenClass[] = $col->xl_col_display;
        }
        if (isset($col->lg_col_display) && $col->lg_col_display) {
            $hiddenClass[] = $col->lg_col_display;
        }
        if (isset($col->md_col_display) && $col->md_col_display) {
            $hiddenClass[] = $col->md_col_display;
        }
        if (isset($col->sm_col_display) && $col->sm_col_display) {
            $hiddenClass[] = $col->sm_col_display;
        }
        if (isset($col->xs_col_display) && $col->xs_col_display) {
            $hiddenClass[] = $col->xs_col_display;
        }

        $orderClass = [];
        if (isset($col->xl_col_order) && $col->xl_col_order != '') {
            $orderClass[] = 'order-xl-' . $col->xl_col_order;
        }
        if (isset($col->lg_col_order) && $col->lg_col_order != '') {
            $orderClass[] = 'order-lg-' . $col->lg_col_order;
        }
        if (isset($col->md_col_order) && $col->md_col_order != '') {
            $orderClass[] = 'order-md-' . $col->md_col_order;
        }
        if (isset($col->sm_col_order) && $col->sm_col_order != '') {
            $orderClass[] = 'order-sm-' . $col->sm_col_order;
        }
        if (isset($col->xs_col_order) && $col->xs_col_order != '') {
            $orderClass[] = 'order-' . $col->xs_col_order;
        }

        $columnStyle = implode(' ', array_merge($hiddenClass, $orderClass));
        return $columnStyle;
    }

    public function getPreloader(string $logo, string $favicon, string $url): string
    {
        $sitePreloader = Config::get('theme/site_preloader');
        $sitePreloaderBg = Config::get('theme/site_preloader_bg');

        if ($sitePreloader == 'site-logo') {
            $preloader_image = $logo;
        }
        else if ($sitePreloader == 'site-favicon') {
            $preloader_image = $favicon;
        }
        else {
            $preloader_image = $url . 'images/svg-loaders/' . $sitePreloader . '.svg';
        }

        $preloader = '<div id="site-preloader" class="loader ' . $sitePreloader . '" style="--fon-preloader-bg:#' . $sitePreloaderBg . '"><div class="align-items-center d-flex flex-column justify-content-center"><img src="' . $preloader_image . '" alt="Preloader" class="' . ($sitePreloader === 'site-logo' ? 'animated pulse infinite' : '') . '"/><p class="mt-3">' . $this->language['preloader_text'] . '</p></div></div>';
        return $preloader;
    }

    public static function isRecaptcha(object $captcha): bool
    {
        if (isset($captcha->module->config) && $captcha->module->config && isset($captcha->module->config['site-key']) && $captcha->module->config['site-key']) {
            return true;
        }

        return false;
    }

    private static function getTldList(string $names = ''): array
    {
        $query = Models::$init->db->select()->from('tldlist AS t');

        if ($names) {
            $query->where('t.name', 'IN (\'' . $names . '\')', '', '&&');
        }

        $query->where('t.status', '=', 'active');
        $query->order_by('t.rank ASC');
        $tlds = ($query->build() ? $query->fetch_assoc() : []);

        if ($tlds) {
            foreach ($tlds as $key => $tld) {
                $tlds[$key]['reg_price'] = self::getTldPrices($tld['id'], 'register');
                $tlds[$key]['ren_price'] = self::getTldPrices($tld['id'], 'renewal');
                $tlds[$key]['tra_price'] = self::getTldPrices($tld['id'], 'transfer');
            }
        }

        return $tlds;
    }

    public static function isMobile(): bool
    {
        $useragent = $_SERVER['HTTP_USER_AGENT'];
        $isMobile = preg_match('/(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i', $useragent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-/i', substr($useragent, 0, 4));
        return $isMobile;
    }

    public static function getPriceHolders(string $text): string
    {
        $pattern = '/\\{\\{(domain|hosting|server|software|sms|special):([\\w.]+)(?::(register|transfer|renewal))?\\}\\}/';
        $codePrice = preg_replace_callback($pattern, function($matches) {
            $urunGrubu = $matches[1];
            $urunId = $matches[2];
            $priceType = $matches[3] ?? NULL;

            if ($urunGrubu === 'domain') {
                $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
                $query = Models::$init->db->select('p.*, t.name, t.promo_status, t.promo_register_price, t.promo_transfer_price, t.promo_duedate')->from('prices AS p');
                $query->join('LEFT', 'tldlist AS t', 't.id=p.owner_id');
                $query->where('p.type', '=', $priceType, '&&');
                $query->where('p.owner', '=', 'tld', '&&');
                $query->where('t.name', '=', $urunId);
                $query->order_by('p.rank ASC');
                $price = ($query->build() ? $query->getAssoc() : false);

                if ($price) {
                    if ($priceType != 'renewal') {
                        if ($price['promo_status'] && (substr($price['promo_duedate'], 0, 4) == '1881') || DateManager::strtotime() < DateManager::strtotime($price['promo_duedate'] . ' 23:59:59') && 0 < $price['promo_' . $priceType . '_price']) {
                            $price['amount'] = $price['promo_' . $priceType . '_price'];
                        }
                    }

                    $rawPrice = self::calculatePrices([$price], self::getCurrencySymbols(), $domain_override_uscurrency, $urunGrubu);
                    $price = $rawPrice['price'];
                }
            }
            else if ($urunGrubu === 'software') {
                $query = Models::$init->db->select('p.*, s.override_usrcurrency')->from('prices AS p');
                $query->join('LEFT', 'pages AS s', 's.id=p.owner_id');
                $query->where('p.owner', '=', 'softwares', '&&');
                $query->where('p.owner_id', '=', $urunId);
                $query->order_by('p.rank ASC');
                $query->limit('1');
                $price = ($query->build() ? $query->getAssoc() : false);

                if ($price) {
                    $rawPrice = self::calculatePrices([$price], self::getCurrencySymbols(), $price['override_usrcurrency'], $urunGrubu);
                    $price = $rawPrice['price'];
                }
            }
            else {
                $query = Models::$init->db->select('p.*, pr.override_usrcurrency')->from('prices AS p');
                $query->join('LEFT', 'products AS pr', 'pr.id=p.owner_id');
                $query->where('pr.type', '=', $urunGrubu, '&&');
                $query->where('p.owner', '=', 'products', '&&');
                $query->where('p.owner_id', '=', $urunId);
                $query->order_by('p.rank ASC');
                $query->limit('1');
                $price = ($query->build() ? $query->getAssoc() : false);

                if ($price) {
                    $rawPrice = self::calculatePrices([$price], self::getCurrencySymbols(), $price['override_usrcurrency'], $urunGrubu);
                    $price = $rawPrice['price'];
                }
            }

            if ($price === false) {
                return $matches[0];
            }

            return strip_tags($price);
        }, $text);
        return $codePrice;
    }

    private function checkAndUpdateVersion(): void
    {
        $themeConfig = $this->config;
        $versionFile = TEMPLATE_DIR . 'website' . DS . $themeConfig['meta']['name'] . DS . 'VERSION';
        $updateFile = TEMPLATE_DIR . 'website' . DS . $themeConfig['meta']['name'] . DS . 'UPDATE';

        if (!file_exists($versionFile)) {
            return;
        }

        $versionFileContent = trim(file_get_contents($versionFile));

        if (!$versionFileContent) {
            return;
        }

        $currentVersion = $themeConfig['meta']['version'] ?? NULL;

        if (version_compare($versionFileContent, $currentVersion, '>')) {
            $themeConfig['meta']['version'] = $versionFileContent;

            if (file_exists($updateFile)) {
                FileManager::file_delete($updateFile);
            }

            $this->ensureKeyExists($themeConfig, [
                ['key' => 'wisecpverion', 'value' => '3.1.9.7', 'parent' => 'meta', 'overwrite' => true],
                ['key' => 'enable_lazy_loading', 'value' => true, 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'google_analytics_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'google_ads_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'google_conversion_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'facebook_pixel_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'google_tm_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'fb_pixel_via_gtm', 'value' => false, 'parent' => 'settings', 'overwrite' => false]
            ]);
            $this->migratePreviewImagesToCDN($themeConfig);
            $configDir = TEMPLATE_DIR . 'website' . DS . $themeConfig['meta']['name'] . DS;
            $export = Utility::array_export($themeConfig, ['pwith' => true]);
            FileManager::file_write($configDir . 'theme-config.php', $export);
            $this->_clearFonBuilderCache();
        }
    }

    private function ensureKeyExists(array &$config, array $options = []): void
    {
        if (!empty($options)) {
            foreach ($options as $option) {
                $key = $option['key'] ?? '';
                $value = $option['value'] ?? NULL;
                $parent = $option['parent'] ?? '';
                $forceUpdate = isset($option['overwrite']) && $option['overwrite'] === true;

                if ($key === '') {
                    continue;
                }

                if ($parent !== '') {
                    if (!isset($config[$parent]) || !is_array($config[$parent])) {
                        $config[$parent] = [];
                    }
                    if (!array_key_exists($key, $config[$parent]) || $forceUpdate) {
                        $config[$parent][$key] = $value;
                    }
                }
                else if (!array_key_exists($key, $config) || $forceUpdate) {
                    $config[$key] = $value;
                }
            }
        }
    }

    private function migratePreviewImagesToCDN(array &$config): bool
    {
        $search = 'https://fonwise.com/documentation/images/';
        $replace = 'https://cdn.jsdelivr.net/gh/Fononline/documentation-assets/';
        $targetKeys = ['package_styles', 'accordion_styles', 'animated_number_styles', 'articles_styles', 'banner_styles', 'campaign_styles', 'contentbox_styles', 'domain_tlds_styles', 'featurebox_styles', 'news_styles', 'references_styles', 'software_styles', 'tabs_styles', 'team_styles', 'testimonial_styles', 'timeline_styles'];
        $hasChanges = false;

        foreach ($targetKeys as $section) {
            if (isset($config[$section]) && is_array($config[$section])) {
                foreach ($config[$section] as $key => $value) {
                    if (is_string($value) && strpos($value, $search) !== false) {
                        $config[$section][$key] = str_replace($search, $replace, $value);
                        $hasChanges = true;
                    }
                }
            }
        }

        return $hasChanges;
    }

    public static function getLazyPlaceholder(): string
    {
        $lazyPlaceholder = static::assetLinkDetermine('templates/website/Datawise/builder/image/lazy-placeholder.svg');
        return $lazyPlaceholder;
    }

    public static function getDueDateWarning(string $dueDate, array $language, string $status): string
    {
        if (!$dueDate || $dueDate == '1970') {
            return '';
        }

        $dueDateObj = new DateTime($dueDate);
        $today = new DateTime();
        $interval = $today->diff($dueDateObj);
        $daysLeft = (int) $interval->format('%r%a');
        if (($daysLeft <= 60) && $status == 'active') {
            return ' <i class="fa-solid fa-bell fa-shake text-danger" title="' . $language['duedate_warning'] . '"></i>';
        }

        return '';
    }

    public static function getBCPLocale(string $lang): string
    {
        $localeMap = ['af' => 'af-ZA', 'am' => 'am-ET', 'ar' => 'ar-SA', 'ay' => 'ay-BO', 'az' => 'az-AZ', 'be' => 'be-BY', 'bg' => 'bg-BG', 'bi' => 'bi-VU', 'bn' => 'bn-IN', 'bs' => 'bs-BA', 'ca' => 'ca-ES', 'ch' => 'ch-PW', 'cs' => 'cs-CZ', 'da' => 'da-DK', 'de' => 'de-DE', 'dv' => 'dv-MV', 'dz' => 'dz-BT', 'el' => 'el-GR', 'en' => 'en-US', 'es' => 'es-ES', 'et' => 'et-EE', 'fa' => 'fa-IR', 'fi' => 'fi-FI', 'fj' => 'fj-FJ', 'fo' => 'fo-FO', 'fr' => 'fr-FR', 'ga' => 'ga-IE', 'gn' => 'gn-PY', 'gv' => 'gv-GB', 'he' => 'he-IL', 'hi' => 'hi-IN', 'ho' => 'ho-PG', 'hr' => 'hr-HR', 'ht' => 'ht-HT', 'hu' => 'hu-HU', 'hy' => 'hy-AM', 'hz' => 'hz-NA', 'id' => 'id-ID', 'is' => 'is-IS', 'it' => 'it-IT', 'ja' => 'ja-JP', 'ka' => 'ka-GE', 'kg' => 'kg-CD', 'kk' => 'kk-KZ', 'kl' => 'kl-GL', 'km' => 'km-KH', 'ko' => 'ko-KR', 'ky' => 'ky-KG', 'la' => 'la-VAT', 'ln' => 'ln-CD', 'lo' => 'lo-LA', 'lt' => 'lt-LT', 'lu' => 'lu-CD', 'lv' => 'lv-LV', 'mg' => 'mg-MG', 'mh' => 'mh-MH', 'mi' => 'mi-NZ', 'mk' => 'mk-MK', 'mn' => 'mn-MN', 'ms' => 'ms-MY', 'mt' => 'mt-MT', 'my' => 'my-MM', 'na' => 'na-NR', 'nb' => 'nb-NO', 'nd' => 'nd-ZW', 'ne' => 'ne-NP', 'ng' => 'ng-NA', 'nl' => 'nl-NL', 'nn' => 'nn-NO', 'no' => 'no-NO', 'nr' => 'nr-ZA', 'ny' => 'ny-MW', 'pl' => 'pl-PL', 'ps' => 'ps-AF', 'pt' => 'pt-PT', 'qu' => 'qu-PE', 'rm' => 'rm-CH', 'rn' => 'rn-BI', 'ro' => 'ro-RO', 'ru' => 'ru-RU', 'rw' => 'rw-RW', 'sg' => 'sg-CF', 'si' => 'si-LK', 'sk' => 'sk-SK', 'sl' => 'sl-SI', 'sm' => 'sm-AS', 'sn' => 'sn-ZW', 'so' => 'so-SO', 'sq' => 'sq-AL', 'sr' => 'sr-RS', 'ss' => 'ss-ZA', 'st' => 'st-ZA', 'sv' => 'sv-SE', 'sw' => 'sw-KE', 'ta' => 'ta-IN', 'tg' => 'tg-TJ', 'th' => 'th-TH', 'ti' => 'ti-ER', 'tk' => 'tk-TM', 'tn' => 'tn-ZA', 'to' => 'to-TO', 'tr' => 'tr-TR', 'ts' => 'ts-ZA', 'uk' => 'uk-UA', 'ur' => 'ur-PK', 'uz' => 'uz-UZ', 've' => 've-ZA', 'vi' => 'vi-VN', 'xh' => 'xh-ZA', 'zh' => 'zh-CN', 'zu' => 'zu-ZA'];
        $lang = strtolower($lang);
        return $localeMap[$lang] ?? 'en-US';
    }

    public static function getStarRating(int $score, string $color = 'var(--theme-primary)', int $starSize = 20): string
    {
        $maxStars = 5;
        $fullStar = '<span class="d-inline-flex align-items-center justify-content-center rounded text-white" style="width: ' . ($starSize + 8) . 'px;height: ' . ($starSize + 8) . 'px;background-color:' . $color . '"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>';
        $halfStar = '<span class="d-inline-flex align-items-center justify-content-center rounded text-white" style="width: ' . ($starSize + 8) . 'px;height: ' . ($starSize + 8) . 'px;background-color:' . $color . '"><i class="fa-solid fa-star-half" style="font-size:' . $starSize . 'px" ></i></span>';
        $emptyStar = '<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white" style="width: ' . ($starSize + 8) . 'px;height: ' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>';
        $starsHtml = '';
        $fullStars = floor($score);
        $decimalPart = $score - $fullStars;

        if (0.75 <= $decimalPart) {
            ++$fullStars;
            $halfStars = 0;
        }
        else if (0.25 <= $decimalPart) {
            $halfStars = 1;
        }
        else {
            $halfStars = 0;
        }

        $emptyStars = $maxStars - $fullStars - $halfStars;
        $starsHtml .= str_repeat($fullStar, $fullStars);
        $starsHtml .= str_repeat($halfStar, $halfStars);
        $starsHtml .= str_repeat($emptyStar, $emptyStars);
        return $starsHtml;
    }

    public static function parseCanonicalUrl(string $url, string $current_lang = '', bool $alternate = false): string
    {
        if (!$current_lang) {
            $current_lang = Language::selected();
        }

        $default_lang = Config::get('general/local');
        $page_param = '';

        if (strpos($url, '?') !== false) {
            $url_parts = explode('?', $url, 2);
            $url = $url_parts[0];
            $parsed_query = [];
            parse_str($url_parts[1], $parsed_query);
            if (isset($parsed_query['page']) && is_numeric($parsed_query['page'])) {
                $page_param = '?page=' . (int) $parsed_query['page'];
            }
        }

        $slug_suffix = '';

        if (preg_match('#/sayfa/([0-9]+)$#i', $url, $page_matches)) {
            $slug_suffix = '/sayfa/' . $page_matches[1];
            $url = preg_replace('#/sayfa/[0-9]+$#i', '', $url);
        }

        $parsed = parse_url($url);
        $protocol = (isset($parsed['scheme']) ? $parsed['scheme'] : (Utility::isSSL() ? 'https' : 'http'));
        $host = (isset($parsed['host']) ? $parsed['host'] : $_SERVER['HTTP_HOST']);

        if (View::$init->template_file == 'index.php') {
            $homeRoute = ___('website-routes/website-routes/home', false, $current_lang);
            $firstHomeRoute = trim($homeRoute[0], ' ' . "\t\n\r" . "\0" . '/');

            if ($firstHomeRoute !== '') {
                $url = str_replace($homeRoute[0], '', $url);
            }
            else {
                $url = str_replace($homeRoute[1], '', $url);
            }
        }

        if ($current_lang == $default_lang) {
            $url = preg_replace('#^' . preg_quote($protocol . '://' . $host, '#') . '/' . $default_lang . '(?=/|$)#', $protocol . '://' . $host, $url);
        }

        $categoryRoute = ___('website-routes/website-routes/products', false, $current_lang);
        $category_slug = preg_replace('/\\/\\(\\?\\).*/', '', $categoryRoute[0]);
        $pattern = '#/' . $category_slug . '/(.*)#';

        if (preg_match($pattern, $url, $matches)) {
            $category_path = $matches[1];
            $slugs = explode('/', trim($category_path, '/'));
            $lang_prefix = ($current_lang != $default_lang ? $current_lang . '/' : '');
            $last_slug = end($slugs);

            if ($last_slug == 'sms') {
                $canonical_path = $category_slug . '/sms';
                $url = $protocol . '://' . $host . '/' . $lang_prefix . $canonical_path;
            }
            else {
                $canonical_path = $category_slug . '/' . trim($last_slug, '/');
                $url = $protocol . '://' . $host . '/' . $lang_prefix . $canonical_path;
            }
        }

        $url = rtrim($url, '/');
        $url = $url . $slug_suffix . $page_param;
        return $url;
    }

    private static function parseShortcodesToHtml(string $content): string
    {
        $content = preg_replace_callback('/\\[iframe\\s+(.*?)\\]/i', function($matches) {
            $attrs = [];
            preg_match_all('/(\\w+)\\s*=\\s*"([^"]*)"/', $matches[1], $attrMatches, PREG_SET_ORDER);

            foreach ($attrMatches as $attr) {
                $attrs[] = $attr[1] . '="' . htmlspecialchars($attr[2], ENT_QUOTES) . '"';
            }

            return '<iframe ' . implode(' ', $attrs) . '></iframe>';
        }, $content);
        $content = preg_replace_callback('/\\[script\\](.*?)\\[\\/script\\]/is', function($matches) {
            return '<script>' . $matches[1] . '</script>';
        }, $content);
        return $content;
    }

    public function googleStructuredData(array $pageData = []): string
    {
        $settings = (isset($this->config['settings']) ? $this->config['settings'] : []);
        $gsdData = ['show' => (isset($settings['seo_gsd_show']) ? $settings['seo_gsd_show'] : false), 'site_name' => (isset($settings['seo_site_name']) ? $settings['seo_site_name'] : []), 'organisation_name' => (isset($settings['seo_organisation_name']) ? $settings['seo_organisation_name'] : []), 'organisation_address' => (isset($settings['seo_organisation_address']) ? $settings['seo_organisation_address'] : ''), 'organisation_city' => (isset($settings['seo_organisation_city']) ? $settings['seo_organisation_city'] : ''), 'organisation_region' => (isset($settings['seo_organisation_region']) ? $settings['seo_organisation_region'] : ''), 'organisation_postal_code' => (isset($settings['seo_organisation_postal_code']) ? $settings['seo_organisation_postal_code'] : ''), 'organisation_country' => (isset($settings['seo_organisation_country']) ? $settings['seo_organisation_country'] : ''), 'organisation_price_min' => (isset($settings['seo_organisation_price_min']) ? $settings['seo_organisation_price_min'] : 0), 'organisation_price_max' => (isset($settings['seo_organisation_price_max']) ? $settings['seo_organisation_price_max'] : 0), 'organisation_price_currency' => (isset($settings['seo_organisation_price_currency']) ? $settings['seo_organisation_price_currency'] : 147), 'organisation_rating_value' => (isset($settings['seo_organisation_rating_value']) ? $settings['seo_organisation_rating_value'] : ''), 'organisation_rating_count' => (isset($settings['seo_organisation_rating_count']) ? $settings['seo_organisation_rating_count'] : '')];
        $template = $pageData['hoptions']['page'] ?? 'index';
        $lang = Language::selected();
        $currencies = Money::getCurrencies();
        $phones = Config::get('contact/phone-numbers');
        $address = Config::get('contact/address');
        $emails = Config::get('contact/email-addresses');
        $socials = Config::get('contact/social-links');
        $maps = Config::get('contact/maps');
        $logo = static::assetLinkDetermine(Config::get('theme/header-logo'));
        $breadcrumb = $pageData['breadcrumb'] ?? [];

        if ($socials) {
            $socials = array_column($socials, 'url');
        }

        $output = [];
        if (!empty($gsdData) && isset($gsdData['show']) && $gsdData['show']) {
            if ($breadcrumb) {
                end($breadcrumb);
                $lastKey = key($breadcrumb);
                $breadcrumb[$lastKey]['link'] = $pageData['hoptions']['gsd_route'] ?? '';
                $breadcrumbItems = [];

                foreach ($breadcrumb as $item) {
                    if (isset($item['title']) && isset($item['link'])) {
                        $breadcrumbItems[] = ['@type' => 'ListItem', 'position' => count($breadcrumbItems) + 1, 'name' => $item['title'], 'item' => ($item['link'] != '' ? $item['link'] : (!preg_match('/^https?:\\/\\//', $_SERVER['REQUEST_URI']) ? Controllers::$init->CRLink(ltrim($_SERVER['REQUEST_URI'], '/'), false, 'none') : $_SERVER['REQUEST_URI']))];
                    }
                }

                $output['breadcrums'] = ['@context' => 'http://schema.org', '@type' => 'BreadcrumbList', 'itemListElement' => $breadcrumbItems];
            }

            $output['website'] = [
                '@context'    => 'http://schema.org',
                '@type'       => 'WebSite',
                '@id'         => $pageData['badress'] ?? Utility::AppAdress(),
                'name'        => $gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang),
                'description' => __('website/index/meta/description', false, $lang),
                'url'         => $pageData['badress'] ?? Utility::AppAdress(),
                'image'       => ['@type' => 'ImageObject', 'url' => $logo],
                'sameAs'      => $socials
            ];
            $output['webpage'] = [
                '@context'    => 'http://schema.org',
                '@type'       => 'WebPage',
                'name'        => (isset($pageData['header_title']) && $pageData['header_title'] ? $pageData['header_title'] : (isset($pageData['meta']['title']) && $pageData['meta']['title'] ? $pageData['meta']['title'] : __('website/index/meta/title', false, $lang))),
                'description' => (isset($pageData['header_description']) && $pageData['header_description'] ? $pageData['header_description'] : (isset($pageData['meta']['description']) && $pageData['meta']['description'] ? $pageData['meta']['description'] : __('website/index/meta/description', false, $lang))),
                'url'         => $_SERVER['REQUEST_URI'],
                'inLanguage'  => $lang,
                'isPartOf'    => ['@id' => $pageData['badress'] ?? Utility::AppAdress()]
            ];

            if ($template == 'index') {
                $output['index'] = [
                    '@context'    => 'http://schema.org',
                    '@type'       => 'Organization',
                    'name'        => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang)),
                    'description' => __('website/index/meta/description', false, $lang),
                    'url'         => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'        => $logo ?? false,
                    'image'       => $logo ?? false,
                    'email'       => $emails[0] ?? false,
                    'sameAs'      => $socials,
                    'telephone'   => str_replace(' ', '', $phones[0] ?? ''),
                    'address'     => ['@type' => 'PostalAddress', 'streetAddress' => $gsdData['organisation_address'] ?? ($address ?? false), 'addressLocality' => $gsdData['organisation_city'] ?? false, 'addressRegion' => $gsdData['organisation_region'] ?? false, 'postalCode' => $gsdData['organisation_postal_code'] ?? false, 'addressCountry' => $gsdData['organisation_country'] ?? false]
                ];
            }
            else if ($template == 'articles') {
                if (isset($pageData['hoptions']['gsd_list']) && is_array($pageData['hoptions']['gsd_list']) && 0 < count($pageData['hoptions']['gsd_list'])) {
                    $blogPosts = [];

                    foreach ($pageData['hoptions']['gsd_list'] as $index => $item) {
                        $mtime = $this->gsd_get_page_mtime($item['id']);
                        $blogPosts[] = [
                            '@type'         => 'BlogPosting',
                            'headline'      => $item['title'],
                            'url'           => $item['route'],
                            'image'         => $item['image'] ?? false,
                            'datePublished' => (isset($item['ctime']) && $item['ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $item['ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c')),
                            'dateModified'  => $mtime ?: (new DateTime())->format('c'),
                            'author'        => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()]
                        ];
                    }
                    $output['blog'] = ['@context' => 'https://schema.org', '@type' => 'Blog', 'name' => (isset($pageData['meta']['title']) && $pageData['meta']['title'] != '' ? $pageData['meta']['title'] : $pageData['header_title']), 'url' => Controllers::$init->CRLink('articles', false, $lang), 'blogPost' => $blogPosts];
                }
            }
            else if (($template == 'softwares') || $template == 'news' || $template == 'knowledgebase' || $template == 'references') {
                if (isset($pageData['hoptions']['gsd_list']) && is_array($pageData['hoptions']['gsd_list']) && 0 < count($pageData['hoptions']['gsd_list'])) {
                    $itemListElements = [];

                    foreach ($pageData['hoptions']['gsd_list'] as $index => $item) {
                        $itemListElements[$index] = ['@type' => 'ListItem', 'url' => $item['route'], 'name' => $item['title'], 'position' => $index + 1];
                    }
                    $output[$template] = ['@context' => 'https://schema.org', '@type' => 'ItemList', 'name' => (isset($pageData['meta']['title']) && $pageData['meta']['title'] != '' ? $pageData['meta']['title'] : $pageData['header_title']), 'itemListElement' => $itemListElements];
                }
            }
            else if (($template == 'hosting-products') || $template == 'server-products' || $template == 'sms-products' || $template == 'special-products') {
                if (isset($pageData['hoptions']['gsd_list']['list']) && $pageData['hoptions']['gsd_list']['list'] && 0 < count($pageData['hoptions']['gsd_list']['list'])) {
                    $old_serialize_precision = ini_get('serialize_precision');
                    ini_set('serialize_precision', -1);
                    $offers = [];

                    foreach ($pageData['hoptions']['gsd_list']['list'] as $item) {
                        $currency = (isset($item['prices'][0]['cid']) ? $currencies[array_search($item['prices'][0]['cid'], array_column($currencies, 'id'))]['code'] : 'TRY');
                        $sale_price = $item['prices'][0]['amount'];
                        $raw_price = 0;

                        if (0 < $item['prices'][0]['discount']) {
                            $raw_price = $item['prices'][0]['amount'] / (1 - ($item['prices'][0]['discount'] / 100));
                        }
                        $offers[$item['id']] = [
                            '@type'         => 'Offer',
                            'name'          => $item['title'],
                            'sku'           => (isset($pageData['hoptions']['gsd_list']['cat']) && $pageData['hoptions']['gsd_list']['cat'] ? $pageData['hoptions']['gsd_list']['cat'] . '-' . $item['id'] : $item['id']),
                            'availability'  => (isset($item['haveStock']) && $item['haveStock'] ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock'),
                            'itemCondition' => 'https://schema.org/NewCondition',
                            'seller'        => ['@type' => 'Organization', 'name' => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang))],
                            'url'           => self::parseCanonicalUrl($item['buy_link'], $lang)
                        ];
                        if ((0 < $raw_price) && $raw_price != $sale_price) {
                            $offers[$item['id']]['priceSpecification'] = [
                                ['@type' => 'UnitPriceSpecification', 'price' => (float) sprintf('%.2f', $sale_price), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false],
                                ['@type' => 'UnitPriceSpecification', 'priceType' => 'https://schema.org/StrikethroughPrice', 'price' => (float) sprintf('%.2f', $raw_price), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false]
                            ];
                        }
                        else {
                            $offers[$item['id']]['priceSpecification'] = ['@type' => 'UnitPriceSpecification', 'price' => (float) sprintf('%.2f', $sale_price), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false];
                        }
                    }
                    $output[$template] = [
                        '@context'    => 'https://schema.org',
                        '@type'       => 'Product',
                        'name'        => $pageData['header_title'],
                        'description' => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['header_description']) && $pageData['header_description'] != '' ? $pageData['header_description'] : false)),
                        'brand'       => ['@type' => 'Brand', 'name' => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang))],
                        'image'       => ['@type' => 'ImageObject', 'url' => (isset($pageData['header_background']) && $pageData['header_background'] ? $pageData['header_background'] : false)],
                        'offers'      => array_values($offers)
                    ];
                    ini_set('serialize_precision', $old_serialize_precision);
                }
                if (isset($pageData['hoptions']['gsd_faq']) && $pageData['hoptions']['gsd_faq'] && 0 < count($pageData['hoptions']['gsd_faq'])) {
                    $faqs = [];

                    foreach ($pageData['hoptions']['gsd_faq'] as $faq) {
                        $faqs[] = [
                            '@type'          => 'Question',
                            'name'           => $faq['title'],
                            'acceptedAnswer' => ['@type' => 'Answer', 'text' => $faq['description']]
                        ];
                    }

                    $output[$template . '_faqs'] = ['@context' => 'https://schema.org', '@type' => 'FAQPage', 'mainEntity' => $faqs];
                }
            }
            else if ($template == 'page-detail-software') {
                $old_serialize_precision = ini_get('serialize_precision');
                ini_set('serialize_precision', -1);
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['software-detail'] = [
                    '@context'            => 'https://schema.org',
                    '@type'               => 'SoftwareApplication',
                    'mainEntityOfPage'    => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'name'                => $pageData['header_title'],
                    'applicationCategory' => 'BusinessApplication',
                    'description'         => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'               => (isset($pageData['hoptions']['gsd_mockup']) && $pageData['hoptions']['gsd_mockup'] ? $pageData['hoptions']['gsd_mockup'] : (isset($pageData['hoptions']['gsd_cover']) && $pageData['hoptions']['gsd_cover'] ? $pageData['hoptions']['gsd_cover'] : $pageData['header_background'] ?? false)),
                    'datePublished'       => $ctime,
                    'dateModified'        => $mtime ?: $ctime,
                    'aggregateRating'     => ['@type' => 'AggregateRating', 'ratingValue' => (float) sprintf('%.1f', 4.7), 'ratingCount' => $pageData['hoptions']['gsd_ratingCount'] ?? 0],
                    'offers'              => ['@type' => 'Offer', 'price' => (float) sprintf('%.2f', $pageData['hoptions']['gsd_price']['amount']), 'priceCurrency' => $currencies[array_search($pageData['hoptions']['gsd_price']['cid'], array_column($currencies, 'id'))]['code']],
                    'operatingSystem'     => 'Web'
                ];
                ini_set('serialize_precision', $old_serialize_precision);
            }
            else if ($template == 'page-detail-articles') {
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['article-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'BlogPosting',
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'isPartOf'         => ['@type' => 'Blog', 'name' => __('website/articles/meta/title') . ' - ' . __('website/index/meta/title'), 'url' => Controllers::$init->CRLink('articles')],
                    'headline'         => $pageData['header_title'],
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => (isset($pageData['hoptions']['gsd_cover']) && $pageData['hoptions']['gsd_cover'] ? $pageData['hoptions']['gsd_cover'] : $pageData['header_background'] ?? false),
                    'datePublished'    => $ctime,
                    'dateModified'     => $mtime ?: $ctime,
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ]
                ];
            }
            else if ($template == 'page-detail-news') {
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['news-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'NewsArticle',
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'headline'         => $pageData['header_title'],
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => (isset($pageData['hoptions']['gsd_cover']) && $pageData['hoptions']['gsd_cover'] ? static::assetLinkDetermine('resources/uploads/news/' . $pageData['hoptions']['gsd_cover']) : $pageData['header_background'] ?? false),
                    'datePublished'    => $ctime,
                    'dateModified'     => $mtime ?: $ctime,
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ]
                ];
            }
            else if ($template == 'page-detail-references') {
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['reference-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'Article',
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'isPartOf'         => ['@type' => 'CollectionPage', 'name' => __('website/references/meta/title') . ' - ' . __('website/index/meta/title'), 'url' => Controllers::$init->CRLink('references')],
                    'headline'         => $pageData['header_title'],
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => (isset($pageData['hoptions']['gsd_mockup']) && $pageData['hoptions']['gsd_mockup'] ? $pageData['hoptions']['gsd_mockup'] : (isset($pageData['hoptions']['gsd_cover']) && $pageData['hoptions']['gsd_cover'] ? static::assetLinkDetermine('resources/uploads/references/' . $pageData['hoptions']['gsd_cover']) : $pageData['header_background'] ?? false)),
                    'datePublished'    => $ctime,
                    'dateModified'     => $mtime ?: $ctime,
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ]
                ];
            }
            else if ($template == 'page-detail-normal') {
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['normal-page-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'Article',
                    '@id'              => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link'],
                    'url'              => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link'],
                    'name'             => $pageData['header_title'],
                    'headline'         => $pageData['header_title'],
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => $pageData['header_background'] ?? false,
                    'inLanguage'       => $lang,
                    'datePublished'    => $ctime,
                    'dateModified'     => $mtime ?: $ctime,
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ],
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']]
                ];
            }
            else if ($template == 'knowledgebase-detail') {
                $ctime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0, 'ctime', 'knowledgebase');
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0, 'mtime', 'knowledgebase');
                $output['knowledgebase-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'TechArticle',
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'isPartOf'         => ['@type' => 'CollectionPage', 'name' => __('website/knowledgebase/meta/title') . ' - ' . __('website/index/meta/title'), 'url' => Controllers::$init->CRLink('knowledgebase')],
                    'headline'         => (isset($pageData['hoptions']['gsd_title']) && $pageData['hoptions']['gsd_title'] != '' ? $pageData['hoptions']['gsd_title'] : (isset($pageData['meta']['title']) && $pageData['meta']['title'] != '' ? $pageData['meta']['title'] : '')),
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => (isset($pageData['header_background']) && $pageData['header_background'] ? $pageData['header_background'] : false),
                    'datePublished'    => $ctime ?: (new DateTime())->format('c'),
                    'dateModified'     => $mtime ?: (new DateTime())->format('c'),
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ]
                ];
            }
            else if ($template == 'contact') {
                $old_serialize_precision = ini_get('serialize_precision');
                ini_set('serialize_precision', -1);
                $output['contact'] = [
                    '@context'        => 'https://schema.org',
                    '@type'           => ['LocalBusiness'],
                    '@id'             => ($pageData['badress'] ? $pageData['badress'] . '#LocalBusiness' : Utility::AppAdress() . '#LocalBusiness'),
                    'image'           => $logo ?? false,
                    'name'            => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title')),
                    'telephone'       => str_replace(' ', '', $phones[0] ?? ''),
                    'email'           => $emails[0] ?? false,
                    'priceRange'      => str_replace(' ', '', Money::formatter_symbol($gsdData['organisation_price_min'], $gsdData['organisation_price_currency'])) . ' - ' . str_replace(' ', '', Money::formatter_symbol($gsdData['organisation_price_max'], $gsdData['organisation_price_currency'])),
                    'address'         => ['@type' => 'PostalAddress', 'streetAddress' => $gsdData['organisation_address'] ?? ($address ?? false), 'addressLocality' => $gsdData['organisation_city'] ?? false, 'addressRegion' => $gsdData['organisation_region'] ?? false, 'postalCode' => $gsdData['organisation_postal_code'] ?? false, 'addressCountry' => $gsdData['organisation_country'] ?? false],
                    'aggregateRating' => ['@type' => 'AggregateRating', 'ratingValue' => ($gsdData['organisation_rating_value'] ? (float) sprintf('%.1f', $gsdData['organisation_rating_value']) : 5), 'reviewCount' => $gsdData['organisation_rating_count'] ?? 100, 'worstRating' => 1, 'bestRating' => 5],
                    'geo'             => ['@type' => 'GeoCoordinates', 'latitude' => $maps['latitude'] ?? false, 'longitude' => $maps['longitude'] ?? false],
                    'url'             => $pageData['badress'] ?? Utility::AppAdress(),
                    'sameAs'          => $socials
                ];
                ini_set('serialize_precision', $old_serialize_precision);
            }
            else if ($template == 'domain') {
                if (isset($pageData['hoptions']['gsd_list']) && $pageData['hoptions']['gsd_list'] && 0 < count($pageData['hoptions']['gsd_list'])) {
                    $old_serialize_precision = ini_get('serialize_precision');
                    ini_set('serialize_precision', -1);
                    $offers = [];

                    foreach ($pageData['hoptions']['gsd_list'] as $item) {
                        $currency = (isset($item['currency']) ? $currencies[array_search($item['currency'], array_column($currencies, 'id'))]['code'] : 'TRY');
                        $offers[$item['id']] = [
                            '@type'         => 'Offer',
                            'name'          => '.' . $item['name'] . ' Domain',
                            'sku'           => 'domain-' . $item['name'],
                            'availability'  => 'https://schema.org/InStock',
                            'itemCondition' => 'https://schema.org/NewCondition',
                            'seller'        => ['@type' => 'Organization', 'name' => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang))],
                            'url'           => self::parseCanonicalUrl(Controllers::$init->CRLink('domain', false, $lang), $lang)
                        ];
                        if ($item['promo_status'] && 0 < $item['promo_register_price']) {
                            $offers[$item['id']]['priceValidUntil'] = $item['promo_duedate'];
                            $offers[$item['id']]['priceSpecification'] = [
                                ['@type' => 'UnitPriceSpecification', 'price' => (float) sprintf('%.2f', $item['promo_register_price']), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false],
                                ['@type' => 'UnitPriceSpecification', 'priceType' => 'https://schema.org/StrikethroughPrice', 'price' => (float) sprintf('%.2f', $item['reg_price']['amount']), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false]
                            ];
                        }
                        else {
                            $offers[$item['id']]['priceSpecification'] = ['@type' => 'UnitPriceSpecification', 'price' => (float) sprintf('%.2f', $item['reg_price']['amount']), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false];
                        }
                    }
                    $output[$template] = [
                        '@context'    => 'https://schema.org',
                        '@type'       => 'Product',
                        'name'        => $pageData['header_title'],
                        'description' => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['header_description']) && $pageData['header_description'] != '' ? $pageData['header_description'] : false)),
                        'brand'       => ['@type' => 'Brand', 'name' => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang))],
                        'image'       => ['@type' => 'ImageObject', 'url' => (isset($pageData['header_background']) && $pageData['header_background'] ? $pageData['header_background'] : false)],
                        'offers'      => array_values($offers)
                    ];
                    ini_set('serialize_precision', $old_serialize_precision);
                }
                if (isset($pageData['hoptions']['gsd_faq']) && $pageData['hoptions']['gsd_faq'] && 0 < count($pageData['hoptions']['gsd_faq'])) {
                    $faqs = [];

                    foreach ($pageData['hoptions']['gsd_faq'] as $faq) {
                        $faqs[] = [
                            '@type'          => 'Question',
                            'name'           => $faq['title'],
                            'acceptedAnswer' => ['@type' => 'Answer', 'text' => $faq['description']]
                        ];
                    }

                    $output['hosting-faqs'] = ['@context' => 'https://schema.org', '@type' => 'FAQPage', 'mainEntity' => $faqs];
                }
            }
        }

        $final_output = '<!-- Google Yapılandırılmış Veri - Start -->' . "\n";
        if ($output && is_array($output) && 0 < count($output)) {
            foreach ($output as $item) {
                $final_output .= '<script type="application/ld+json">';
                $final_output .= json_encode($item, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
                $final_output .= '</script>';
            }
        }

        $final_output .= '<!-- Google Yapılandırılmış Veri - End -->' . "\n";
        return $final_output;
    }

    public function parseOpenGraph(array $data = []): string
    {
        if (($data['type'] ?? '') == 'business.business') {
            $settings = (isset($this->config['settings']) ? $this->config['settings'] : []);
            $data['title'] = (isset($settings['seo_organisation_name'][$this->lang]) ? $settings['seo_organisation_name'][$this->lang] : __('website/meta/title', false, $this->lang));
            $data['image'] = static::assetLinkDetermine(Config::get('theme/header-logo'));
            $data['description'] = __('website/meta/description', false, $this->lang);
            $data['url'] = Controllers::$init->CRLink('contact');
            $address = (isset($settings['seo_organisation_address']) ? $settings['seo_organisation_address'] : Config::get('contact/address') ?? '');
            $city = (isset($settings['seo_organisation_city']) ? $settings['seo_organisation_city'] : '');
            $region = (isset($settings['seo_organisation_region']) ? $settings['seo_organisation_region'] : '');
            $zipcode = (isset($settings['seo_organisation_postal_code']) ? $settings['seo_organisation_postal_code'] : '');
            $country = (isset($settings['seo_organisation_country']) ? $settings['seo_organisation_country'] : Config::get('general/country') ?? '');
            $countryList = AddressManager::getCountryList();
            $countryName = '';

            if ($country) {
                foreach ($countryList as $c) {
                    if (strtoupper($country) == $c['code']) {
                        $countryName = $c['name'];
                    }
                }
            }
        }

        $ogLang = self::getBCPLocale($this->lang);
        $opengraph = '';
        $opengraph .= '<meta property="og:locale" content="' . $ogLang . '">' . PHP_EOL;
        $opengraph .= '<meta property="og:site_name" content="' . __('website/index/meta/title', false, $this->lang) . '">' . PHP_EOL;
        if (isset($data['title'][$this->lang]) && $data['title'][$this->lang] != '') {
            $opengraph .= '<meta property="og:title" content="' . $data['title'][$this->lang] . '">' . PHP_EOL;
        }

        $opengraph .= '<meta property="og:type" content="' . ($data['type'] ?? 'website') . '">' . PHP_EOL;
        $opengraph .= '<meta property="og:url" content="' . $data['url'] . '">' . PHP_EOL;
        if (isset($data['image']) && $data['image'] != '') {
            $opengraph .= '<meta property="og:image" content="' . static::assetLinkDetermine($data['image']) . '">' . PHP_EOL;

            if ($data['type'] != 'business.business') {
                $opengraph .= '<meta property="og:image:width" content="1200">' . PHP_EOL;
                $opengraph .= '<meta property="og:image:height" content="630">' . PHP_EOL;
            }
        }
        if (isset($data['description'][$this->lang]) && $data['description'][$this->lang] != '') {
            $opengraph .= '<meta property="og:description" content="' . $data['description'][$this->lang] . '">' . PHP_EOL;
        }
        if (isset($data['type']) && $data['type'] == 'article') {
            if (isset($data['author']) && $data['author'] != '') {
                $opengraph .= '<meta property="article:author" content="' . $data['author'] . '">' . PHP_EOL;
            }
            if (isset($data['published_time']) && $data['published_time'] != '') {
                $opengraph .= '<meta property="article:published_time" content="' . $data['published_time'] . '">' . PHP_EOL;
            }
            if (isset($data['modified_time']) && $data['modified_time'] != '') {
                $opengraph .= '<meta property="article:modified_time" content="' . $data['modified_time'] . '">' . PHP_EOL;
            }
            if (isset($data['section']) && $data['section'] != '') {
                $opengraph .= '<meta property="article:section" content="' . $data['section'] . '">' . PHP_EOL;
            }
        }
        if (isset($data['type']) && $data['type'] == 'business.business') {
            if (isset($address) && $address != '') {
                $opengraph .= '<meta property="business:contact_data:street_address" content="' . $address . '">' . PHP_EOL;
            }
            if (isset($region) && $region != '') {
                $opengraph .= '<meta property="business:contact_data:locality" content="' . $region . '">' . PHP_EOL;
            }
            if (isset($city) && $city != '') {
                $opengraph .= '<meta property="business:contact_data:region" content="' . $city . '">' . PHP_EOL;
            }
            if (isset($zipcode) && $zipcode != '') {
                $opengraph .= '<meta property="business:contact_data:postal_code" content="' . $zipcode . '">' . PHP_EOL;
            }
            if (isset($countryName) && $countryName != '') {
                $opengraph .= '<meta property="business:contact_data:country_name" content="' . $countryName . '">' . PHP_EOL;
            }
        }
        if (isset($data['type']) && $data['type'] != 'business.business') {
            $opengraph .= '<meta name="twitter:card" content="summary">' . PHP_EOL;
            $opengraph .= '<meta name="twitter:site" content="' . __('website/index/meta/title', false, $this->lang) . '">' . PHP_EOL;
            if (isset($data['description'][$this->lang]) && $data['description'][$this->lang] != '') {
                $opengraph .= '<meta property="twitter:description" content="' . $data['description'][$this->lang] . '">' . PHP_EOL;
            }
            if (isset($data['image']) && $data['image'] != '') {
                $opengraph .= '<meta name="twitter:image:src" content="' . static::assetLinkDetermine($data['image']) . '">' . PHP_EOL;
            }
        }

        return $opengraph;
    }

    private function _gsd_description_create(string $text, int $limit = 250): string
    {
        $text = strip_tags($text);

        if (mb_strlen($text) <= $limit) {
            return $text;
        }

        $short = mb_substr($text, 0, $limit);
        $lastSpace = mb_strrpos($short, ' ');
        return mb_substr($short, 0, $lastSpace) . '…';
    }

    public function gsd_get_page_mtime(string|int $id, string $column = 'mtime', string $type = 'pages'): string
    {
        $time = '';
        $pageTimeExist = WDB::query('SHOW COLUMNS FROM `' . $type . '` LIKE \'' . $column . '\'')->rowCount();

        if ($pageTimeExist) {
            $query = WDB::select('p.' . $column)->from($type . ' AS p')->where('p.id', '=', $id);
            $result = ($query->build() ? $query->getAssoc() : '');
            if ($result && isset($result[$column]) && $result[$column] != '0000-00-00 00:00:00') {
                $time = date(DATE_ATOM, strtotime($result[$column]));
            }
        }

        return $time;
    }

    public static function wordCount(string $unicode_string): int
    {
        $unicode_string = preg_replace('/[\\p{P}\\p{N}]/u', '', $unicode_string);
        $unicode_string = preg_replace('/\\s+/u', ' ', $unicode_string);
        $words_array = preg_split('/\\s+/u', trim($unicode_string), -1, PREG_SPLIT_NO_EMPTY);
        return count($words_array);
    }

    public static function getImageDimensions(string $image_path_or_url, ?string $base_url = NULL): ?string
    {
        if (empty($base_url)) {
            $protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http');
            $host = $_SERVER['HTTP_HOST'];
            $host = preg_replace('/^www\\./', '', $host);
            $base_url = $protocol . '://' . $host;
        }
        $is_remote = (strpos($image_path_or_url, 'http://') === 0) || strpos($image_path_or_url, 'https://') === 0;
        $full_path = NULL;

        if ($is_remote) {
            if (strpos($image_path_or_url, $base_url) === 0) {
                $relative_path = substr($image_path_or_url, strlen($base_url));
                $base_path = $_SERVER['DOCUMENT_ROOT'];
                $full_path = $base_path . '/' . ltrim($relative_path, '/');

                if (!file_exists($full_path)) {
                    return NULL;
                }
            }
            else {
                return NULL;
            }
        }
        else {
            $base_path = $_SERVER['DOCUMENT_ROOT'];
            $full_path = $base_path . '/' . ltrim($image_path_or_url, '/');

            if (!file_exists($full_path)) {
                return NULL;
            }
        }

        $size_info = @getimagesize($full_path);
        if ($size_info !== false && isset($size_info[0]) && isset($size_info[1]) && 0 < $size_info[0] && 0 < $size_info[1]) {
            return 'width="' . $size_info[0] . '" height="' . $size_info[1] . '"';
        }

        return NULL;
    }

    public static function getImageThumb(string $image, string $type = 'articles'): string
    {
        $defaultImage = 'resources/uploads/' . $type . '/default.jpg';

        if ($type == 'software') {
            $defaultImage = 'resources/uploads/' . $type . '/list-image-default.jpg';
        }

        $defaultImage = static::assetLinkDetermine($defaultImage);

        if ($image) {
            $image = trim($image);
            $parts = parse_url($image);
            $itemImagePath = (isset($parts['path']) ? $parts['path'] : '');
            $segments = explode('/', trim($itemImagePath, '/'));
            $itemImageFolder = $segments[count($segments) - 2] ?? '';
            $itemImageFile = end($segments) ?: '';

            if (strpos($itemImagePath, '/' . $type . '/thumb/') !== false) {
                $defaultImage = $image;
            }
            else {
                $thumbUrl = preg_replace('#/(' . preg_quote($type, '#') . ')/#', '/$1/thumb/', $image, 1);
                $thumbPath = RESOURCE_DIR . 'uploads' . DS . $type . DS . 'thumb' . DS . $itemImageFolder . DS . $itemImageFile;

                if (file_exists($thumbPath)) {
                    $defaultImage = $thumbUrl;
                }
                else {
                    $defaultImage = $image;
                }
            }
        }

        return $defaultImage;
    }

    private function sanitizeRelativePath(string $path): string
    {
        $safePath = str_replace('\\', '/', $path);
        $safePath = str_replace('..', '', $safePath);
        return ltrim($safePath, '/');
    }

    private function buildGalleryPrettyTitle(string $fileBaseName): string
    {
        $cleaned = preg_replace('/[^a-zA-Z0-9]+/', ' ', $fileBaseName) ?? '';
        $cleaned = trim($cleaned);

        if ($cleaned === '') {
            return 'Untitled';
        }

        return ucwords(strtolower($cleaned));
    }

    private function ensureThumbDirectory(string $path): void
    {
        if (!is_dir($path)) {
            mkdir($path, 509, true);
        }
    }

    private function buildGalleryThumbForImage(string $relativePath, string $baseDir, string $thumbDir, int $width, int $height): array
    {
        if (!class_exists('Upload')) {
            require_once ROOT_DIR . 'coremio' . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . 'Uploads' . DIRECTORY_SEPARATOR . 'class.upload.php';
        }

        $safeRelativePath = $this->sanitizeRelativePath($relativePath);
        $sourcePath = realpath($baseDir . DIRECTORY_SEPARATOR . $safeRelativePath);
        $baseRealPath = realpath($baseDir);
        if ($sourcePath === false || $baseRealPath === false || strpos($sourcePath, $baseRealPath) !== 0) {
            return ['crop' => $safeRelativePath, 'fit' => $safeRelativePath];
        }

        $sourceDir = (string) pathinfo($safeRelativePath, PATHINFO_DIRNAME);
        $baseName = (string) pathinfo($safeRelativePath, PATHINFO_FILENAME);
        $safeBaseName = Filter::permalink($baseName);
        $sourceDir = ($sourceDir === '.' ? '' : $sourceDir);
        $targetDir = $thumbDir . ($sourceDir !== '' ? DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $sourceDir) : '');
        $this->ensureThumbDirectory($targetDir);
        $fileStem = $safeBaseName . '_' . $width . '_' . $height;
        $cropName = $fileStem . '_crop.jpg';
        $fitName = $fileStem . '_fit.jpg';
        $cropAbsolute = $targetDir . DIRECTORY_SEPARATOR . $cropName;
        $fitAbsolute = $targetDir . DIRECTORY_SEPARATOR . $fitName;

        if (!is_file($cropAbsolute)) {
            $upload = new Upload($sourcePath);
            $upload->image_resize = true;
            $upload->image_convert = 'jpg';
            $upload->image_x = $width;
            $upload->image_y = $height;
            $upload->image_ratio_crop = true;
            $upload->jpeg_quality = 85;
            $upload->file_safe_name = false;
            $upload->file_overwrite = true;
            $upload->file_new_name_body = $fileStem . '_crop';
            $upload->file_new_name_ext = 'jpg';
            $upload->process($targetDir);
        }

        if (!is_file($fitAbsolute)) {
            $upload = new Upload($sourcePath);
            $upload->image_resize = true;
            $upload->image_convert = 'jpg';
            $upload->image_x = $width;
            $upload->image_y = $height;
            $upload->image_ratio = true;
            $upload->jpeg_quality = 85;
            $upload->file_safe_name = false;
            $upload->file_overwrite = true;
            $upload->file_new_name_body = $fileStem . '_fit';
            $upload->file_new_name_ext = 'jpg';
            $upload->process($targetDir);
        }

        $thumbPrefix = 'fongallerythumb/' . ($sourceDir !== '' ? $sourceDir . '/' : '');
        return ['crop' => $thumbPrefix . $cropName, 'fit' => $thumbPrefix . $fitName];
    }

    private function _parseResponsiveBootstrapTextAligns(object|array $alignData): string
    {
        if (empty($alignData)) {
            return '';
        }

        $alignData = (array) $alignData;
        $directionMap = ['left' => 'start', 'right' => 'end', 'center' => 'center', 'justify' => 'justify'];
        $classes = [];

        foreach ($alignData as $breakpoint => $value) {
            if (!isset($directionMap[$value])) {
                continue;
            }

            $bsValue = $directionMap[$value];

            if ($breakpoint === 'xs') {
                $classes[] = 'text-' . $bsValue;
            }
            else {
                $classes[] = 'text-' . $breakpoint . '-' . $bsValue;
            }
        }

        return implode(' ', $classes);
    }

    private function _parseResponsiveBootstrapFlexAligns(object|array $alignData): string
    {
        if (empty($alignData)) {
            return '';
        }

        $alignData = (array) $alignData;
        $directionMap = ['left' => 'start', 'right' => 'end', 'center' => 'center', 'justify' => 'between'];
        $classes = [];

        foreach ($alignData as $breakpoint => $value) {
            if (!isset($directionMap[$value])) {
                continue;
            }

            $bsValue = $directionMap[$value];

            if ($breakpoint === 'xs') {
                $classes[] = 'justify-content-' . $bsValue;
            }
            else {
                $classes[] = 'justify-content-' . $breakpoint . '-' . $bsValue;
            }
        }

        return implode(' ', $classes);
    }

    public static function getFieldMultilingualText(mixed $field, string $currentLang = 'tr', array|string $default = ''): string
    {
        if (!isset($field) || empty($field)) {
            return $default;
        }
        if (is_object($field) || is_array($field)) {
            $fieldArray = (array) $field;
            if (isset($fieldArray[$currentLang]) && $fieldArray[$currentLang] !== '') {
                return $fieldArray[$currentLang];
            }

            $firstValue = array_values($fieldArray)[0] ?? '';
            return ($firstValue !== '' ? $firstValue : $default);
        }

        if (is_string($field)) {
            return ($field !== '' ? $field : $default);
        }

        return $default;
    }

    private function addPreloadLink(string $imageUrl, string $page = 'index', string $as = 'image'): void
    {
        $url = static::assetLinkDetermine($imageUrl);
        $preloadCode = '<link rel="preload" href="' . $url . '" as="' . $as . '" fetchpriority="high">';
        $encoded = htmlentities($preloadCode, ENT_QUOTES, 'UTF-8');
        $this->addHeaderCode($page, $encoded . PHP_EOL);
    }

    private function handlePatternImages(string $classes, string $pageKey, string $tadress, bool $isLcpCandidate = false): string
    {
        $themeUrl = $tadress . 'images/bg/';
        $patterns = [
            'bg-data-pattern-left'      => [
            'images' => ['data-pattern-left.png'],
            'pos'    => 'left center',
            'size'   => 'contain'
        ],
            'bg-data-pattern-right'     => [
            'images' => ['data-pattern-right.png'],
            'pos'    => 'right center',
            'size'   => 'contain'
        ],
            'bg-data-pattern-all'       => [
            'images' => ['data-pattern-left.png', 'data-pattern-right.png'],
            'pos'    => 'left center, right center',
            'size'   => '450px, 450px'
        ],
            'bg-data-pattern-all-white' => [
            'images' => ['data-pattern-left-white.png', 'data-pattern-right-white.png'],
            'pos'    => 'left center, right center',
            'size'   => '450px, 450px'
        ]
        ];
        $inlineStyle = '';
        $classArray = array_filter(explode(' ', $classes));

        foreach ($patterns as $classKey => $data) {
            if (in_array($classKey, $classArray)) {
                if ($isLcpCandidate && self::$lcpHandled === false) {
                    foreach ($data['images'] as $img) {
                        $fullUrl = $themeUrl . $img;
                        $this->addPreloadLink($fullUrl, $pageKey);
                    }
                }

                $bgUrls = [];

                foreach ($data['images'] as $img) {
                    $bgUrls[] = 'url(' . $themeUrl . $img . ')';
                }

                $inlineStyle = 'background-image: ' . implode(',', $bgUrls) . '!important; ';

                if (isset($data['pos'])) {
                    $inlineStyle .= 'background-position: ' . $data['pos'] . '!important; ';
                }

                if (isset($data['size'])) {
                    $inlineStyle .= 'background-size: ' . $data['size'] . '!important; ';
                }

                break;
            }
        }

        return $inlineStyle;
    }
}

?>

FonPageBuilder.php lisans mekanizma oldugu yeri paylaştım

PHP:
private function runLicenseCheck($activate = false)
    {
        if (!function_exists('curl_init') || !function_exists('curl_exec') || !function_exists('curl_setopt')) {
            self::$licenseStatus = false;
            $this->error = self::$licenseError = 'PHP Curl Library not found';
            return false;
        }

        $licenseFile = __DIR__ . DS . 'LICENSE';
        $license_data = self::getLicenseFileData();
        $config = include __DIR__ . DS . 'config.php';
        $createdAt = (isset($config['created_at']) ? (int) $config['created_at'] : 0);
        $cacheHash = (isset($config['settings']['cache_hash']) ? $config['settings']['cache_hash'] : '');
        $decodedHash = (!empty($cacheHash) ? Crypt::decode($cacheHash, Config::get('crypt/system')) : '');
        $isVerified = $decodedHash === $config['meta']['name'] . '_cache_secure_99';
        if (!$activate && !empty($license_data) && isset($license_data['next-check-time'])) {
            if (time() < strtotime($license_data['next-check-time'])) {
                self::$licenseStatus = true;
                return true;
            }
        }

        $retryCount = (isset($license_data['retry-count']) ? (int) $license_data['retry-count'] : 0);
        $documentRoot = realpath($_SERVER['DOCUMENT_ROOT']);
        $currentDir = realpath(__DIR__);

        if (strpos($currentDir, $documentRoot) !== 0) {
            return false;
        }

        $domain = Utility::getDomain();

        if (!$domain) {
            if (isset($_SERVER['HTTP_X_BALANCED_HOST'])) {
                $domain = str_replace('www.', '', $_SERVER['HTTP_X_BALANCED_HOST']);
            }
            else if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
                $domain = str_replace('www.', '', $_SERVER['HTTP_X_FORWARDED_HOST']);
            }
            else if (isset($_SERVER['HTTP_HOST'])) {
                $domain = str_replace('www.', '', $_SERVER['HTTP_HOST']);
            }
            else {
                $domain = str_replace('www.', '', $_SERVER['SERVER_NAME']);
            }
        }

        $directory = __DIR__;

        if (class_exists('UserManager')) {
            $ip = UserManager::GetIP();
        }
        else {
            $ip = static::getClientIP();
        }

        $server_ip = $_SERVER['SERVER_ADDR'];
        if (($server_ip == '127.0.0.1') && isset($_SERVER['HTTP_X_TARGET_IP'])) {
            $server_ip = $_SERVER['HTTP_X_TARGET_IP'];
        }

        $origin = (Utility::isSSL() ? 'https://' : 'http://');
        $entered_url = $origin . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        $entered_url = parse_url($entered_url);
        unset($entered_url['query']);
        $entered_url = $entered_url['scheme'] . '://' . $entered_url['host'] . rtrim($entered_url['path'], '/');
        $referer_url = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');

        if ($referer_url) {
            $referer_url = parse_url($referer_url);
            unset($referer_url['query']);
            $referer_url = $referer_url['scheme'] . '://' . $referer_url['host'] . rtrim($referer_url['path'], '/');
        }

        $parameters = ['domain' => $domain, 'server_ip' => $server_ip, 'user_ip' => $ip, 'entered_url' => $entered_url, 'referer_url' => $referer_url, 'directory' => $directory];
        $address = 'https://fononline.net/license/checking/d153d7b91000f4b1509484fb3b896d03/305?' . http_build_query($parameters);
        $resultErr = false;
        if (!file_exists($licenseFile) || empty($license_data)) {
            $isOldInstall = 86400 < (time() - $createdAt);
            $isFirstMigration = !isset($config['settings']['cache_hash']);
            if ($isOldInstall || $isVerified) {
                if (!$isFirstMigration) {
                    $result = self::useLicenseCurl($address, $resultErr, true);

                    if ($result['status'] !== 'success') {
                        self::$licenseStatus = false;
                        $this->error = self::$licenseError = 'Güvenlik doğrulaması yapılamadı. Lütfen internet bağlantınızı kontrol edin.';
                        return false;
                    }
                }
            }
        }

        if (!isset($result)) {
            $result = self::useLicenseCurl($address, $resultErr, true);
        }

        if ($result['status'] !== 'success') {
            Modules::save_log('Addons', __CLASS__, __FUNCTION__, $parameters, $address, $result);
            $isHardError = ($result['message'] === 'ERROR') || $result['status'] == 'license_error';

            if ($isHardError) {
                self::setConfigVerified(false);
                $report = self::useLicenseCurl('https://fononline.net/license/error?user_ip=' . $ip, $resultErr);
                $rawError = $report['message'] ?: ($this->lang['license_error_message'] ?? 'Geçerli bir lisansınız yok.');
                $errBody = static::getBodyFromCurlResponse($rawError);

                if (!$errBody) {
                    $errBody = $rawError;
                }

                $this->error = self::$licenseError = $errBody;
                $nextCheckTime = date('Y-m-d H:i:s', strtotime('+1 day'));
                $gracePeriodEnd = date('Y-m-d H:i:s');
                $retryCount = 0;
                self::$licenseStatus = false;
            }
            else {
                ++$retryCount;

                if ($retryCount <= 8) {
                    $nextCheckTime = date('Y-m-d H:i:s', strtotime('+3 hours'));
                    self::$licenseStatus = true;
                    $gracePeriodEnd = $nextCheckTime;
                    $rawError = $resultErr ?: ($this->lang['license_error_curl'] ?? 'Bağlantı sorunu, yeniden deneniyor.');
                }
                else {
                    $nextCheckTime = date('Y-m-d H:i:s', strtotime('+3 hours'));
                    $gracePeriodEnd = date('Y-m-d H:i:s');
                    self::$licenseStatus = false;
                    $rawError = $this->lang['license_error_timeout'] ?? 'Lisans sunucusuna ulaşılamadı. Lütfen sunucunuzun dış bağlantılarını kontrol edin.';
                }

                $errBody = static::getBodyFromCurlResponse($rawError);

                if (!$errBody) {
                    $errBody = $rawError;
                }

                $this->error = self::$licenseError = $errBody;
            }

            $checkFileData = self::cryptChip('encrypt', Utility::jencode(['last-check-time' => date('Y-m-d H:i:s'), 'next-check-time' => $nextCheckTime, 'license-status' => self::$licenseStatus, 'grace-period-end' => $gracePeriodEnd, 'license-error' => $this->error, 'retry-count' => $retryCount]), 'a2dNeVRxQlJxaGpTUVNUUTZiT2xFM0VyeUJLYVF5YWIvQWtXLytQNTFiK01NR0prL2ZVSmgwTyt3dGhZYkJOdw==');
            FileManager::file_write(__DIR__ . DS . 'LICENSE', $checkFileData);
            self::getLicenseFileData(true);
            return self::$licenseStatus;
        }
        if (isset($this) && $this instanceof self) {
            $set_config = $this->config;
            $rawValue = $set_config['meta']['name'] . '_cache_secure_99';
            $set_config['settings']['cache_hash'] = Crypt::encode($rawValue, Config::get('crypt/system'));
            $this->save_config($set_config);
            $this->config = $set_config;
        }
        else {
            self::setConfigVerified(true);
        }

        $checkFileData = self::cryptChip('encrypt', Utility::jencode(['last-check-time' => date('Y-m-d H:i:s'), 'next-check-time' => date('Y-m-d H:i:s', strtotime('+1 month')), 'license-status' => true, 'retry-count' => 0]), 'a2dNeVRxQlJxaGpTUVNUUTZiT2xFM0VyeUJLYVF5YWIvQWtXLytQNTFiK01NR0prL2ZVSmgwTyt3dGhZYkJOdw==');
        FileManager::file_write(__DIR__ . DS . 'LICENSE', $checkFileData);
        self::getLicenseFileData(true);
        self::$licenseStatus = true;
        self::$licenseError = '';
        return true;
    }

    private static function getLicenseFileData($reload = false)
    {
        if ($reload || !static::$licenseTempFile) {
            if (!file_exists(__DIR__ . DS . 'LICENSE')) {
                return false;
            }

            $checkingFileData = FileManager::file_read(__DIR__ . DS . 'LICENSE');

            if ($checkingFileData) {
                $checkingFileData = self::cryptChip('decrypt', $checkingFileData, 'a2dNeVRxQlJxaGpTUVNUUTZiT2xFM0VyeUJLYVF5YWIvQWtXLytQNTFiK01NR0prL2ZVSmgwTyt3dGhZYkJOdw==');

                if ($checkingFileData) {
                    static::$licenseTempFile = Utility::jdecode($checkingFileData, true);
                    return static::$licenseTempFile;
                }
            }
        }
        else {
            return static::$licenseTempFile;
        }

        return false;
    }

    private static function cryptChip($action, $string, $salt = '')
    {
        if ($salt != 'a2dNeVRxQlJxaGpTUVNUUTZiT2xFM0VyeUJLYVF5YWIvQWtXLytQNTFiK01NR0prL2ZVSmgwTyt3dGhZYkJOdw==') {
            return false;
        }

        $key = '0|.%J.MF4AMT$(.VU1J' . $salt . 'O1SbFd$|N83JG' . str_replace('www.', '', $_SERVER['SERVER_NAME']) . '.~&/-_f?fge&';
        $output = false;
        $encrypt_method = 'AES-256-CBC';

        if (is_null($key)) {
            $secret_key = 'NULL';
        }
        else {
            $secret_key = $key;
        }

        $secret_iv = 'JxaGpTUVNUUTZiT2';
        $key = hash('sha256', $secret_key);
        $iv = substr(hash('sha256', $secret_iv), 0, 16);

        if ($action === 'encrypt') {
            $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
            $output = base64_encode($output);
        }
        else if ($action === 'decrypt') {
            $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
        }

        return $output;
    }

    private static function getClientIP()
    {
        $ipKeys = ['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];

        foreach ($ipKeys as $key) {
            if (!empty($_SERVER[$key])) {
                $ipList = preg_split('/[\\s,]+/', $_SERVER[$key]);

                foreach ($ipList as $ip) {
                    if (filter_var($ip, FILTER_VALIDATE_IP)) {
                        return $ip;
                    }
                }
            }
        }

        return '0.0.0.0';
    }

    private static function useLicenseCurl($address, &$error_msg, $check = false)
    {
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => $address,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 3,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 20,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'GET',
            CURLOPT_HEADER => true,
            CURLOPT_NOBODY => false,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_USERAGENT => 'FonPageBuilder-License-Checker/2.0',
            CURLOPT_RESOLVE => ['fononline.net:443:18.102.222.10']
        ]);
        $response = curl_exec($curl);
        $errNo = curl_errno($curl);
        $error = curl_error($curl);

        if ($errNo) {
            $error_msg = 'Error Code: ' . $errNo . ' - ' . $error;
            curl_close($curl);
            return ['status' => 'timeout', 'code' => 'cURL', 'errno' => $errNo, 'message' => $error_msg];
        }

        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
        $body = trim(substr($response, $header_size));

        if (!mb_check_encoding($body, 'UTF-8')) {
            $body = mb_convert_encoding($body, 'UTF-8', 'ISO-8859-9');
        }

        curl_close($curl);

        if ($httpCode == 200) {
            if ($check) {
                if ($body === 'OK') {
                    return ['status' => 'success', 'code' => $httpCode, 'message' => $body];
                }
                else {
                    return ['status' => 'license_error', 'code' => $httpCode, 'message' => $body];
                }
            }

            return ['status' => 'error', 'code' => $httpCode, 'message' => $body];
        }
        else if (400 <= $httpCode) {
            return ['status' => 'server_error', 'code' => $httpCode, 'message' => $body];
        }

        return ['status' => 'error', 'code' => $httpCode, 'message' => 'Unknown License Control Response'];
    }

    private static function getBodyFromCurlResponse($html)
    {
        if (empty($html)) {
            return '';
        }

        $doc = new DOMDocument();
        libxml_use_internal_errors(true);
        $utf8_header = '<?xml encoding="utf-8" ?>';
        $doc->loadHTML($utf8_header . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOERROR | LIBXML_NOWARNING);
        libxml_clear_errors();
        $body = $doc->getElementsByTagName('body')->item(0);

        if (!$body) {
            $text = $doc->saveHTML();
        }
        else {
            $text = $doc->saveHTML($body);
        }

        $text = strip_tags($text);
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
        $text = preg_replace('/\\s+/', ' ', $text);
        return trim($text);
    }

    public function isLicenseValid(): bool
    {
        $licenseData = self::getLicenseFileData();
        if (isset($licenseData['grace-period-end']) && time() < strtotime($licenseData['grace-period-end'])) {
            return true;
        }

        return self::$licenseStatus === true;
    }

    private static function setConfigVerified($status = true)
    {
        $configPath = __DIR__ . DS . 'config.php';

        if (!file_exists($configPath)) {
            return false;
        }

        $config = include $configPath;
        $rawValue = $config['meta']['name'] . '_cache_secure_99';
        $hashValue = ($status ? Crypt::encode($rawValue, Config::get('crypt/system')) : '');
        if (isset($config['settings']['cache_hash']) && $hashValue === $config['settings']['cache_hash']) {
            return true;
        }

        $config['settings']['cache_hash'] = $hashValue;
        $export = Utility::array_export($config, ['pwith' => true]);
        return FileManager::file_write($configPath, $export);
    }

    public function create_error($error = '')
    {
        if ($error) {
            Helper::Load(['Events']);
            return Events::create([
                'type'     => 'info',
                'owner'    => 'system',
                'owner_id' => '0',
                'name'     => 'module-addon-error',
                'data'     => ['name' => __CLASS__, 'message' => $error]
            ]);
        }

        return false;
    }

    private function disableAddon()
    {
        $config = $this->config;
        $config['status'] = 0;
        FileManager::file_write(__DIR__ . DS . 'config.php', Utility::array_export($config, ['pwith' => true]));
        return true;
    }

    public function upgrade()
    {
        if (version_compare($this->version, $this->config['meta']['version'], '>')) {
            $set_config = $this->config;
            if (isset($set_config['created_at']) && $set_config['created_at'] == 1693916240) {
                $set_config['created_at'] = time();
            }

            $set_config['meta']['version'] = $this->version;
            $this->save_config($set_config);
            $this->config = $set_config;
            $dbPrefix = Config::get('database/prefix');
            $tables = [$dbPrefix . 'categories' => 'mtime', $dbPrefix . 'pages' => 'mtime', $dbPrefix . 'knowledgebase' => 'mtime', $dbPrefix . 'fonpagebuilder' => 'mtime'];

            foreach ($tables as $table => $column) {
                $checkColumn = WDB::query('SHOW COLUMNS FROM `' . $table . '` LIKE \'' . $column . '\'')->rowCount();

                if ($checkColumn == 0) {
                    WDB::query('ALTER TABLE `' . $table . '` ADD COLUMN `' . $column . '` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;');
                }
            }

            $tblSuggestions = $dbPrefix . 'fon_ai_domain_suggestions';

            if (!WDB::hasTable($tblSuggestions)) {
                $sql = 'CREATE TABLE IF NOT EXISTS `' . $tblSuggestions . '` (' . "\r\n" . '                    `id`          INT AUTO_INCREMENT PRIMARY KEY,' . "\r\n" . '                    `sorgu_hash`  CHAR(32)     NOT NULL,' . "\r\n" . '                    `user_query`  TEXT         NOT NULL,' . "\r\n" . '                    `engine`      VARCHAR(30)  NOT NULL DEFAULT \'\',' . "\r\n" . '                    `model`       VARCHAR(120) NOT NULL DEFAULT \'\',' . "\r\n" . '                    `lang`        CHAR(5)      NOT NULL DEFAULT \'\',' . "\r\n" . '                    `tlds`        VARCHAR(255) NOT NULL DEFAULT \'\',' . "\r\n" . '                    `ai_response` JSON         NOT NULL,' . "\r\n" . '                    `created_at`  TIMESTAMP    DEFAULT CURRENT_TIMESTAMP,' . "\r\n" . '                    FULLTEXT KEY `ft_query`   (`user_query`),' . "\r\n" . '                    INDEX        `idx_hash`   (`sorgu_hash`),' . "\r\n" . '                    INDEX        `idx_filter` (`engine`, `lang`)' . "\r\n" . '                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';

                if (!WDB::exec($sql)) {
                    $this->create_error = 'fon_ai_domain_suggestions veritabanı tablosu oluşturulamadı.';
                }
            }

            $tblStats = $dbPrefix . 'fon_ai_stats';

            if (!WDB::hasTable($tblStats)) {
                $sql = 'CREATE TABLE IF NOT EXISTS `' . $tblStats . '` (' . "\r\n" . '                    `id`                INT AUTO_INCREMENT PRIMARY KEY,' . "\r\n" . '                    `user_ip`           VARCHAR(45)   NOT NULL,' . "\r\n" . '                    `engine`            VARCHAR(30)   NOT NULL DEFAULT \'\',' . "\r\n" . '                    `model`             VARCHAR(120)  NOT NULL DEFAULT \'\',' . "\r\n" . '                    `prompt_tokens`     INT           NOT NULL DEFAULT 0,' . "\r\n" . '                    `completion_tokens` INT           NOT NULL DEFAULT 0,' . "\r\n" . '                    `total_tokens`      INT           NOT NULL DEFAULT 0,' . "\r\n" . '                    `estimated_cost`    DECIMAL(15,10) NOT NULL DEFAULT 0.0000000000,' . "\r\n" . '                    `cache_hit`         TINYINT(1)    NOT NULL DEFAULT 0,' . "\r\n" . '                    `similar_hit`       TINYINT(1)    NOT NULL DEFAULT 0,' . "\r\n" . '                    `created_at`        TIMESTAMP     DEFAULT CURRENT_TIMESTAMP,' . "\r\n" . '                    INDEX `idx_created` (`created_at`),' . "\r\n" . '                    INDEX `idx_engine`  (`engine`)' . "\r\n" . '                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';

                if (!WDB::exec($sql)) {
                    $this->create_error = 'fon_ai_stats veritabanı tablosu oluşturulamadı.';
                }
            }
        }

        return true;
    }

    private static function logLicense($message)
    {
        $logFile = __DIR__ . '/license_debug.log';
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = '[' . $timestamp . '] [IP: ' . $_SERVER['REMOTE_ADDR'] . '] [URL: ' . $_SERVER['REQUEST_URI'] . ('] ' . $message) . PHP_EOL;
        file_put_contents($logFile, $logEntry, FILE_APPEND);
    }

    private static function diffDay($start = '', $end = '')
    {
        $dStart = new DateTime($start);
        $dEnd = new DateTime($end);
        $dDiff = $dStart->diff($dEnd);
        return $dDiff->days;
    }

    private static function siteMapCategoryRoute($id, $lang)
    {
        $hierarchy = [];
        $query = WDB::select('c.id, c.parent, cl.route');
        $query->from('categories c');
        $query->join('INNER', 'categories_lang cl', 'cl.owner_id = c.id');
        $query->where('c.type', '=', 'products', '&&');
        $query->where('cl.lang', '=', $lang, '&&');
        $query->where('c.id', '=', $id);
        $category = ($query->build() ? $query->getAssoc() : false);

        while ($category) {
            array_unshift($hierarchy, $category['route']);

            if ($category['parent'] == 0) {
                break;
            }

            $query = WDB::select('c.id, c.parent, cl.route');
            $query->from('categories c');
            $query->join('INNER', 'categories_lang cl', 'cl.owner_id = c.id');
            $query->where('c.id', '=', $category['parent'], '&&');
            $query->where('cl.lang', '=', $lang);
            $category = $query->build(true)->getAssoc();
        }

        if (2 < count($hierarchy)) {
            $hierarchy = array_slice($hierarchy, -2, 2, true);
        }

        return $hierarchy;
    }

    public function save_fields($fields = [])
    {
        return $fields;
    }

    public function activate()
    {
        $set_config = $this->config;
        if (isset($set_config['created_at']) && $set_config['created_at'] == 1693916240) {
            $set_config['created_at'] = time();
            $this->save_config($set_config);
            $this->config = $set_config;
        }

        $licenced = $this->runLicenseCheck(true);

        if (!$licenced) {
            return false;
        }

        if (!file_exists($this->imageFolder)) {
            @mkdir($this->imageFolder, 511, true);
            @touch($this->imageFolder . DS . 'index.html');
        }

        $operation = WDB::exec('CREATE TABLE IF NOT EXISTS `fonpagebuilder` (' . "\r\n\t\t\t\t" . '  `id` int(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,' . "\r\n\t\t\t\t" . '  `name` varchar(255) NOT NULL,' . "\r\n\t\t\t\t" . '  `type` varchar(100) NOT NULL,' . "\r\n\t\t\t\t" . '  `type_id` int(11) NOT NULL DEFAULT 0,' . "\r\n\t\t\t\t" . '  `page_options` text,' . "\r\n\t\t\t\t" . '  `page_content` longtext,' . "\r\n\t\t\t\t" . '  `page_style` text DEFAULT NULL,' . "\r\n\t\t\t\t" . '  `status` tinyint(1) NOT NULL DEFAULT 1,' . "\r\n\t\t\t\t" . '  `ctime` datetime NOT NULL DEFAULT current_timestamp(),' . "\r\n\t\t\t\t" . '  `mtime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP' . "\r\n\t\t\t\t" . ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;' . "\r\n\t\t\t\t" . 'CREATE TABLE IF NOT EXISTS `fonpagebuilder_saved` (' . "\r\n\t\t\t\t" . '  `id` int(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,' . "\r\n\t\t\t\t" . '  `name` varchar(255) NOT NULL,' . "\r\n\t\t\t\t" . '  `type` varchar(100) NOT NULL,' . "\r\n\t\t\t\t" . '  `page_content` text DEFAULT NULL' . "\r\n\t\t\t\t" . ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;' . "\r\n\t\t\t");

        if (!$operation) {
            $this->error = $this->lang['database_not_created'] ?? 'Veritabanı oluşturulamadı: ';
            return false;
        }

        return true;
    }

    public function deactivate()
    {
        $set = ['status' => 0];
        $operation = Models::$init->db->update('fonpagebuilder');
        $operation->set($set);
        $operation->where('status', '=', '1');
        $save = $operation->save();
        return true;
    }
 

Graves

Graves

Karanlık Özgürlüktür
Moderator
9 Eki 2024
10,630 Mesaj
TIM Görevleri
2

Aktiflik

Seviye

Deneyim

TIM / GÖREV:

@N0STR4 Datawise 1.0.9.1 surum icinde theme.php dosyasını cözdüm ama diyer modul cözdüm ama biraz ugraşın diye paylaşmıyorum tama calıştırmak icin FonPageBuilder icinde lisans mekanizması var theme icinde lisans mekanızması yok @Graves şifreli 3 dosyayı sana yolladım zaten istersen paylaş kırabilen varsa kırsın​

PHP:
<?php

class Datawise_Theme
{
    public $name = 'Datawise';
    public $error = null;
    public $db_prefix = null;
    public $lang = null;
    public $language = null;
    public $languages = null;
    public array $config = [];
    private array $assets = [];
    private array $styles = [];
    private array $scripts = [];
    private array $headerCodes = [];
    private static $builderConfig = [];
    private static $lcpHandled = false;

    public function __construct()
    {
        if (!$this->languages) {
            $this->languages = View::$init->theme_language_loader($this->name);
        }

        if (!$this->language) {
            $this->language = View::$init->theme_lang(Language::selected(), $this->languages);
        }

        if (!$this->lang) {
            $this->lang = Language::selected();
        }

        $this->db_prefix = (Config::get('database/prefix') ? Config::get('database/prefix') . '_' : '');
        $this->config = include __DIR__ . DS . 'theme-config.php';
        self::$builderConfig = Modules::Config('Addons', 'FonPageBuilder');
        $this->checkAndUpdateVersion();

        if (DEMO_MODE) {
            $headerType = Cookie::get('fon_header_type');

            if (isset($_GET['setHeaderType'])) {
                $setHeaderType = $_GET['setHeaderType'];
                Cookie::set('fon_header_type', $setHeaderType ?: 'header');
                $headerType = $setHeaderType;
            }

            Config::set('theme', ['header-type' => $headerType ?: 'header']);
            $headerStyle = Cookie::get('fon_header_style');

            if (isset($_GET['setHeaderStyle'])) {
                $setHeaderStyle = $_GET['setHeaderStyle'];
                Cookie::set('fon_header_style', $setHeaderStyle ?: 'header_compact');
                $headerStyle = $setHeaderStyle;
            }

            Config::set('theme', ['header_style' => $headerStyle ?: 'header_compact']);
            $primaryColor = Cookie::get('fon_primary_color');

            if (isset($_GET['setPrimaryColor'])) {
                $setPrimaryColor = $_GET['setPrimaryColor'];
                Cookie::set('fon_primary_color', $setPrimaryColor ?: Config::get('theme/color1'));
                $primaryColor = $setPrimaryColor;
            }

            Config::set('theme', ['color1' => ltrim($primaryColor, '#') ?: Config::get('theme/color1')]);
        }
    }

    public function router(array $params = []): mixed
    {
        $raw = implode('/', $params);
        $page = Filter::folder((isset($params[0]) ? $params[0] : ''));
        if (($params[0] ?? false) && $params[1] ?? false && file_exists(__DIR__ . DS . 'pages' . DS . Filter::folder($params[0] ?? false) . DS . Filter::folder($params[1] ?? false) . '.php')) {
            return ['include_file' => __DIR__ . DS . 'pages' . DS . Filter::folder($params[0] ?? false) . DS . Filter::folder($params[1] ?? false) . '.php'];
        }
        else if ($page && file_exists(__DIR__ . DS . 'pages' . DS . $page . '.php')) {
            return ['include_file' => __DIR__ . DS . 'pages' . DS . $page . '.php'];
        }

        return false;
    }

    public function change_settings(): array
    {
        $settings = (isset($this->config['settings']) ? $this->config['settings'] : []);
        $languages = Bootstrap::$lang->rank_list('active');
        $header_type = Filter::init('POST/header_type', 'hclear');
        $clientArea_type = (int) Filter::init('POST/clientArea_type', 'numbers');
        $color1 = ltrim(Filter::init('POST/color1'), '#');
        $color2 = ltrim(Filter::init('POST/color2'), '#');
        $text_color = ltrim(Filter::init('POST/text-color'), '#');
        $link_color = ltrim(Filter::init('POST/link_color'), '#');
        $link_color_hover = ltrim(Filter::init('POST/link_color_hover'), '#');
        $link_color_active = ltrim(Filter::init('POST/link_color_active'), '#');
        $articles_style = (int) Filter::init('POST/articles_style', 'numbers');
        $news_style = (int) Filter::init('POST/news_style', 'numbers');
        $references_style = (int) Filter::init('POST/references_style', 'numbers');
        $software_style = (int) Filter::init('POST/software_style', 'numbers');
        $image_sizes = Filter::init('POST/image_sizes', 'array');
        $sticky_header = (bool) Filter::init('POST/sticky_header', 'numbers');
        $cache_pages = (bool) Filter::init('POST/cache_pages', 'numbers');
        $show_preloader = (bool) Filter::init('POST/show_preloader', 'numbers');
        $preloader = Filter::init('POST/site_preloader', 'hclear');
        $preloader_bg = ltrim(Filter::init('POST/site_preloader_bg'), '#');
        $show_totop = (bool) Filter::init('POST/show_totop', 'numbers');
        $show_contact_info = (bool) Filter::init('POST/show_contact_info', 'numbers');
        $top_notify_show = (bool) Filter::init('POST/top_notify_show', 'numbers');
        $top_notify_text = Filter::init('POST/top_notify_text', 'array');
        $top_notify_show_link = (bool) Filter::init('POST/top_notify_show_link', 'numbers');
        $top_notify_link = Filter::init('POST/top_notify_link', 'array');
        $top_notify_link_text = Filter::init('POST/top_notify_link_text', 'array');
        $top_notify_show_countdown = (bool) Filter::init('POST/top_notify_show_countdown', 'numbers');
        $top_notify_countdown_date = Filter::init('POST/top_notify_countdown_date', 'hclear');
        $top_notify_countdown_time = Filter::init('POST/top_notify_countdown_time', 'hclear');
        $top_notify_show_close = (bool) Filter::init('POST/top_notify_show_close', 'numbers');
        $popup_notify_show = (bool) Filter::init('POST/popup_notify_show', 'numbers');
        $popup_notify_image = Filter::init('POST/popup_notify_image', 'array');
        $popup_notify_show_link = (bool) Filter::init('POST/popup_notify_show_link', 'numbers');
        $popup_notify_link = Filter::init('POST/popup_notify_link', 'array');
        $popup_notify_link_text = Filter::init('POST/popup_notify_link_text', 'array');
        $popup_notify_show_countdown = (bool) Filter::init('POST/popup_notify_show_countdown', 'numbers');
        $popup_notify_countdown_date = Filter::init('POST/popup_notify_countdown_date', 'hclear');
        $popup_notify_countdown_time = Filter::init('POST/popup_notify_countdown_time', 'hclear');
        $popup_notify_display = Filter::init('POST/popup_notify_display', 'hclear');
        $popup_notify_display_when = Filter::init('POST/popup_notify_display_when', 'hclear');
        $right_click = (bool) Filter::init('POST/right_click', 'numbers');
        $header_style = Filter::init('POST/header_style', 'hclear');
        $header_style_align = Filter::init('POST/header_style_align', 'hclear');
        $header_search = (bool) Filter::init('POST/header_search', 'numbers');
        $header_phone = (bool) Filter::init('POST/header_phone', 'numbers');
        $header_email = (bool) Filter::init('POST/header_email', 'numbers');
        $header_social = (bool) Filter::init('POST/header_social', 'numbers');
        $header_lang = (bool) Filter::init('POST/header_lang', 'numbers');
        $header_currency = (bool) Filter::init('POST/header_currency', 'numbers');
        $header_ticket = (bool) Filter::init('POST/header_ticket', 'numbers');
        $header_seperated_sign = (bool) Filter::init('POST/header_seperated_sign', 'numbers');
        $show_whatsapp = (bool) Filter::init('POST/show_whatsapp', 'numbers');
        $whatsapp_number = Filter::init('POST/whatsapp_number', 'hclear');
        $show_phone = (bool) Filter::init('POST/show_phone', 'numbers');
        $seo_gsd_show = (bool) Filter::init('POST/seo_gsd_show', 'numbers');
        $seo_site_name = Filter::init('POST/seo_site_name', 'array');
        $seo_organisation_name = Filter::init('POST/seo_organisation_name', 'array');
        $seo_organisation_country = Filter::init('POST/seo_organisation_country', 'hclear');
        $seo_organisation_city = Filter::init('POST/seo_organisation_city', 'hclear');
        $seo_organisation_region = Filter::init('POST/seo_organisation_region', 'hclear');
        $seo_organisation_address = Filter::init('POST/seo_organisation_address', 'hclear');
        $seo_organisation_postal_code = Filter::init('POST/seo_organisation_postal_code', 'hclear');
        $seo_organisation_price_min = (int) Filter::init('POST/seo_organisation_price_min', 'numbers');
        $seo_organisation_price_max = (int) Filter::init('POST/seo_organisation_price_max', 'numbers');
        $seo_organisation_price_currency = (int) Filter::init('POST/seo_organisation_price_currency', 'numbers');
        $seo_organisation_rating_value = Filter::init('POST/seo_organisation_rating_value', 'hclear');
        $seo_organisation_rating_count = (int) Filter::init('POST/seo_organisation_rating_count', 'numbers');
        $fonts = Filter::init('POST/fonts', 'array');
        $external_login = (bool) Filter::init('POST/external_login', 'numbers');
        $use_cdn = (bool) Filter::init('POST/use_cdn', 'numbers');
        $package_style = (int) Filter::init('POST/package_style', 'numbers');
        $order_steps_monthly_price = (int) Filter::init('POST/order_steps_monthly_price', 'numbers');
        $footer_bg_image = Filter::init('POST/footer_bg_image', 'hclear');
        $show_footer_home_newsletter = (bool) Filter::init('POST/show_footer_home_newsletter', 'numbers');
        $show_footer_social = (bool) Filter::init('POST/show_footer_social', 'numbers');
        $show_secure_and_payment_icons = (bool) Filter::init('POST/show_secure_and_payment_icons', 'numbers');
        $footer_copyright_text = Filter::init('POST/footer_copyright_text', 'array');
        $enable_lazy_loading = (bool) Filter::init('POST/enable_lazy_loading', 'numbers');
        $google_analytics_id = Filter::init('POST/google_analytics_id', 'hclear');
        $google_ads_id = Filter::init('POST/google_ads_id', 'hclear');
        $google_conversion_id = Filter::init('POST/google_conversion_id', 'hclear');
        $facebook_pixel_id = Filter::init('POST/facebook_pixel_id', 'hclear');
        $google_tm_id = Filter::init('POST/google_tm_id', 'hclear');
        $fb_pixel_via_gtm = (bool) Filter::init('POST/fb_pixel_via_gtm', 'numbers');

        if ($header_type != $settings['header-type']) {
            $settings['header-type'] = $header_type;
        }

        if ($header_search != $settings['header_search']) {
            $settings['header_search'] = $header_search;
        }

        if ($header_phone != $settings['header_phone']) {
            $settings['header_phone'] = $header_phone;
        }

        if ($header_email != $settings['header_email']) {
            $settings['header_email'] = $header_email;
        }

        if ($header_social != $settings['header_social']) {
            $settings['header_social'] = $header_social;
        }

        if ($header_lang != $settings['header_lang']) {
            $settings['header_lang'] = $header_lang;
        }

        if ($header_currency != $settings['header_currency']) {
            $settings['header_currency'] = $header_currency;
        }

        if ($header_ticket != $settings['header_ticket']) {
            $settings['header_ticket'] = $header_ticket;
        }

        if ($header_seperated_sign != $settings['header_seperated_sign']) {
            $settings['header_seperated_sign'] = $header_seperated_sign;
        }

        if ($footer_bg_image != $settings['footer_bg_image']) {
            $settings['footer_bg_image'] = $footer_bg_image;
        }

        if ($show_footer_home_newsletter != $settings['show_footer_home_newsletter']) {
            $settings['show_footer_home_newsletter'] = $show_footer_home_newsletter;
        }

        if ($show_footer_social != $settings['show_footer_social']) {
            $settings['show_footer_social'] = $show_footer_social;
        }

        if ($show_secure_and_payment_icons != $settings['show_secure_and_payment_icons']) {
            $settings['show_secure_and_payment_icons'] = $show_secure_and_payment_icons;
        }

        if ($clientArea_type != $settings['clientArea-type']) {
            $settings['clientArea-type'] = $clientArea_type;
        }

        if ($color1 != $settings['color1']) {
            $settings['color1'] = $color1;
            $settings['meta-color'] = '#' . $color1;
        }

        if ($color2 != $settings['color2']) {
            $settings['color2'] = $color2;
        }

        if ($text_color != $settings['text-color']) {
            $settings['text-color'] = $text_color;
        }

        if ($link_color != $settings['link_color']) {
            $settings['link_color'] = $link_color;
        }

        if ($link_color_hover != $settings['link_color_hover']) {
            $settings['link_color_hover'] = $link_color_hover;
        }

        if ($link_color_active != $settings['link_color_active']) {
            $settings['link_color_active'] = $link_color_active;
        }

        if ($articles_style != $settings['articles_style']) {
            $settings['articles_style'] = $articles_style;
        }

        if ($news_style != $settings['news_style']) {
            $settings['news_style'] = $news_style;
        }

        if ($references_style != $settings['references_style']) {
            $settings['references_style'] = $references_style;
        }

        if ($software_style != $settings['software_style']) {
            $settings['software_style'] = $software_style;
        }

        if ($sticky_header != $settings['sticky_header']) {
            $settings['sticky_header'] = $sticky_header;
        }

        if ($cache_pages != $settings['cache_pages']) {
            $settings['cache_pages'] = $cache_pages;
        }

        if ($show_preloader != $settings['show_preloader']) {
            $settings['show_preloader'] = $show_preloader;
        }

        if ($preloader != $settings['site_preloader']) {
            $settings['site_preloader'] = $preloader;
        }

        if ($preloader_bg != $settings['site_preloader_bg']) {
            $settings['site_preloader_bg'] = $preloader_bg;
        }

        if ($show_totop != $settings['show_totop']) {
            $settings['show_totop'] = $show_totop;
        }

        if ($show_contact_info != $settings['show_contact_info']) {
            $settings['show_contact_info'] = $show_contact_info;
        }

        if ($external_login != $settings['external_login']) {
            $settings['external_login'] = $external_login;
        }

        if ($use_cdn != $settings['use_cdn']) {
            $settings['use_cdn'] = $use_cdn;
        }

        if ($package_style != $settings['package_style']) {
            $settings['package_style'] = $package_style;
        }

        if ($enable_lazy_loading != $settings['enable_lazy_loading']) {
            $settings['enable_lazy_loading'] = $enable_lazy_loading;
        }

        if ($top_notify_show != $settings['top_notify_show']) {
            $settings['top_notify_show'] = $top_notify_show;
        }

        if ($top_notify_show_link != $settings['top_notify_show_link']) {
            $settings['top_notify_show_link'] = $top_notify_show_link;
        }

        if ($top_notify_show_countdown != $settings['top_notify_show_countdown']) {
            $settings['top_notify_show_countdown'] = $top_notify_show_countdown;
        }

        if ($top_notify_countdown_date != $settings['top_notify_countdown_date']) {
            $settings['top_notify_countdown_date'] = $top_notify_countdown_date;
        }

        if ($top_notify_countdown_time != $settings['top_notify_countdown_time']) {
            $settings['top_notify_countdown_time'] = $top_notify_countdown_time;
        }

        if ($top_notify_show_close != $settings['top_notify_show_close']) {
            $settings['top_notify_show_close'] = $top_notify_show_close;
        }

        if ($popup_notify_show != $settings['popup_notify_show']) {
            $settings['popup_notify_show'] = $popup_notify_show;
        }

        if ($popup_notify_show_link != $settings['popup_notify_show_link']) {
            $settings['popup_notify_show_link'] = $popup_notify_show_link;
        }

        if ($popup_notify_show_countdown != $settings['popup_notify_show_countdown']) {
            $settings['popup_notify_show_countdown'] = $popup_notify_show_countdown;
        }

        if ($popup_notify_countdown_date != $settings['popup_notify_countdown_date']) {
            $settings['popup_notify_countdown_date'] = $popup_notify_countdown_date;
        }

        if ($popup_notify_countdown_time != $settings['popup_notify_countdown_time']) {
            $settings['popup_notify_countdown_time'] = $popup_notify_countdown_time;
        }

        if ($popup_notify_display != $settings['popup_notify_display']) {
            $settings['popup_notify_display'] = $popup_notify_display;
        }

        if ($popup_notify_display_when != $settings['popup_notify_display_when']) {
            $settings['popup_notify_display_when'] = $popup_notify_display_when;
        }

        if ($right_click != $settings['right_click']) {
            $settings['right_click'] = $right_click;
        }

        if ($header_style != $settings['header_style']) {
            $settings['header_style'] = $header_style;
        }

        if ($header_style_align != $settings['header_style_align']) {
            $settings['header_style_align'] = $header_style_align;
        }

        if ($show_whatsapp != $settings['show_whatsapp']) {
            $settings['show_whatsapp'] = $show_whatsapp;
        }

        if ($whatsapp_number != $settings['whatsapp_number']) {
            $settings['whatsapp_number'] = $whatsapp_number;
        }

        if ($show_phone != $settings['show_phone']) {
            $settings['show_phone'] = $show_phone;
        }

        if ($seo_gsd_show != $settings['seo_gsd_show']) {
            $settings['seo_gsd_show'] = $seo_gsd_show;
        }

        if ($seo_organisation_country != $settings['seo_organisation_country']) {
            $settings['seo_organisation_country'] = $seo_organisation_country;
        }

        if ($seo_organisation_city != $settings['seo_organisation_city']) {
            $settings['seo_organisation_city'] = $seo_organisation_city;
        }

        if ($seo_organisation_region != $settings['seo_organisation_region']) {
            $settings['seo_organisation_region'] = $seo_organisation_region;
        }

        if ($seo_organisation_address != $settings['seo_organisation_address']) {
            $settings['seo_organisation_address'] = $seo_organisation_address;
        }

        if ($seo_organisation_postal_code != $settings['seo_organisation_postal_code']) {
            $settings['seo_organisation_postal_code'] = $seo_organisation_postal_code;
        }

        if ($seo_organisation_price_min != $settings['seo_organisation_price_min']) {
            $settings['seo_organisation_price_min'] = $seo_organisation_price_min;
        }

        if ($seo_organisation_price_max != $settings['seo_organisation_price_max']) {
            $settings['seo_organisation_price_max'] = $seo_organisation_price_max;
        }

        if ($seo_organisation_price_currency != $settings['seo_organisation_price_currency']) {
            $settings['seo_organisation_price_currency'] = $seo_organisation_price_currency;
        }

        if ($seo_organisation_rating_value != $settings['seo_organisation_rating_value']) {
            $settings['seo_organisation_rating_value'] = $seo_organisation_rating_value;
        }

        if ($seo_organisation_rating_count != $settings['seo_organisation_rating_count']) {
            $settings['seo_organisation_rating_count'] = $seo_organisation_rating_count;
        }

        if ($order_steps_monthly_price != $settings['order_steps_monthly_price']) {
            $settings['order_steps_monthly_price'] = $order_steps_monthly_price;
        }

        if ($google_analytics_id != $settings['google_analytics_id']) {
            $settings['google_analytics_id'] = $google_analytics_id;
        }

        if ($google_ads_id != $settings['google_ads_id']) {
            $settings['google_ads_id'] = $google_ads_id;
        }

        if ($google_conversion_id != $settings['google_conversion_id']) {
            $settings['google_conversion_id'] = $google_conversion_id;
        }

        if ($facebook_pixel_id != $settings['facebook_pixel_id']) {
            $settings['facebook_pixel_id'] = $facebook_pixel_id;
        }

        if ($google_tm_id != $settings['google_tm_id']) {
            $settings['google_tm_id'] = $google_tm_id;
        }

        if ($fb_pixel_via_gtm != $settings['fb_pixel_via_gtm']) {
            $settings['fb_pixel_via_gtm'] = $fb_pixel_via_gtm;
        }

        foreach ($languages as $language) {
            if ($top_notify_text[$language['key']] != $settings['top_notify_text'][$language['key']]) {
                $settings['top_notify_text'][$language['key']] = $top_notify_text[$language['key']];
            }

            if ($top_notify_link[$language['key']] != $settings['top_notify_link'][$language['key']]) {
                $settings['top_notify_link'][$language['key']] = $top_notify_link[$language['key']];
            }

            if ($top_notify_link_text[$language['key']] != $settings['top_notify_link_text'][$language['key']]) {
                $settings['top_notify_link_text'][$language['key']] = $top_notify_link_text[$language['key']];
            }

            if ($popup_notify_image[$language['key']] != $settings['popup_notify_image'][$language['key']]) {
                $settings['popup_notify_image'][$language['key']] = $popup_notify_image[$language['key']];
            }

            if ($popup_notify_link[$language['key']] != $settings['popup_notify_link'][$language['key']]) {
                $settings['popup_notify_link'][$language['key']] = $popup_notify_link[$language['key']];
            }

            if ($popup_notify_link_text[$language['key']] != $settings['popup_notify_link_text'][$language['key']]) {
                $settings['popup_notify_link_text'][$language['key']] = $popup_notify_link_text[$language['key']];
            }

            if ($seo_site_name[$language['key']] != $settings['seo_site_name'][$language['key']]) {
                $settings['seo_site_name'][$language['key']] = $seo_site_name[$language['key']];
            }

            if ($seo_organisation_name[$language['key']] != $settings['seo_organisation_name'][$language['key']]) {
                $settings['seo_organisation_name'][$language['key']] = $seo_organisation_name[$language['key']];
            }

            if ($footer_copyright_text[$language['key']] != $settings['footer_copyright_text'][$language['key']]) {
                $settings['footer_copyright_text'][$language['key']] = $footer_copyright_text[$language['key']];
            }
        }

        if (!isset($settings['fonts'])) {
            $settings['fonts'] = [];
        }

        foreach ($fonts as $key => $value) {
            if (!isset($settings['fonts'][$key])) {
                $settings['fonts'][$key] = $value;
            }
            else if (!is_array($value)) {
                if ($value != $settings['fonts'][$key]) {
                    $settings['fonts'][$key] = $value;
                }
            }
            else {
                foreach ($value as $subKey => $subValue) {
                    if (!isset($settings['fonts'][$key][$subKey]) || $subValue !== $settings['fonts'][$key][$subKey]) {
                        $settings['fonts'][$key][$subKey] = $subValue;
                    }
                }
            }
        }

        $options = [];
        if ($image_sizes && is_array($image_sizes)) {
            foreach ($image_sizes as $page => $image_size) {
                if ($page == 'page-news') {
                    $pageSettings = Config::get('pictures/page-news');
                }
                else if ($page == 'page-articles') {
                    $pageSettings = Config::get('pictures/page-articles');
                }
                else if ($page == 'page-references') {
                    $pageSettings = Config::get('pictures/page-references');
                    $pageSettings['mockup']['sizing']['width'] = $image_size['sizing'];
                    $pageSettings['mockup']['sizing']['height'] = false;
                    $pageSettings['mockup']['thumb']['width'] = $image_size['thumb'];
                    $pageSettings['mockup']['thumb']['height'] = false;
                }
                else if ($page == 'software') {
                    $pageSettings = Config::get('pictures/software');
                    $pageSettings['mockup']['sizing']['width'] = $image_size['sizing'];
                    $pageSettings['mockup']['sizing']['height'] = false;
                }

                $pageSettings['list']['sizing']['width'] = ($page == 'software' ? $image_size['thumb'] : $image_size['sizing']);
                $pageSettings['list']['sizing']['height'] = false;

                if ($page != 'software') {
                    $pageSettings['list']['thumb']['width'] = $image_size['thumb'];
                    $pageSettings['list']['thumb']['height'] = false;
                }

                $options[$page] = $pageSettings;
            }
        }

        $export = Utility::array_export(Config::set('pictures', $options), ['pwith' => true]);
        FileManager::file_write(CONFIG_DIR . 'pictures.php', $export);
        return $settings;
    }

    private function _fonFastCache(string $key, mixed $data = NULL, int $finalMtime = 0, string $filePrefix = ''): mixed
    {
        $baseDir = (defined('CACHE_DIR') ? CACHE_DIR : (defined('ROOT_DIR') ? ROOT_DIR . 'cache/' : $_SERVER['DOCUMENT_ROOT'] . '/cache/'));
        $dir = $baseDir . 'fonbuilder/';

        if (!is_dir($dir)) {
            @mkdir($dir, 493, true);
            @file_put_contents($dir . 'index.php', '<?php // Silence is golden');
        }

        $prefixPart = ($filePrefix ? $filePrefix . '_' : '');
        $file = $dir . $prefixPart . md5($key) . '.json';

        if ($data !== null) {
            if (isset($data['html']) && !empty($data['html'])) {
                $data['html'] = $this->sanitizeOutputUrls($data['html']);
            }

            $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            return @file_put_contents($file, $json, LOCK_EX) !== false;
        }
        else {
            if (!file_exists($file)) {
                return false;
            }
            if ((0 < $finalMtime) && filemtime($file) < $finalMtime) {
                return false;
            }

            $content = @file_get_contents($file);

            if (!$content) {
                return false;
            }

            $decoded = json_decode($content, true);
            return (is_null($decoded) ? false : $decoded);
        }
    }

    private function _injectFreshData(string $html): string
    {
        $currentTime = Crypt::encode(time(), Config::get('crypt/system'));
        $html = preg_replace('/(<input[^>]+name="form_loaded_at"[^>]+value=["\'])([^"\']*)(["\'])/i', '${1}' . $currentTime . '${3}', $html);
        $html = preg_replace('/(<input[^>]+name="g-recaptcha-response"[^>]+value=["\'])([^"\']*)(["\'])/i', '${1}${3}', $html);

        if (preg_match('/name="(formbuilder_[a-f0-9]{32})"/i', $html, $matches)) {
            $honeypotName = $matches[1];

            if (class_exists('Session')) {
                Session::set('formbuilder_honeypot_name', $honeypotName, true);
            }
        }

        if (preg_match('/name="(formbuilder_[a-f0-9]{32})"/i', $html, $matches)) {
            $honeypotName = $matches[1];

            if (class_exists('Session')) {
                Session::set('formbuilder_honeypot_name', $honeypotName, true);
            }
        }

        if (class_exists('Validation')) {
            $targetForms = [
                'domain-check'     => ['selector' => 'id=["\']checkForm["\']'],
                'cfeedback'        => ['selector' => 'class=["\'][^"\']*cFeedBackForm[^"\']*["\']'],
                'formbuilder_form' => ['selector' => 'class=["\'][^"\']*fon-formbuilder-form[^"\']*["\']']
            ];

            foreach ($targetForms as $tokenKey => $rule) {
                $freshTokenTag = Validation::get_csrf_token($tokenKey);
                $freshTokenValue = '';

                if (preg_match('/value=["\'](.*?)["\']/', $freshTokenTag, $matches)) {
                    $freshTokenValue = $matches[1];
                }

                if ($freshTokenValue) {
                    $pattern = '/(' . $rule['selector'] . '.*?<input[^>]+name=["\'](?:token|csrf_token|_token)["\'][^>]+value=["\'])([^"\']*)(["\'])/is';
                    $html = preg_replace_callback($pattern, function($m) use($freshTokenValue) {
                        return $m[1] . $freshTokenValue . $m[3];
                    }, $html);
                }
            }
        }

        return $html;
    }

    private function _clearFonBuilderCache(): void
    {
        $baseDir = (defined('CACHE_DIR') ? CACHE_DIR : (defined('ROOT_DIR') ? ROOT_DIR . 'cache/' : $_SERVER['DOCUMENT_ROOT'] . '/cache/'));
        $dir = $baseDir . 'fonbuilder/';

        if (is_dir($dir)) {
            $files = glob($dir . '*.json');

            foreach ($files as $file) {
                if (is_file($file)) {
                    @unlink($file);
                }
            }
        }
    }

    private function sanitizeOutputUrls(string $html_content): string
    {
        $currentHost = $_SERVER['HTTP_HOST'] ?? '';

        if (empty($currentHost)) {
            return $html_content;
        }

        $nakedHost = preg_replace('/^www\\./i', '', $currentHost);
        $domains_to_remove = ['https://' . $nakedHost, 'https://www.' . $nakedHost, 'http://' . $nakedHost, 'http://www.' . $nakedHost];

        if (defined('APP_URI')) {
            $domains_to_remove[] = rtrim(APP_URI, '/');
        }

        $domains_to_remove = array_unique($domains_to_remove);
        $clean_html = str_replace($domains_to_remove, '', $html_content);
        return $clean_html;
    }

    public function builderRow(array $pageContent = [], array $pageData = []): string
    {
        $currentCurrency = $pageData['selected_currency'] ?? Config::get('general/currency');
        $currentLang = Language::selected();
        $cacheEnabled = Config::get('theme/cache_pages');
        $pageID = (isset($pageData['builder_id']) ? $pageData['builder_id'] : md5(json_encode($pageContent)));
        $cacheKey = $pageData['page'] . '_' . $pageID . '_' . $currentLang . '_' . $currentCurrency;
        $dbMtime = 0;

        if (isset($pageData['builder_mtime'])) {
            $dbMtime = (is_numeric($pageData['builder_mtime']) ? $pageData['builder_mtime'] : strtotime($pageData['builder_mtime']));
        }

        $currencyMtime = Config::get('cronjobs/tasks/auto-currency-rates/last-run-time');
        $currencyMtime = strtotime($currencyMtime);
        $finalMtime = max($dbMtime, $currencyMtime);
        $filePrefix = 'page_' . $pageID;
        $cachedData = $this->_fonFastCache($cacheKey, NULL, $finalMtime, $filePrefix);
        if ($cachedData !== false && $cacheEnabled) {
            if (isset($cachedData['headerCodes']) && !empty($cachedData['headerCodes'])) {
                foreach ($cachedData['headerCodes'] as $pPage => $pCode) {
                    $this->headerCodes = array_merge($this->headerCodes, $cachedData['headerCodes']);
                }
            }
            if (isset($cachedData['styles']) && !empty($cachedData['styles'])) {
                $this->styles = array_merge($this->styles, $cachedData['styles']);
            }
            if (isset($cachedData['scripts']) && !empty($cachedData['scripts'])) {
                $this->scripts = array_merge($this->scripts, $cachedData['scripts']);
            }
            if (isset($cachedData['assets']) && !empty($cachedData['assets'])) {
                $this->assets = array_unique(array_merge($this->assets, $cachedData['assets']));
            }

            $finalHtml = $cachedData['html'];
            $finalHtml = $this->_injectFreshData($finalHtml);
            return $finalHtml;
        }

        $output = '';
        self::$lcpHandled = false;

        if ($pageContent) {
            foreach ($pageContent as $row_key => $row) {
                if (isset($row->row_hide) && $row->row_hide == '1') {
                    continue;
                }
                $rowBg = (isset($row->background_type) && $row->background_type == 2 && isset($row->bg_image) ? $row->bg_image : '');
                $rowBgPattern = '';
                $rowPatternStyle = '';
                $colPatternStyle = [];
                $rowClasses = ($row->row_section ? $row->row_section_class . ' ' . $row->text_class_id : $row->text_class);
                $rowPatternStyle = $this->handlePatternImages($rowClasses, $pageData['page'], $pageData['tadress'], self::$lcpHandled === false);

                if (self::$lcpHandled === false) {
                    if (!empty($rowBg)) {
                        $this->addPreloadLink($rowBg, $pageData['page']);
                    }
                }

                if ($rowBg) {
                    $rowBgPattern = 'background-image: url(' . self::assetLinkDetermine($rowBg) . ');';
                }
                if (isset($row->cols) && is_array($row->cols)) {
                    foreach ($row->cols as $col_key => $col) {
                        $colClasses = $col->text_class;
                        $colPatternStyle[$col->text_class_id] = $this->handlePatternImages($colClasses, $pageData['page'], $pageData['tadress'], self::$lcpHandled === false);

                        if (self::$lcpHandled === false) {
                            $colBg = (isset($col->background_type) && $col->background_type == 2 && isset($col->bg_image) ? $col->bg_image : '');

                            if (!empty($colBg)) {
                                $this->addPreloadLink($colBg, $pageData['page']);
                            }
                        }
                    }
                }
                $output .= '<section id="' . ($row->row_section && $row->row_section_id ? $row->row_section_id : $row->text_class_id) . '" class="fon-main-section clearfix ' . ($row->row_section ? $row->row_section_class . ' ' . $row->text_class_id : $row->text_class) . ' ' . ((($row->background_type == 2) || $row->background_type == 3) && $row->overlay_type != '' ? 'overflow-hidden' : '') . ' ' . (($row->background_type == 3) && $row->video_type == 'youtube' ? 'fon-external-video-bg' : '') . '" style="' . $rowPatternStyle . ' ' . $rowBgPattern . '">';

                if ($row->background_type == 3) {
                    if ($row->video_type == 'youtube') {
                        $output .= '<div class="fon-background-youtube d-none">' . "\n" . '                            <iframe class="fon-bg-youtube" src="//www.youtube-nocookie.com/embed/' . $row->video_youtube . '?playlist=' . $row->video_youtube . '&iv_load_policy=3&enablejsapi=1&disablekb=1&autoplay=1&controls=0&showinfo=0&rel=0&loop=1&wmode=transparent&widgetid=1&mute=1" frameborder="0" allowfullscreen></iframe>' . "\n" . '                         </div>';
                    }
                    else {
                        $output .= '<div class="fon-background-video">' . "\n" . '                            <video class="fon-bg-video" autoplay muted playsinline loop ' . ($row->video_poster ? 'poster="' . static::assetLinkDetermine($row->video_poster) . '"' : '') . '>' . "\n" . '                                <source src="' . static::assetLinkDetermine($row->video_local) . '" type="video/mp4">' . "\n" . '                            </video>' . "\n" . '                         </div>';
                    }
                }
                if (($row->background_type == 2) || $row->background_type == 3) {
                    if ($row->overlay_type != '') {
                        $output .= '<div class="fon-background-overlay"></div>';
                    }
                }

                $output .= '<div class="' . ($row->row_container_fluid == 1 ? 'container-fluid' : 'container') . ' ' . ($row->row_remove_gutter ? ' g-0' : '') . '">';
                $rowSectionTitle = (isset($row->row_section_title->{$this->lang}) && $row->row_section_title->{$this->lang} ? $row->row_section_title->{$this->lang} : array_values((array) $row->row_section_title)[0] ?? '');
                $rowSectionDesc = (isset($row->row_section_desc->{$this->lang}) && $row->row_section_desc->{$this->lang} ? $row->row_section_desc->{$this->lang} : array_values((array) $row->row_section_desc)[0] ?? '');
                if (isset($row->row_section_title_show) && $row->row_section_title_show && $rowSectionTitle || $rowSectionDesc) {
                    $output .= '<div class="fon-section-title">';

                    if ($rowSectionTitle) {
                        $output .= '<h2 class="fon-section-title-heading">' . self::getPriceHolders($rowSectionTitle) . '</h2>';
                    }

                    if ($rowSectionDesc) {
                        $output .= '<p class="fon-section-title-subheading">' . strip_tags(self::getPriceHolders($rowSectionDesc)) . '</p>';
                    }

                    $output .= '</div>';
                }

                $row_animation = '';

                if ($row->row_animation_effect) {
                    $row_animation .= 'data-aos="' . $row->row_animation_effect . '" ';

                    if ($row->row_animation_offset) {
                        $row_animation .= 'data-aos-offset="' . $row->row_animation_offset . '" ';
                    }

                    if ($row->row_animation_delay) {
                        $row_animation .= 'data-aos-delay="' . $row->row_animation_delay . '" ';
                    }

                    if ($row->row_animation_duration) {
                        $row_animation .= 'data-aos-duration="' . $row->row_animation_duration . '" ';
                    }

                    if ($row->row_animation_transition) {
                        $row_animation .= 'data-aos-easing="' . $row->row_animation_transition . '" ';
                    }

                    if ($row->row_animation_position) {
                        $row_animation .= 'data-aos-anchor-placement="' . $row->row_animation_position . '" ';
                    }
                }
                $output .= '<div class="row ' . $row->text_class . ($row->row_remove_gutter ? ' g-0' : '') . ' ' . (isset($row->row_column_align) && $row->row_column_align ? 'align-items-' . $row->row_column_align : '') . '" ' . $row_animation . '>';

                foreach ($row->cols as $col_key => $col) {
                    $col_animation = '';

                    if ($col->col_animation_effect) {
                        $col_animation .= 'data-aos="' . $col->col_animation_effect . '" ';

                        if ($col->col_animation_offset) {
                            $col_animation .= 'data-aos-offset="' . $col->col_animation_offset . '" ';
                        }

                        if ($col->col_animation_delay) {
                            $col_animation .= 'data-aos-delay="' . $col->col_animation_delay . '" ';
                        }

                        if ($col->col_animation_duration) {
                            $col_animation .= 'data-aos-duration="' . $col->col_animation_duration . '" ';
                        }

                        if ($col->col_animation_transition) {
                            $col_animation .= 'data-aos-easing="' . $col->col_animation_transition . '" ';
                        }

                        if ($col->col_animation_position) {
                            $col_animation .= 'data-aos-anchor-placement="' . $col->col_animation_position . '" ';
                        }
                    }

                    $columnDisplayClasses = self::generateColumnDisplayClassess($col);
                    $thisColStyle = (isset($colPatternStyle[$col->text_class_id]) ? $colPatternStyle[$col->text_class_id] : '');
                    $output .= '<div id="' . $col->text_class_id . '" class="col-' . $col->xs_col . ' col-sm-' . $col->sm_col . ' col-md-' . $col->md_col . ' col-lg-' . $col->lg_col . ' col-xl-' . $col->xl_col . ' ' . ($col->text_class != '' ? $col->text_class : '') . ' ' . (($col->background_type == 2) || $col->background_type == 3 ? 'position-relative' : '') . ' ' . (($col->background_type == 3) && $col->video_type == 'youtube' ? 'fon-external-video-bg' : '') . ' ' . $columnDisplayClasses . '" ' . $col_animation . ' style="' . $thisColStyle . '">';

                    if ($col->background_type == 3) {
                        if ($col->video_type == 'youtube') {
                            $output .= '<div class="fon-background-youtube d-none">' . "\n" . '                                <iframe class="fon-bg-youtube" src="//www.youtube-nocookie.com/embed/' . $col->video_youtube . '?playlist=' . $col->video_youtube . '&iv_load_policy=3&enablejsapi=1&disablekb=1&autoplay=1&controls=0&showinfo=0&rel=0&loop=1&wmode=transparent&widgetid=1&mute=1" frameborder="0" allowfullscreen></iframe>' . "\n" . '                             </div>';
                        }
                        else {
                            $output .= '<div class="fon-background-video">' . "\n" . '                                <video class="fon-bg-video" autoplay muted playsinline loop ' . ($col->video_poster ? 'poster="' . static::assetLinkDetermine($col->video_poster) . '"' : '') . '>' . "\n" . '                                    <source src="' . static::assetLinkDetermine($col->video_local) . '" type="video/mp4">' . "\n" . '                                </video>' . "\n" . '                             </div>';
                        }
                    }
                    if (($col->background_type == 2) || $col->background_type == 3) {
                        if ($col->overlay_type != '') {
                            $output .= '<div class="fon-background-overlay"></div>';
                        }
                    }
                    $colSectionTitle = (isset($col->col_section_title->{$this->lang}) && $col->col_section_title->{$this->lang} ? $col->col_section_title->{$this->lang} : array_values((array) $col->col_section_title)[0] ?? '');
                    $colSectionDesc = (isset($col->col_section_desc->{$this->lang}) && $col->col_section_desc->{$this->lang} ? $col->col_section_desc->{$this->lang} : array_values((array) $col->col_section_desc)[0] ?? '');
                    if (isset($col->col_section_title_show) && $col->col_section_title_show && $colSectionTitle || $colSectionDesc) {
                        $output .= '<div class="fon-column-title">';

                        if ($colSectionTitle) {
                            $output .= '<h3 class="fon-column-title-heading">' . $colSectionTitle . '</h3>';
                        }

                        if ($colSectionDesc) {
                            $output .= '<p class="fon-column-title-subheading">' . strip_tags($colSectionDesc) . '</p>';
                        }

                        $output .= '</div>';
                    }

                    if ($col->widgets) {
                        foreach ($col->widgets as $widget) {
                            if ($widget->content) {
                                $isWidgetLCP = self::$lcpHandled === false;
                                $output .= $this->callWidget($pageData, $widget, $row, $isWidgetLCP);
                            }
                        }
                    }
                    if (isset($col->rows) && $col->rows) {
                        $row_childs = $col->rows;
                        $output .= $this->builderChildRow($row_childs, $pageData);
                    }

                    $output .= '</div>';
                }

                $output .= '</div>';
                $output .= '</div>';
                $output .= '</section>';
                self::$lcpHandled = true;
            }
        }
        if (!empty($output) && $cacheEnabled) {
            $dataToStore = ['html' => $output, 'headerCodes' => $this->headerCodes, 'styles' => $this->styles, 'assets' => $this->assets, 'scripts' => $this->scripts];
            $this->_fonFastCache($cacheKey, $dataToStore, $finalMtime, $filePrefix);
        }
        else if (!empty($output)) {
            $output = $this->sanitizeOutputUrls($output);
        }

        return $output;
    }

    public function builderChildRow(mixed $row_childs, array $pageData = []): string
    {
        $output = '';

        if ($row_childs) {
            foreach ($row_childs as $rc_row_key => $row_child) {
                if (isset($row_child->row_hide) && $row_child->row_hide == '1') {
                    continue;
                }

                $row_child_animation = '';

                if ($row_child->row_animation_effect) {
                    $row_child_animation .= 'data-aos="' . $row_child->row_animation_effect . '" ';

                    if ($row_child->row_animation_offset) {
                        $row_child_animation .= 'data-aos-offset="' . $row_child->row_animation_offset . '" ';
                    }

                    if ($row_child->row_animation_delay) {
                        $row_child_animation .= 'data-aos-delay="' . $row_child->row_animation_delay . '" ';
                    }

                    if ($row_child->row_animation_duration) {
                        $row_child_animation .= 'data-aos-duration="' . $row_child->row_animation_duration . '" ';
                    }

                    if ($row_child->row_animation_transition) {
                        $row_child_animation .= 'data-aos-easing="' . $row_child->row_animation_transition . '" ';
                    }

                    if ($row_child->row_animation_position) {
                        $row_child_animation .= 'data-aos-anchor-placement="' . $row_child->row_animation_position . '" ';
                    }
                }
                $output .= '<div id="' . $row_child->text_class_id . '" class="row ' . ($row_child->row_remove_gutter ? 'g-0' : '') . ' ' . ($row_child->text_class ?? $row_child->text_class) . ' ' . (($row_child->background_type == 2) || $row_child->background_type == 3 ? 'position-relative' : '') . ' ' . (($row_child->background_type == 3) && $row_child->video_type == 'youtube' ? 'fon-external-video-bg' : '') . ' ' . (isset($row_child->row_column_align) && $row_child->row_column_align ? 'align-items-' . $row_child->row_column_align : '') . '" ' . $row_child_animation . '>';

                if ($row_child->background_type == 3) {
                    if ($row_child->video_type == 'youtube') {
                        $output .= '<div class="fon-background-youtube d-none">' . "\n" . '                            <iframe class="fon-bg-youtube" src="//www.youtube-nocookie.com/embed/' . $row_child->video_youtube . '?playlist=' . $row_child->video_youtube . '&iv_load_policy=3&enablejsapi=1&disablekb=1&autoplay=1&controls=0&showinfo=0&rel=0&loop=1&wmode=transparent&widgetid=1&mute=1" frameborder="0" allowfullscreen></iframe>' . "\n" . '                         </div>';
                    }
                    else {
                        $output .= '<div class="fon-background-video">' . "\n" . '                            <video class="fon-bg-video" autoplay muted playsinline loop ' . ($row_child->video_poster ? 'poster="' . static::assetLinkDetermine($row_child->video_poster) . '"' : '') . '>' . "\n" . '                                <source src="' . static::assetLinkDetermine($row_child->video_local) . '" type="video/mp4">' . "\n" . '                            </video>' . "\n" . '                         </div>';
                    }
                }
                if (($row_child->background_type == 2) || $row_child->background_type == 3) {
                    if ($row_child->overlay_type != '') {
                        $output .= '<div class="fon-background-overlay"></div>';
                    }
                }

                foreach ($row_child->cols as $rc_col_key => $col_child) {
                    $col_child_animation = '';

                    if ($col_child->col_animation_effect) {
                        $col_child_animation .= 'data-aos="' . $col_child->col_animation_effect . '" ';

                        if ($col_child->col_animation_offset) {
                            $col_child_animation .= 'data-aos-offset="' . $col_child->col_animation_offset . '" ';
                        }

                        if ($col_child->col_animation_delay) {
                            $col_child_animation .= 'data-aos-delay="' . $col_child->col_animation_delay . '" ';
                        }

                        if ($col_child->col_animation_duration) {
                            $col_child_animation .= 'data-aos-duration="' . $col_child->col_animation_duration . '" ';
                        }

                        if ($col_child->col_animation_transition) {
                            $col_child_animation .= 'data-aos-easing="' . $col_child->col_animation_transition . '" ';
                        }

                        if ($col_child->col_animation_position) {
                            $col_child_animation .= 'data-aos-anchor-placement="' . $col_child->col_animation_position . '" ';
                        }
                    }

                    $colChildDisplayClasses = self::generateColumnDisplayClassess($col_child);
                    $output .= '<div id="' . $col_child->text_class_id . '" class="col-' . $col_child->xs_col . ' col-sm-' . $col_child->sm_col . ' col-md-' . $col_child->md_col . ' col-lg-' . $col_child->lg_col . ' col-xl-' . $col_child->xl_col . ' ' . ($col_child->text_class != '' ? $col_child->text_class : '') . ' ' . (($col_child->background_type == 2) || $col_child->background_type == 3 ? 'position-relative' : '') . ' ' . (($col_child->background_type == 3) && $col_child->video_type == 'youtube' ? 'fon-external-video-bg' : '') . ' ' . $colChildDisplayClasses . '" ' . $col_child_animation . '>';

                    if ($col_child->background_type == 3) {
                        if ($col_child->video_type == 'youtube') {
                            $output .= '<div class="fon-background-youtube d-none">' . "\n" . '                                <iframe class="fon-bg-youtube" src="//www.youtube-nocookie.com/embed/' . $col_child->video_youtube . '?playlist=' . $col_child->video_youtube . '&iv_load_policy=3&enablejsapi=1&disablekb=1&autoplay=1&controls=0&showinfo=0&rel=0&loop=1&wmode=transparent&widgetid=1&mute=1" frameborder="0" allowfullscreen></iframe>' . "\n" . '                             </div>';
                        }
                        else {
                            $output .= '<div class="fon-background-video">' . "\n" . '                                <video class="fon-bg-video" autoplay muted playsinline loop ' . ($col_child->video_poster ? 'poster="' . static::assetLinkDetermine($col_child->video_poster) . '"' : '') . '>' . "\n" . '                                    <source src="' . static::assetLinkDetermine($col_child->video_local) . '" type="video/mp4">' . "\n" . '                                </video>' . "\n" . '                             </div>';
                        }
                    }
                    if (($col_child->background_type == 2) || $col_child->background_type == 3) {
                        if ($col_child->overlay_type != '') {
                            $output .= '<div class="fon-background-overlay"></div>';
                        }
                    }
                    $colChildSectionTitle = (isset($col_child->col_section_title->{$this->lang}) && $col_child->col_section_title->{$this->lang} ? $col_child->col_section_title->{$this->lang} : array_values((array) $col_child->col_section_title)[0] ?? '');
                    $colChildSectionDesc = (isset($col_child->col_section_desc->{$this->lang}) && $col_child->col_section_desc->{$this->lang} ? $col_child->col_section_desc->{$this->lang} : array_values((array) $col_child->col_section_desc)[0] ?? '');
                    if (isset($col_child->col_section_title_show) && $col_child->col_section_title_show && $colChildSectionTitle || $colChildSectionDesc) {
                        $output .= '<div class="fon-column-title">';

                        if ($colChildSectionTitle) {
                            $output .= '<h3 class="fon-column-title-heading">' . $colChildSectionTitle . '</h3>';
                        }

                        if ($colChildSectionDesc) {
                            $output .= '<p class="fon-column-title-subheading">' . strip_tags($colChildSectionDesc) . '</p>';
                        }

                        $output .= '</div>';
                    }

                    if ($col_child->widgets) {
                        foreach ($col_child->widgets as $child_widget) {
                            if ($child_widget->content) {
                                $output .= $this->callWidget($pageData, $child_widget, $row_child);
                            }
                        }
                    }
                    if (isset($col_child->rows) && $col_child->rows) {
                        $row_childs = $col_child->rows;
                        $output .= $this->builderChildRow($row_childs, $pageData);
                    }

                    $output .= '</div>';
                }

                $output .= '</div>';
            }
        }

        return $output;
    }

    public function callWidget(array $pageData, object $widget, object $row, bool $isLCPCandidate = false): string
    {
        $content = $widget->content;
        $funcWidget = $widget->widget . '_widget';

        if (method_exists($this, $funcWidget)) {
            return $this->{$funcWidget}($content, $widget->module, $pageData, $row, $isLCPCandidate);
        }

        return $this->callCustomWidgetRenderer($widget, $content, $pageData);
    }

    private function callCustomWidgetRenderer(object $widget, mixed $content, array $pageData): string
    {
        $moduleId = (string) ($widget->module ?? '');
        $page = (is_array($pageData) && isset($pageData['page']) && is_string($pageData['page']) ? trim($pageData['page']) : '');
        if (!isset($widget->widget) || !is_string($widget->widget) || $widget->widget === '') {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => '', 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'widget_name_empty'], '');
            return '';
        }

        $safeWidget = $this->sanitizeCustomWidgetName($widget->widget);

        if ($safeWidget === '') {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $widget->widget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'widget_name_invalid'], '');
            return '';
        }

        $rendererFile = $this->resolveCustomWidgetRendererFile($safeWidget);

        if ($rendererFile === '') {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_file_not_found'], '');
            return '';
        }

        if (!$this->isCustomWidgetRendererSafe($rendererFile)) {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_security_check_failed'], '');
            return '';
        }

        require_once $rendererFile;
        $rendererClass = 'FonCustomWidgetRenderer_' . $safeWidget;

        if (!class_exists($rendererClass)) {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_class_not_found'], '');
            return '';
        }

        try {
            $renderMethod = new ReflectionMethod($rendererClass, 'render');
            if (!$renderMethod->isPublic() || !$renderMethod->isStatic()) {
                Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_method_invalid'], '');
                return '';
            }
        }
        catch (ReflectionException $e) {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_reflection_exception'], ['error_message' => $e->getMessage(), 'error_type' => get_class($e)]);
            return '';
        }

        try {
            $html = (string) $rendererClass::render($this, $content, $moduleId, (is_array($pageData) ? $pageData : []));
            return $html;
        }
        catch (Throwable $e) {
            Modules::save_log('Addons', 'FonPageBuilder', 'WidgetRender', ['widget' => $safeWidget, 'module_id' => $moduleId, 'page' => $page, 'status' => 'error'], ['reason' => 'renderer_exception'], ['renderer_class' => $rendererClass, 'error_message' => $e->getMessage(), 'error_code' => $e->getCode(), 'error_type' => get_class($e), 'error_file' => $e->getFile(), 'error_line' => $e->getLine()]);
            return '';
        }
    }

    private function resolveCustomWidgetRendererFile(string $safeWidget): string
    {
        $basePath = realpath(__DIR__ . DS . 'builder' . DS . 'custom-widgets');

        if ($basePath === false) {
            return '';
        }

        $rendererPath = $basePath . DS . $safeWidget . DS . 'renderer.php';

        if (!is_file($rendererPath)) {
            return '';
        }

        $rendererRealPath = realpath($rendererPath);

        if ($rendererRealPath === false) {
            return '';
        }

        return ($this->isPathInsideDirectory($basePath, $rendererRealPath) ? $rendererRealPath : '');
    }

    private function isPathInsideDirectory(string $baseDir, string $path): bool
    {
        $normalizedBase = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $baseDir), DIRECTORY_SEPARATOR);
        $normalizedPath = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR);
        if (($normalizedBase === '') || $normalizedPath === '') {
            return false;
        }

        if ($normalizedPath === $normalizedBase) {
            return true;
        }

        return strpos($normalizedPath, $normalizedBase . DIRECTORY_SEPARATOR) === 0;
    }

    private function isCustomWidgetRendererSafe(string $rendererFile): bool
    {
        static $securityCheckCache = [];

        if (isset($securityCheckCache[$rendererFile])) {
            return $securityCheckCache[$rendererFile];
        }

        $code = @file_get_contents($rendererFile);

        if ($code === false) {
            $securityCheckCache[$rendererFile] = false;
            return false;
        }

        $securityCheckCache[$rendererFile] = !$this->hasForbiddenRendererTokens($code);
        return $securityCheckCache[$rendererFile];
    }

    private function hasForbiddenRendererTokens(string $phpCode): bool
    {
        $tokens = token_get_all($phpCode);
        $forbiddenFunctions = ['eval', 'assert', 'shell_exec', 'exec', 'system', 'passthru', 'proc_open', 'popen'];
        $tokenCount = count($tokens);

        for ($i = 0; $i < $tokenCount; ++$i) {
            $token = $tokens[$i];

            if ($token === '`') {
                return true;
            }

            if (!is_array($token)) {
            }
            else {
                if ($token[0] === T_EVAL) {
                    return true;
                }
                if (($token[0] === T_STRING) && $this->isForbiddenFunctionCall($tokens, $i, $forbiddenFunctions)) {
                    return true;
                }
            }
        }

        return false;
    }

    private function isForbiddenFunctionCall(array $tokens, int $index, array $forbiddenFunctions): bool
    {
        if (!isset($tokens[$index]) || !is_array($tokens[$index])) {
            return false;
        }

        $tokenName = strtolower((string) $tokens[$index][1]);

        if (!in_array($tokenName, $forbiddenFunctions, true)) {
            return false;
        }

        $tokenCount = count($tokens);

        for ($i = $index + 1; $i < $tokenCount; ++$i) {
            $nextToken = $tokens[$i];
            if (is_array($nextToken) && in_array($nextToken[0], [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT], true)) {
            }
            else {
                return $nextToken === '(';
            }
        }

        return false;
    }

    private function sanitizeCustomWidgetName(mixed $widgetName): string
    {
        if (!is_string($widgetName)) {
            return '';
        }

        $name = strtolower(trim($widgetName));

        if ($name === '') {
            return '';
        }

        return (preg_match('/^[a-z][a-z0-9_]*$/', $name) ? $name : '');
    }

    private function accordion_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-accordion-widget ' . ($content->dark_container == 'yes' ? 'dark-container' : '') . ' style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        if (isset($content->items) && is_array($content->items)) {
            $output .= '<div class="accordion" id="accordion-' . $widgetId . '">';

            foreach ($content->items as $key => $item) {
                $output .= '<div class="accordion-item ' . (($content->show_icon == 'yes') && $item->accordion_icon ? 'with-icon' : 'no-icon') . '">';
                $output .= '<div class="accordion-header">';
                $output .= '<a class="accordion-button ' . (($key == 0) && $content->first_open == 'yes' ? '' : 'collapsed') . '" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-' . $widgetId . '-' . $key . '" aria-expanded="' . ($key == 0 ? 'true' : 'false') . '" aria-controls="collapse-' . $widgetId . '-' . $key . '">';
                if (($content->show_icon == 'yes') && $item->accordion_icon) {
                    $output .= '<span class="accordion-icon me-1"><i class="' . $item->accordion_icon . '"></i></span>';
                }

                $accordionTitle = self::getFieldMultilingualText($item->accordion_title ?? NULL, $this->lang, '');
                $output .= $accordionTitle;
                $output .= '</a>';
                $output .= '</div>';
                $output .= '<div id="collapse-' . $widgetId . '-' . $key . '" class="accordion-collapse collapse ' . (($key == 0) && $content->first_open == 'yes' ? 'show' : '') . '" data-bs-parent="#accordion-' . $widgetId . '">';
                $output .= '<div class="accordion-body">';
                $accordionContent = self::getFieldMultilingualText($item->accordion_content ?? NULL, $this->lang, '');
                $output .= $accordionContent;
                $output .= '</div>';
                $output .= '</div>';
                $output .= '</div>';
            }

            $output .= '</div>';
        }

        $output .= '</div>';
        return $output;
    }

    private function alert_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (($content->name_widget_status == 'yes') && isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang}) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';
            if ($content->title_color && $content->alert_type == 'light') {
                $style .= 'color: ' . $content->title_color . ';';
            }

            if ($content->title_margin->top) {
                $style .= 'margin-top: ' . $content->title_margin->top . 'px;';
            }

            if ($content->title_margin->bottom) {
                $style .= 'margin-bottom: ' . $content->title_margin->bottom . 'px;';
            }

            if ($content->title_font) {
                $style .= self::parseFontProperties($content->title_font);
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-alert-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<div class="alert alert-' . $content->alert_type . ' ' . ($content->show_close ? 'alert-dismissible fade show' : '') . ' ' . ($content->show_icon == 'yes' ? 'd-flex align-items-center' : '') . '" role="alert">';
        if (isset($content->show_icon) && $content->show_icon == 'yes') {
            $output .= '<div class="alert-icon me-3"><i class="' . $content->icon . ' fa-2x"></i></div>';
            $output .= '<div class="alert-content">';
        }
        if (isset($content->name_widget_status) && $content->name_widget_status == 'yes' && isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang}) {
            $output .= '<' . $content->heading_selector . ' class="fon-widget-title alert-heading">';
            $output .= $content->name_widget->{$this->lang};
            $output .= '</' . $content->heading_selector . '>';
        }
        if (isset($content->content->{$this->lang}) && $content->content->{$this->lang}) {
            $output .= $content->content->{$this->lang};
        }
        if (isset($content->show_close) && $content->show_close == 'yes') {
            $output .= '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="' . $this->language['text_close'] . '"></button>';
        }
        if (isset($content->show_icon) && $content->show_icon == 'yes') {
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function animated_heading_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $heading_type = (isset($content->heading_type) && $content->heading_type ? $content->heading_type : 'animation');
        $heading_layout = (isset($content->heading_layout) && $content->heading_layout ? $content->heading_layout : 'inline');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $heading_font = (isset($content->heading_font) && $content->heading_font ? $content->heading_font : '');
        $heading_color = (isset($content->heading_color) && $content->heading_color ? $content->heading_color : '#000000');
        $heading_margin = (isset($content->heading_margin) && $content->heading_margin ? $content->heading_margin : '');
        $heading_padding = (isset($content->heading_padding) && $content->heading_padding ? $content->heading_padding : '');
        $heading_align = (isset($content->heading_align) && $content->heading_align ? $content->heading_align : (object) ['xl' => 'left', 'lg' => 'left', 'md' => 'left', 'sm' => 'left', 'xs' => 'left']);
        $heading_align_class = $this->_parseResponsiveBootstrapFlexAligns($heading_align);
        $animated_text_color = (isset($content->animated_text_color) && $content->animated_text_color ? $content->animated_text_color : '#3366FF');
        $animated_text_font = (isset($content->animated_text_font) && $content->animated_text_font ? $content->animated_text_font : '');
        $animation_effect = (isset($content->animation_effect) && $content->animation_effect ? $content->animation_effect : 'blinds');
        $highlight_shape = (isset($content->highlight_shape) && $content->highlight_shape ? $content->highlight_shape : 'circle');
        $shape_color = (isset($content->shape_color) && $content->shape_color ? $content->shape_color : '#3366FF');
        $shape_width = (isset($content->shape_width) && $content->shape_width ? $content->shape_width : '');
        $shape_rounded_edge = (isset($content->shape_rounded_edge) && $content->shape_rounded_edge == 'yes' ? true : false);
        $animation_duration = (isset($content->animation_duration) && $content->animation_duration ? (string) $content->animation_duration : '10');
        $iteration_count = (isset($content->iteration_count) && $content->iteration_count ? (string) $content->iteration_count : '2');
        $heading_before = '';

        if (is_object($content->heading_before)) {
            $heading_before = (isset($content->heading_before->{$this->lang}) && $content->heading_before->{$this->lang} ? $content->heading_before->{$this->lang} : array_values((array) $content->heading_before)[0] ?? '');
        }
        else if (is_string($content->heading_before)) {
            $heading_before = $content->heading_before;
        }

        $name_widget = '';

        if (is_object($content->name_widget)) {
            $name_widget = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        }
        else if (is_string($content->name_widget)) {
            $name_widget = $content->name_widget;
        }

        $heading_after = '';

        if (is_object($content->heading_after)) {
            $heading_after = (isset($content->heading_after->{$this->lang}) && $content->heading_after->{$this->lang} ? $content->heading_after->{$this->lang} : array_values((array) $content->heading_after)[0] ?? '');
        }
        else if (is_string($content->heading_after)) {
            $heading_after = $content->heading_after;
        }

        $animated_text = '';

        if (is_object($content->animated_text)) {
            $animated_text = (isset($content->animated_text->{$this->lang}) && $content->animated_text->{$this->lang} ? $content->animated_text->{$this->lang} : array_values((array) $content->animated_text)[0] ?? '');
        }
        else if (is_string($content->animated_text)) {
            $animated_text = $content->animated_text;
        }

        if ($animated_text) {
            if (str_contains($animated_text, ',')) {
                $animated_text = explode(',', $animated_text);
            }
            else {
                $animated_text = [$animated_text];
            }
        }
        else {
            $animated_text = [];
        }

        $highlight_text = '';

        if (is_object($content->highlight_text)) {
            $highlight_text = (isset($content->highlight_text->{$this->lang}) && $content->highlight_text->{$this->lang} ? $content->highlight_text->{$this->lang} : array_values((array) $content->highlight_text)[0] ?? '');
        }
        else if (is_string($content->highlight_text)) {
            $highlight_text = $content->highlight_text;
        }

        $style = '';
        if ($heading_color || $heading_font) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';

            if ($heading_font) {
                $style .= self::parseFontProperties($heading_font);
            }

            if ($heading_color) {
                $style .= 'color: ' . $heading_color . ';';
            }

            $style .= '}';
        }

        if ($heading_margin) {
            $responsiveItems = [
                '.fon-widget-title' => [
                ['type' => 'margin', 'unit' => '', 'value' => $heading_margin]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }

        if ($heading_padding) {
            $responsiveItems = [
                '.fon-widget-title' => [
                ['type' => 'padding', 'unit' => '', 'value' => $heading_padding]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        if ($animated_text_color || $animated_text_font) {
            $style .= '#' . $widgetId . ' .animated-text, #' . $widgetId . ' .animated-head-highlighted-text{';

            if ($animated_text_font) {
                $style .= self::parseFontProperties($animated_text_font);
            }

            if ($animated_text_color) {
                $style .= 'color: ' . $animated_text_color . ';';
            }

            $style .= '}';
        }
        if (($heading_type == 'highlight') && $shape_color || $shape_width || $shape_rounded_edge) {
            $style .= '#' . $widgetId . ' .animated-head-highlighted-wrap svg path{';

            if ($shape_width) {
                $style .= 'stroke-width: ' . $shape_width . 'px;';
            }

            if ($shape_rounded_edge) {
                $style .= 'stroke-linecap: round;';
                $style .= 'stroke-linejoin: round;';
            }

            if ($shape_color) {
                $style .= 'stroke: ' . $shape_color . ';';
            }

            if ($animation_duration) {
                $style .= '-webkit-animation-duration: ' . $animation_duration . 's;';
                $style .= 'animation-duration: ' . $animation_duration . 's;';
            }

            if ($iteration_count) {
                $style .= '-webkit-animation-iteration-count: ' . $iteration_count . ';';
                $style .= 'animation-iteration-count: ' . $iteration_count . ';';
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isHaveAnimatedText = ($heading_type == 'animation') && $animated_text;

        if ($isHaveAnimatedText) {
            $animated_text_class = 'animated-head-text ';

            if ($animation_effect) {
                switch ($animation_effect) {
                case 'blinds':
                    $animated_text_class .= 'letters animation-blinds';
                    break;
                case 'typing':
                    $animated_text_class .= 'letters type';
                    break;
                case 'flip':
                    $animated_text_class .= 'text-animation-flip';
                    break;
                case 'fade':
                    $animated_text_class .= 'zoom';
                    break;
                case 'loading':
                    $animated_text_class .= 'loading-bar';
                    break;
                case 'scale':
                    $animated_text_class .= 'letters scale';
                    break;
                case 'slide':
                    $animated_text_class .= 'slide';
                    break;
                case 'push':
                    $animated_text_class .= 'push';
                    break;
                case 'wave':
                    $animated_text_class .= 'letters animation-wave';
                    break;
                case 'clip':
                    $animated_text_class .= 'text-clip is-full-width';
                    break;
                default:
                    $animated_text_class .= 'letters type';
                    break;
                }
            }
        }
        $isHaveHighlightText = ($heading_type == 'highlight') && $highlight_text;

        if ($isHaveHighlightText) {
            $highlight_shape_content = '';

            if ($highlight_shape) {
                switch ($highlight_shape) {
                case 'cross':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none" style="z-index: 2">' . "\n" . '                            <path d="M497.4,23.9C301.6,40,155.9,80.6,4,144.4"></path>' . "\n" . '                            <path d="M14.1,27.6c204.5,20.3,393.8,74,467.3,111.7"></path>' . "\n" . '                        </svg>';
                    break;
                case 'circle':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M325,18C228.7-8.3,118.5,8.3,78,21C22.4,38.4,4.6,54.6,5.6,77.6c1.4,32.4,52.2,54,142.6,63.7 c66.2,7.1,212.2,7.5,273.5-8.3c64.4-16.6,104.3-57.6,33.8-98.2C386.7-4.9,179.4-1.4,126.3,20.7">' . "\n\t\t\t\t\t\t" . '</path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'bg-fill':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n" . '                        <path fill="none" stroke="#020202" stroke-width="150" stroke-miterlimit="10" d="M0 75h500"/>' . "\n" . '                        </svg>';
                    break;
                case 'square':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t" . '<path d="M44.22 0c2.46 51.77-2.05 99.72-13.51 143.84 50.37-7.64 316.96-30.55 469.29-5.09-16.41-40.58-21.99-71.11-23.34-127.29C378.38 22.92 97.06 34.37 0 22.92"/>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'scribble-underline':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M9.3,127.3c49.3-3,150.7-7.6,199.7-7.4c121.9,0.4,189.9,0.4,282.3,7.2C380.1,129.6,181.2,130.6,70,139 c82.6-2.9,254.2-1,335.9,1.3c-56,1.4-137.2-0.3-197.1,9"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'diagonal':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none"  style="z-index: 2">' . "\n\t\t\t\t\t\t" . '<path d="M13.5,15.5c131,13.7,289.3,55.5,475,125.5"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'top-bottom-line':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M8.4,143.1c14.2-8,97.6-8.8,200.6-9.2c122.3-0.4,287.5,7.2,287.5,7.2"></path>' . "\n\t\t\t\t\t\t" . '<path d="M8,19.4c72.3-5.3,162-7.8,216-7.8c54,0,136.2,0,267,7.8"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'strikethrough':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none" style="z-index: 2">' . "\n\t\t\t\t\t\t" . '<path d="M3,75h493.5"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'underline':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M7.7,145.6C109,125,299.9,116.2,401,121.3c42.1,2.2,87.6,11.8,87.3,25.7"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'duble-underline':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M5,125.4c30.5-3.8,137.9-7.6,177.3-7.6c117.2,0,252.2,4.7,312.7,7.6"></path>' . "\n\t\t\t\t\t\t" . '<path d="M26.9,143.8c55.1-6.1,126-6.3,162.2-6.1c46.5,0.2,203.9,3.2,268.9,6.4"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'zigzag-underline':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t" . '<path d="M.23 139.83l28.27-19.78 25.43 19.79 28.27-19.77 22.6 19.79 29.68-19.78 25.44 19.79 25.44-19.78 28.27 19.79 26.85-19.77 26.84 19.8 24.04-19.79 24.01 19.8 22.62-19.78 22.61 19.8 22.61-19.78 24.02 19.79 24.03-19.78 24.02 19.8 22.62-19.79 21.19 19.79"/>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                case 'wave':
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M3,146.1c17.1-8.8,33.5-17.8,51.4-17.8c15.6,0,17.1,18.1,30.2,18.1c22.9,0,36-18.6,53.9-18.6 c17.1,0,21.3,18.5,37.5,18.5c21.3,0,31.8-18.6,49-18.6c22.1,0,18.8,18.8,36.8,18.8c18.8,0,37.5-18.6,49-18.6c20.4,0,17.1,19,36.8,19 c22.9,0,36.8-20.6,54.7-18.6c17.7,1.4,7.1,19.5,33.5,18.8c17.1,0,47.2-6.5,61.1-15.6"></path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                default:
                    $highlight_shape_content = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 150" preserveAspectRatio="none">' . "\n\t\t\t\t\t\t" . '<path d="M325,18C228.7-8.3,118.5,8.3,78,21C22.4,38.4,4.6,54.6,5.6,77.6c1.4,32.4,52.2,54,142.6,63.7 c66.2,7.1,212.2,7.5,273.5-8.3c64.4-16.6,104.3-57.6,33.8-98.2C386.7-4.9,179.4-1.4,126.3,20.7">' . "\n\t\t\t\t\t\t" . '</path>' . "\n\t\t\t\t\t" . '</svg>';
                    break;
                }
            }
        }

        $this->addAsset('fon-animated-head');
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-animated-heading-widget ' . ($content->fon_class ?? '') . '">';

        if (DEMO_MODE) {
            $output .= '<h3 class="fs-6 border-bottom py-3 mb-3">' . $name_widget . '</h3>';
        }

        $output .= '<div class="fon-widget-animated-head">';
        $output .= '<' . $heading_selector . ' class="fon-widget-title layout-' . $heading_layout . ' align-items-start align-items-md-center ' . ($isHaveAnimatedText ? $animated_text_class : 'highlighted-text') . ' ' . $heading_align_class . '">';
        $output .= '<span class="animated-head-before-part">' . $heading_before . '</span>';

        if ($isHaveAnimatedText) {
            $output .= '<span class="animated-text-words-wrapper">';

            foreach ($animated_text as $key => $text) {
                $output .= '<span class="animated-text ' . ($key == 0 ? 'is-visible' : '') . '">' . $text . '</span>';
            }

            $output .= '</span>';
        }

        if ($isHaveHighlightText) {
            $output .= '<span class="animated-head-highlighted-wrap">';
            $output .= '<span class="animated-head-highlighted-text shape-' . $highlight_shape . '">' . $highlight_text . '</span>';
            $output .= $highlight_shape_content;
            $output .= '</span>';
        }

        $output .= '<span class="animated-head-after-part">' . $heading_after . '</span>';
        $output .= '</' . $heading_selector . '>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function animated_number_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $desc = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');
        $style = '';
        $style .= '#' . $widgetId . ' .animated-number .number{';
        if (isset($content->number_size) && $content->number_size) {
            $style .= 'font-size:' . $content->number_size . 'px;';
        }
        if (isset($content->number_weight) && $content->number_weight) {
            $style .= 'font-weight:' . $content->number_weight . ';';
        }
        if (isset($content->number_color) && $content->number_color) {
            $style .= 'color:' . $content->number_color . ';';
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .animated-number .number:' . $content->number_prefix_position . '{';
        $style .= 'content: "' . $content->number_prefix . '";';
        $style .= '}';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = '';
        $counterClass = '';
        $counterData = '';
        $counterContent = '';
        $icon_class = (isset($content->icon_class) && $content->icon_class ? $content->icon_class : '');

        if ($content->number_counter_type == 'counter') {
            $counterClass = 'counter counter-number';
            $counterData = 'data-speed="' . ($content->number_animation_speed ?? '7000') . '" data-to="' . $content->number . '"';
            $counterData .= (is_float($content->number) ? ' data-decimal="1"' : '');
        }
        else if ($content->number_counter_type == 'vertical') {
            $counterClass = 'vertical-counter appear ';
            $counterData = 'data-to="' . $content->number . '"';
            $counterNumbers = str_split($content->number);

            foreach ($counterNumbers as $number) {
                $counterContent .= '<span class="vertical-counter-number" data-to="' . $number . '" ><ul class="list-unstyled"><li class="vcn">0</li><li class="vcn">1</li><li class="vcn">2</li><li class="vcn">3</li><li class="vcn">4</li><li class="vcn">5</li><li class="vcn">6</li><li class="vcn">7</li><li class="vcn">8</li><li class="vcn">9</li></ul></span>';
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-animated-number-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'animated_number' . DS . 'style_' . $content->widget_style . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function articles_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetPages($content, $moduleId, $pageData, 'articles');
    }

    private function banner_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : '1');
        $image = '';

        if (is_object($content->image)) {
            $image = (isset($content->image->{$this->lang}) && $content->image->{$this->lang} ? $content->image->{$this->lang} : array_values((array) $content->image)[0] ?? '');
        }
        else if (is_string($content->image)) {
            $image = $content->image;
        }

        $image_src = ($image ? static::assetLinkDetermine($image) : $lazyPlaceholder);
        $imageDimensions = static::getImageDimensions($image_src, $pageData['badress']);
        $overlay_type = (isset($content->overlay_type) && $content->overlay_type ? $content->overlay_type : 'none');
        $image_overlay = ($overlay_type != 'none' ? true : false);
        $title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $description = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');
        $tag = (isset($content->tag->{$this->lang}) && $content->tag->{$this->lang} ? $content->tag->{$this->lang} : array_values((array) $content->tag)[0] ?? '');
        $icon = (isset($content->icon) && $content->icon ? $content->icon : '');
        $link = (isset($content->link) && $content->link ? $content->link : '');
        $link_target = (isset($content->link_target) && $content->link_target ? $content->link_target : '_blank');
        $link_rel = (isset($content->link_rel) && $content->link_rel ? $content->link_rel : []);
        $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');
        $show_button = (isset($content->show_button) && $content->show_button == 'yes' ? true : false);
        $button_text = (isset($content->button_text->{$this->lang}) && $content->button_text->{$this->lang} ? $content->button_text->{$this->lang} : array_values((array) $content->button_text)[0] ?? '');
        $show_button_icon = (isset($content->show_button_icon) && $content->show_button_icon == 'yes' ? true : false);
        $button_icon = (isset($content->button_icon) && $content->button_icon ? $content->button_icon : '');
        $button_icon_position = (isset($content->button_icon_position) && $content->button_icon_position ? $content->button_icon_position : 'right');
        $image_alt = (isset($content->image_alt->{$this->lang}) && $content->image_alt->{$this->lang} ? $content->image_alt->{$this->lang} : (isset($content->image_alt) ? array_values((array) $content->image_alt)[0] ?? '' : ''));
        $image_title = (isset($content->image_title->{$this->lang}) && $content->image_title->{$this->lang} ? $content->image_title->{$this->lang} : (isset($content->image_title) ? array_values((array) $content->image_title)[0] ?? '' : ''));

        if (empty($image_alt)) {
            if (!empty($title)) {
                $image_alt = $title;
            }
            else if (!empty($image_title)) {
                $image_alt = $image_title;
            }
            else {
                $image_alt = basename($image_src);
            }
        }

        if (empty($image_title)) {
            if (!empty($title)) {
                $image_title = $title;
            }
            else if (!empty($image_alt)) {
                $image_title = $image_alt;
            }
            else {
                $image_title = basename($image_src);
            }
        }

        $style = '';

        if ($image_overlay) {
            $style .= '#' . $widgetId . '.fon-banner-widget{';

            if ($overlay_type == 'color') {
                $style .= (isset($content->color_overlay->normal) && $content->color_overlay->normal ? '--bs-bg-overlay-color:' . $content->color_overlay->normal . ';' : '');
                $style .= (isset($content->color_overlay->hover) && $content->color_overlay->hover ? '--bs-bg-overlay-hover-color:' . $content->color_overlay->hover . ';' : '');
            }

            if ($overlay_type == 'gradient') {
                $style .= (isset($content->gradient_overlay->normal) && $content->gradient_overlay->normal ? self::parseGradient($content->gradient_overlay->normal, 'bg-overlay') : '');
                $style .= (isset($content->gradient_overlay->hover) && $content->gradient_overlay->hover ? self::parseGradient($content->gradient_overlay->hover, 'bg-overlay-hover') : '');
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-banner-widget style-' . $widget_style . ' overlay-' . $overlay_type . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'banner' . DS . 'style_' . $content->widget_style . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function bank_account_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $class = (isset($content->fon_class) && $content->fon_class ? $content->fon_class : '');
        $show_title = (isset($content->show_name) && $content->show_name == 'yes' ? true : false);
        $show_logo = (isset($content->show_logo) && $content->show_logo == 'yes' ? true : false);
        $title = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        $owner = (isset($content->owner) && $content->owner ? $content->owner : '');
        $iban = (isset($content->iban) && $content->iban ? $content->iban : '');
        $swift = (isset($content->swift) && $content->swift ? $content->swift : '');
        $number = (isset($content->number) && $content->number ? $content->number : '');
        $branch = (isset($content->branch) && $content->branch ? $content->branch : '');
        $widget_style = (isset($content->style) && $content->style ? $content->style : 'horizontal');
        $logo = (isset($content->logo) && $content->logo ? $content->logo : '');
        $logo_src = ($logo ? static::assetLinkDetermine($logo) : $lazyPlaceholder);
        $imageDimensions = static::getImageDimensions($logo_src, $pageData['badress']);
        $moduleLang = Modules::Lang('Payment', 'BankTransfer', Language::selected());
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="card fon-bank-account rounded-4 bg-theme-light border-0 mb-4 ' . $class . '">';
        $output .= '<div class="row g-0 align-items-center justify-content-center">';
        if ($show_logo && $logo) {
            $output .= '<div class="col-md-' . ($widget_style == 'horizontal' ? '4' : '12') . '">';
            $output .= '<div class="h-100 rounded-4 d-flex flex-column justify-content-center align-items-center">';

            if ($enableLazyLoading) {
                $output .= '<img class="card-image img-fluid" loading="lazy" decoding="async" src="' . $logo_src . '" alt="' . $title . '" style="' . ($widget_style == 'horizontal' ? 'max-width:80%' : 'max-height:150px') . '" ' . $imageDimensions . '/>';
            }
            else {
                $output .= '<img class="card-image img-fluid" src="' . $logo_src . '" alt="' . $title . '" style="' . ($widget_style == 'horizontal' ? 'max-width:80%' : 'max-height:150px') . '" ' . $imageDimensions . '/>';
            }

            $output .= '</div>';
            $output .= '</div>';
        }
        $output .= '<div class="col-md-' . (($widget_style == 'horizontal') && $show_logo && $logo ? '8' : '12') . '">';
        $output .= '<div class="card-body">';
        if ($show_title && $title) {
            $output .= '<h5 class="card-title">' . $title . '</h5>';
        }

        $output .= '<ul class="list-group rounded-4 list-group-flush">';
        $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
        $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-buyer-name'] . ' :</strong>';
        $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $owner . ' <button type="button" data-text="' . $owner . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
        $output .= '</li>';
        $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
        $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-iban'] . ' :</strong>';
        $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $iban . ' <button type="button" data-text="' . $iban . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
        $output .= '</li>';

        if ($swift) {
            $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
            $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-swift'] . ' :</strong>';
            $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $swift . ' <button type="button" data-text="' . $swift . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
            $output .= '</li>';
        }

        if ($number) {
            $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
            $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-number'] . ' :</strong>';
            $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $number . ' <button type="button" data-text="' . $number . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
            $output .= '</li>';
        }

        if ($branch) {
            $output .= '<li class="list-group-item d-flex flex-column flex-sm-row align-items-start align-items-sm-center justify-content-between">';
            $output .= '<strong class="text-start flex-shrink-0 d-flex">' . $moduleLang['account-branch-nc'] . ' :</strong>';
            $output .= '<span class="text-start text-sm-end d-flex flex-grow-1 align-items-center justify-content-between justify-content-sm-end w-100">' . $branch . ' <button type="button" data-text="' . $branch . '" data-bs-toggle="tooltip" data-bs-title="' . ___('needs/copy') . '" class="btn btn-link btn-copy p-0 ms-2 shadow-none"><i class="fa-regular fa-copy"></i></button></span>';
            $output .= '</li>';
        }

        $output .= '</ul>';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function button_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        $aligns = (isset($content->align) && $content->align ? $content->align : NULL);

        foreach ($aligns as $k => $v) {
            if ($v == 'left') {
                $aligns->{$k} = 'start';
            }
            else if ($v == 'right') {
                $aligns->{$k} = 'end';
            }
        }

        $output = '';
        if (isset($content->items) && is_array($content->items)) {
            $buttonCount = count($content->items);

            if (1 < $buttonCount) {
                if (isset($content->gap) && $content->gap) {
                    $style .= '#' . $widgetId . ' .fon-widget-button-group .btn{';
                    $style .= 'margin: ' . $content->gap . 'px';
                    $style .= '}';
                }
            }

            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-button-widget ' . $content->fon_class . '">';
            $output .= $this->parseButtons($content->items, $moduleId, $pageData, $aligns);
            $output .= '</div>';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        return $output;
    }

    private function calltoaction_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceHolder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $bg_type = (isset($content->bg_type) && $content->bg_type ? $content->bg_type : 'none');
        $bg_image = '';

        if (is_object($content->bg_image)) {
            $bg_image = (isset($content->bg_image->{$this->lang}) && $content->bg_image->{$this->lang} ? $content->bg_image->{$this->lang} : array_values((array) $content->bg_image)[0] ?? '');
        }
        else if (is_string($content->bg_image)) {
            $bg_image = $content->bg_image;
        }

        $bg_image_src = ($bg_image ? static::assetLinkDetermine($bg_image) : $lazyPlaceHolder);
        $overlay_type = (isset($content->overlay_type) && $content->overlay_type ? $content->overlay_type : 'none');
        $bg_overlay = ($overlay_type != 'none' ? true : false);
        $bg_color = (isset($content->bg_color) && $content->bg_color ? $content->bg_color : '');
        $bg_color_overlay = (isset($content->color_overlay) && $content->color_overlay ? $content->color_overlay : '');
        $bg_gradient = (isset($content->bg_gradient) && $content->bg_gradient ? $content->bg_gradient : '');
        $bg_gradient_overlay = (isset($content->gradient_overlay) && $content->gradient_overlay ? $content->gradient_overlay : '');
        $button_position = (isset($content->button_position) && $content->button_position ? $content->button_position : 'right');
        $align = (isset($content->align) && $content->align ? $content->align : '');
        $padding = (isset($content->padding) && $content->padding ? $content->padding : '');
        $use_border = (isset($content->use_border) && $content->use_border == 'yes' ? true : false);
        $border = (isset($content->border) && $content->border ? $content->border : '');
        $border_radius = (isset($content->border_radius) && $content->border_radius ? $content->border_radius : '');
        $shadow = (isset($content->shadow) && $content->shadow ? $content->shadow : '');
        $title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : '');
        $title_color = (isset($content->title_color) && $content->title_color ? $content->title_color : '');
        $description = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');
        $description_font = (isset($content->content_font) && $content->content_font ? $content->content_font : '');
        $description_color = (isset($content->content_color) && $content->content_color ? $content->content_color : '');
        $show_icon = (isset($content->show_icon) && $content->show_icon == 'yes' ? true : false);
        $icon = (isset($content->icon) && $content->icon ? $content->icon : '');
        $icon_size = (isset($content->icon_size) && $content->icon_size ? $content->icon_size : '');
        $icon_color = (isset($content->icon_color) && $content->icon_color ? $content->icon_color : '');
        $style = '';
        $style .= '#' . $widgetId . '{';

        if ($bg_type != 'none') {
            if (($bg_type == 'color') && $bg_color) {
                $style .= 'background-color: ' . $bg_color . ';';
            }
            else if (($bg_type == 'gradient') && $bg_gradient) {
                $style .= 'background-image: ' . self::parseGradient($bg_gradient) . ';';
            }
            else if (($bg_type == 'image') && $bg_image) {
                $style .= 'background-image: url(' . $bg_image_src . ');';
            }
        }

        if ($padding) {
            $style .= 'padding: ' . $padding . 'px;';
        }
        if ($use_border && $border) {
            $style .= 'border: ' . $border . ';';
        }

        if ($border_radius) {
            $style .= 'border-radius: ' . $border_radius . 'px;';
        }

        if ($shadow) {
            $style .= 'box-shadow: ' . $shadow . ';';
        }

        $style .= '}';
        if (($button_position == 'bottom') && $align != 'center') {
            $responsiveItems = [
                '.fon-widget-content' => [
                ['type' => 'width', 'unit' => '%', 'value' => $content->width]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        if (($bg_type == 'image') && $bg_overlay && $bg_color_overlay || $bg_gradient_overlay) {
            $style .= '#' . $widgetId . ' .fon-calltoaction-overlay{';
            $style .= (($overlay_type == 'color') && $bg_color_overlay ? 'background-color:' . $bg_color_overlay . ';' : '');
            $style .= (($overlay_type == 'gradient') && $bg_gradient_overlay ? self::parseGradient($bg_gradient_overlay) : '');

            if ($border_radius) {
                $style .= 'border-radius: ' . $border_radius . 'px;';
            }

            $style .= '}';
        }

        $style .= '#' . $widgetId . ' .fon-calltoaction-title{';
        $style .= ($title_font ? self::parseFontProperties($title_font) : '');
        $style .= ($title_color ? 'color: ' . $title_color . ';' : '');
        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-calltoaction-description{';
        $style .= ($description_font ? self::parseFontProperties($description_font) : '');
        $style .= ($description_color ? 'color: ' . $description_color . ';' : '');
        $style .= '}';
        if ($show_icon && $icon) {
            $style .= '#' . $widgetId . ' .fon-calltoaction-icon i{';
            $style .= ($icon_color ? 'color: ' . $icon_color . ';' : '');
            $style .= ($icon_size ? 'font-size: ' . $icon_size . 'px;' : '');
            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        if (!is_object($align) && $align != '') {
            $align = new stdClass();
            $textAlign = '';

            switch ($align) {
            case 'left':
                $textAlign = 'start';
                break;
            case 'center':
                $textAlign = 'center';
                break;
            case 'right':
                $textAlign = 'end';
                break;
            }

            $align->xs = $align->sm = $align->md = $align->lg = $align->xl = $textAlign;
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-calltoaction-widget bg-cover buttons-' . $button_position . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-calltoaction-overlay position-absolute w-100 h-100 top-0 start-0"></div>';
        $output .= '<div class="fon-widget-content position-relative ' . ($button_position == 'right' ? 'row g-0 align-items-center ' : '') . '">';
        if ($show_icon && $icon) {
            $output .= '<div class="fon-calltoaction-icon ' . ($button_position == 'right' ? 'col-12 col-md-1 text-center align-self-start' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">';
            $output .= '<i class="' . $icon . '  ' . ($button_position == 'right' ? 'm-2 ' : 'my-2') . '"></i>';
            $output .= '</div>';
        }
        if ($title || $description) {
            $output .= '<div class="fon-calltoaction-inner-content ' . ($button_position == 'right' ? 'col-12 col-md-8' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">';

            if ($title) {
                $output .= '<' . $heading_selector . ' class="fon-calltoaction-title ' . ($button_position == 'right' ? 'text-center text-md-start' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">' . strip_tags($title) . '</' . $heading_selector . '>';
            }

            if ($description) {
                $output .= '<p class="fon-calltoaction-description ' . ($button_position == 'right' ? 'text-center text-md-start' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">' . strip_tags($description) . '</p>';
            }

            $output .= '</div>';
        }
        if (isset($content->buttons) && is_array($content->buttons) && $content->buttons) {
            $output .= '<div class="fon-calltoaction-buttons ' . ($button_position == 'right' ? 'col-12 col-md-' . ($show_icon && $icon ? '3' : '4') . ' text-center text-md-end' : 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl) . '">';
            $output .= $this->parseButtons($content->buttons, $moduleId, $pageData, $align);
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function campaign_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $mediaType = (isset($content->media_type) && $content->media_type ? $content->media_type : 'icon');
        $useCoupon = (isset($content->use_coupon) && $content->use_coupon == 'yes' ? true : false);
        $useCountdown = (isset($content->use_countdown) && $content->use_countdown == 'yes' ? true : false);

        if (isset($content->campaign_message)) {
            $campaign_message = (isset($content->campaign_message->{$this->lang}) && $content->campaign_message->{$this->lang} ? $content->campaign_message->{$this->lang} : array_values((array) $content->campaign_message)[0] ?? '');
        }
        else {
            $campaign_message = '';
        }

        $dateLangs = ['day' => ___('date/day'), 'hour' => ___('date/hour'), 'minute' => ___('date/minute'), 'second' => ___('date/second')];
        $carouselData = '';
        $columns = [];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel campaign-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl . ' g-3' : '');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-campaign-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content ' . $containerClass . '" ' . $carouselData . '>';
        if (isset($content->items) && is_array($content->items)) {
            foreach ($content->items as $ikey => $item) {
                if ($mediaType == 'image') {
                    if ($item->campaign_image) {
                        $item->campaign_image = static::assetLinkDetermine($item->campaign_image);
                    }
                    else {
                        $item->campaign_image = $lazyPlaceholder;
                    }

                    $imageDimensions = static::getImageDimensions($item->campaign_image, $pageData['badress']);
                }
                $campaign_name = (isset($item->campaign_name->{$this->lang}) && $item->campaign_name->{$this->lang} ? $item->campaign_name->{$this->lang} : array_values((array) $item->campaign_name)[0] ?? '');
                $campaign_link = (isset($item->campaign_link->{$this->lang}) && $item->campaign_link->{$this->lang} ? $item->campaign_link->{$this->lang} : array_values((array) $item->campaign_link)[0] ?? '');
                $campaign_tag = (isset($item->campaign_tag->{$this->lang}) && $item->campaign_tag->{$this->lang} ? $item->campaign_tag->{$this->lang} : array_values((array) $item->campaign_tag)[0] ?? '');

                if (isset($item->campaign_desc)) {
                    $campaign_desc = (isset($item->campaign_desc->{$this->lang}) && $item->campaign_desc->{$this->lang} ? $item->campaign_desc->{$this->lang} : array_values((array) $item->campaign_desc)[0] ?? '');
                }
                else {
                    $campaign_desc = '';
                }

                $campaignRate = '';
                if (($content->show_campaign_rate == 'yes') && $item->campaign_amount_old_price && $item->campaign_amount_new_price) {
                    $campaignRate = round((($item->campaign_amount_old_price - $item->campaign_amount_new_price) / $item->campaign_amount_old_price) * 100);
                    $campaignRate = sprintf(__('theme/package_discount_save'), $campaignRate);
                }
                $dateString = (isset($item->campaign_date) && $item->campaign_date ? $item->campaign_date : date('Y-m-d H:i:s', strtotime('+1 month')));
                $isExpired = $dateString <= date('Y-m-d H:i:s');
                $dateString = date('Y/m/d H:i:s', strtotime($dateString));

                if (!$isCarousel) {
                    $output .= '<div class="col">';
                }
                $isFeatured = isset($item->campaign_featured) && $item->campaign_featured == 'yes';
                include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'campaign' . DS . 'style_' . $content->widget_style . '.php';

                if (!$isCarousel) {
                    $output .= '</div>';
                }
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function carouselslider_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $content_vertical_center = (isset($content->content_vertical_center) && $content->content_vertical_center == 'yes' ? true : false);
        $height = (isset($content->height) && $content->height ? $content->height : 'auto');
        $custom_height = (isset($content->custom_height) && $content->custom_height ? $content->custom_height : (object) ['xl' => 900, 'lg' => 700, 'md' => 600, 'sm' => 500, 'xs' => 400]);
        $animation_style = (isset($content->animation_style) && $content->animation_style ? $content->animation_style : 'slide');
        $autoplay = (isset($content->autoplay) && $content->autoplay == 'yes' ? true : false);
        $interval = (isset($content->interval) && $content->interval ? $content->interval : 3000);
        $disable_touch_swipe = (isset($content->disable_touch_swipe) && $content->disable_touch_swipe == 'yes' ? true : false);
        $arrow_controllers = (isset($content->arrow_controllers) && $content->arrow_controllers == 'yes' ? true : false);
        $dot_controllers = (isset($content->dot_controllers) && $content->dot_controllers == 'yes' ? true : false);
        $dot_controllers_thumb = (isset($content->dot_controllers_thumb) && $content->dot_controllers_thumb == 'yes' ? true : false);
        $slide_items = (isset($content->items) && $content->items ? $content->items : []);
        if (!$arrow_controllers && !$dot_controllers) {
            $autoplay = true;
        }

        $carouselAttributes = '';
        $carouselAttributes .= ($autoplay ? ' data-bs-ride="carousel" ' : '');
        $carouselAttributes .= ($disable_touch_swipe ? ' data-bs-touch="false" ' : '');
        $style = '';

        if ($height != 'auto') {
            $responsiveItems = [
                '.carousel-item' => [
                ['type' => 'height', 'unit' => 'px', 'value' => $custom_height]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-carouselslider-widget ' . ($content_vertical_center ? 'vertical-center' : '') . ' ' . $content->fon_class . '">';
        $output .= '<div id="carousel_' . $moduleId . '" class="carousel slide ' . ($animation_style == 'fade' ? 'carousel-fade' : '') . '" ' . $carouselAttributes . '>';

        if ($slide_items) {
            if ($dot_controllers) {
                $output .= '<div class="carousel-indicators ' . ($dot_controllers_thumb ? 'carousel-thumb' : '') . '">';

                foreach ($slide_items as $sk => $si) {
                    $thumb_image = '';

                    if (is_object($si->image)) {
                        $thumb_image = (isset($si->slide_image->{$this->lang}) && $si->slide_image->{$this->lang} ? $si->slide_image->{$this->lang} : array_values((array) $si->slide_image)[0] ?? '');
                    }
                    else if (is_string($si->slide_image)) {
                        $thumb_image = $si->slide_image;
                    }

                    $output .= '<button' . "\n" . '                        type="button"' . "\n" . '                        data-bs-target="#carousel_' . $moduleId . '"' . "\n" . '                        data-bs-slide-to="' . $sk . '"' . "\n" . '                        class="' . ($sk == 0 ? 'active' : '') . '" ' . ($sk == 0 ? 'aria-current="true"' : '') . "\n" . '                        aria-label="Slide ' . ($sk + 1) . '"' . "\n" . '                        style="' . ($dot_controllers_thumb ? 'background-image:url(' . $thumb_image . ');' : '') . '"></button>';
                }

                $output .= '</div>';
            }

            $output .= '<div class="carousel-inner">';

            foreach ($slide_items as $slide_key => $slide_item) {
                $image = '';

                if (is_object($slide_item->slide_image)) {
                    $image = (isset($slide_item->slide_image->{$this->lang}) && $slide_item->slide_image->{$this->lang} ? $slide_item->slide_image->{$this->lang} : array_values((array) $slide_item->slide_image)[0] ?? '');
                }
                else if (is_string($slide_item->slide_image)) {
                    $image = $slide_item->slide_image;
                }

                $image_src = ($image ? static::assetLinkDetermine($image) : $lazyPlaceholder);
                $imageDimensions = static::getImageDimensions($image_src, $pageData['badress']);
                $mobile_image = '';

                if (is_object($slide_item->slide_mobile_image)) {
                    $mobile_image = (isset($slide_item->slide_mobile_image->{$this->lang}) && $slide_item->slide_mobile_image->{$this->lang} ? $slide_item->slide_mobile_image->{$this->lang} : array_values((array) $slide_item->slide_mobile_image)[0] ?? '');
                }
                else if (is_string($slide_item->slide_mobile_image)) {
                    $mobile_image = $slide_item->slide_mobile_image;
                }

                $mobile_image_src = ($mobile_image ? static::assetLinkDetermine($mobile_image) : $lazyPlaceholder);
                $mobileDimensions = static::getImageDimensions($mobile_image_src, $pageData['badress']);
                $show_info = (isset($slide_item->slide_show_info) && $slide_item->slide_show_info == 'yes' ? true : false);
                $link = (isset($slide_item->button_link->{$this->lang}) && $slide_item->button_link->{$this->lang} ? $slide_item->button_link->{$this->lang} : array_values((array) $slide_item->button_link)[0] ?? '');
                $target = (isset($slide_item->button_target) && $slide_item->button_target ? $slide_item->button_target : '_self');

                if ($show_info) {
                    $title = (isset($slide_item->slide_title->{$this->lang}) && $slide_item->slide_title->{$this->lang} ? $slide_item->slide_title->{$this->lang} : array_values((array) $slide_item->slide_title)[0] ?? '');
                    $title_color = (isset($slide_item->slide_title_color) && $slide_item->slide_title_color ? $slide_item->slide_title_color : '#ffffff');
                    $description = (isset($slide_item->slide_description->{$this->lang}) && $slide_item->slide_description->{$this->lang} ? $slide_item->slide_description->{$this->lang} : array_values((array) $slide_item->slide_description)[0] ?? '');
                    $description_color = (isset($slide_item->slide_description_color) && $slide_item->slide_description_color ? $slide_item->slide_description_color : '#ffffff');
                    $content_bg = (isset($slide_item->slide_content_bg) && $slide_item->slide_content_bg ? $slide_item->slide_content_bg : 'rgba(0,0,0,0.1)');
                    $content_align = (isset($slide_item->slide_content_align) && $slide_item->slide_content_align ? (array) $slide_item->slide_content_align : ['xl' => 'center', 'lg' => 'center', 'md' => 'center', 'sm' => 'center', 'xs' => 'center']);
                    $content_align = (object) array_map(function($val) {
                        return ($val === 'left' ? 'start' : ($val === 'right' ? 'end' : $val));
                    }, $content_align);
                    $alignClass = 'text-' . $content_align->xs . ' text-sm-' . $content_align->sm . ' text-md-' . $content_align->md . ' text-lg-' . $content_align->lg . ' text-xl-' . $content_align->xl;
                }

                $output .= '<div class="carousel-item ' . ($slide_key == 0 ? 'active' : '') . ' ' . ($height != 'auto' ? 'custom-height' : '') . '" data-bs-interval="' . $interval . '">';
                if (!$show_info && $link) {
                    $output .= '<a href="' . $link . '" target="' . $target . '" class="d-block h-100">';
                }
                if ($mobile_image && $mobile_image != $image && $height == 'auto') {
                    if ($enableLazyLoading) {
                        $output .= '<img loading="lazy" decoding="async" src="' . $image_src . '" class="d-none d-lg-block w-100 h-auto" alt="' . ($title ?? ('Slide ' . $slide_key)) . '" ' . $imageDimensions . '>';
                        $output .= '<img loading="lazy" decoding="async" src="' . $mobile_image_src . '" class="d-block d-lg-none w-100 h-auto" alt="' . ($title ?? ('Slide ' . $slide_key)) . '" ' . $imageDimensions . '>';
                    }
                    else {
                        $output .= '<img src="' . $image_src . '" class="d-none d-lg-block w-100 h-auto" alt="' . ($title ?? ('Slide ' . $slide_key)) . '"  ' . $mobileDimensions . '>';
                        $output .= '<img src="' . $mobile_image_src . '" class="d-block d-lg-none w-100 h-auto" alt="' . ($title ?? ('Slide ' . $slide_key)) . '"  ' . $imageDimensions . '>';
                    }
                }
                else if ($enableLazyLoading) {
                    $output .= '<img loading="lazy" decoding="async" src="' . $image_src . '" class="d-block w-100" alt="' . ($title ?? ('Slide ' . $slide_key)) . '">';
                }
                else {
                    $output .= '<img src="' . $image_src . '" class="d-block w-100" alt="' . ($title ?? ('Slide ' . $slide_key)) . '">';
                }
                if (!$show_info && $link) {
                    $output .= '</a>';
                }
                if ($show_info && $title || $description || $link) {
                    $output .= '<div class="carousel-caption d-none d-md-block ' . $alignClass . '">';
                    $output .= '<div class="carousel-caption-inner p-3 rounded" style="background-color:' . $content_bg . ';">';

                    if ($title) {
                        $output .= '<h2 ' . ($title_color ? 'style="color:' . $title_color . '"' : '') . '>' . $title . '</h2>';
                    }

                    if ($description) {
                        $output .= '<p ' . ($description_color ? 'style="color:' . $description_color . '"' : '') . '>' . $description . '</p>';
                    }

                    if ($link) {
                        $output .= self::parseButton($slide_item, $moduleId, $pageData);
                    }

                    $output .= '</div>';
                    $output .= '</div>';
                }

                $output .= '</div>';
            }

            $output .= '</div>';

            if ($arrow_controllers) {
                $output .= '<button class="carousel-control-prev" type="button" data-bs-target="#carousel_' . $moduleId . '" data-bs-slide="prev">';
                $output .= '<span class="fa-solid fa-circle-chevron-left fs-2" aria-hidden="true"></span>';
                $output .= '<span class="visually-hidden">Previous</span>';
                $output .= '</button>';
                $output .= '<button class="carousel-control-next" type="button" data-bs-target="#carousel_' . $moduleId . '" data-bs-slide="next">';
                $output .= '<span class="fa-solid fa-circle-chevron-right fs-2" aria-hidden="true"></span>';
                $output .= '<span class="visually-hidden">Next</span>';
                $output .= '</button>';
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function client_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $use_border = (isset($content->use_border) && $content->use_border == 'yes' ? true : false);
        $show_title = (isset($content->show_title) && $content->show_title == 'yes' ? true : false);
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $center = (isset($content->center) && $content->center == 'yes' ? true : false);
        $remove_hover = (isset($content->remove_hover) && $content->remove_hover == 'yes' ? true : false);
        $background = (isset($content->background) && $content->background ? $content->background : (object) ['normal' => '#ffffff', 'hover' => '#ffffff']);
        $image_filter = (isset($content->image_filter) && $content->image_filter ? $content->image_filter : 'none');
        $border = (isset($content->border) && $content->border ? $content->border : '');
        $radius = (isset($content->radius) && $content->radius ? $content->radius : '');
        $shadow = (isset($content->shadow) && $content->shadow ? $content->shadow : '');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : []);
        $blur_value = (isset($content->blur_value) && $content->blur_value ? $content->blur_value : 0);
        $grayscale_value = (isset($content->grayscale_value) && $content->grayscale_value ? $content->grayscale_value : 0);
        $opacity_value = (isset($content->opacity_value) && $content->opacity_value ? $content->opacity_value : 1);
        $scale_value = (isset($content->scale_value) && $content->scale_value ? $content->scale_value : 1);
        $hover_effect = (isset($content->hover_effect) && $content->hover_effect ? $content->hover_effect : 'none');
        $max_height = (isset($content->max_height) && $content->max_height ? $content->max_height : '');
        $padding = (isset($content->padding) && $content->padding ? $content->padding : '');
        $link_target = (isset($content->link_target) && $content->link_target ? $content->link_target : '_self');
        $style = '';
        $style .= '#' . $widgetId . ' .client{';
        if ($use_border && $border) {
            $style .= 'border: ' . $border . ';';

            if ($radius) {
                $style .= 'border-radius: ' . $radius . 'px;';
            }

            if ($padding) {
                $style .= 'padding: ' . $padding . ';';
            }
        }
        if (isset($background->normal) && $background->normal) {
            $style .= 'background-color: ' . $background->normal . ';';
        }

        if ($shadow) {
            $style .= 'box-shadow: ' . $shadow . ';';
        }

        $style .= '}';
        if (isset($background->hover) && $background->hover) {
            $style .= '#' . $widgetId . ' .client:hover{';
            $style .= 'background-color: ' . $background->hover . ';';
            $style .= '}';
        }
        if ($show_title && $title_font) {
            $style .= '#' . $widgetId . ' .client .client-title{';
            $style .= self::parseFontProperties($title_font);
            $style .= '}';
        }

        if ($image_filter == 'blur') {
            $style .= '#' . $widgetId . '.filter-blur .fon-widget-content:hover .client{';
            $style .= 'filter: blur(' . $blur_value . 'px);';
            $style .= 'opacity:0.6;';
            $style .= '}';
            $style .= '#' . $widgetId . '.filter-blur .fon-widget-content:hover .client:hover{';
            $style .= 'filter: blur(0);';
            $style .= 'opacity:1;';
            $style .= '}';
        }
        else {
            $style .= '#' . $widgetId . ' .client .client-image{';

            if ($max_height) {
                $style .= 'max-height: ' . $max_height . 'px;';
            }

            if ($image_filter != 'none') {
                if ($image_filter == 'grayscale') {
                    $style .= 'filter: grayscale(' . $grayscale_value . '%);';
                }
                else if ($image_filter == 'opacity') {
                    $style .= 'filter: opacity(' . $opacity_value . '%);';
                }
            }

            if ($hover_effect != 'none') {
                if ($hover_effect == 'scale') {
                    $style .= 'transform: scale(1);';
                }
                else if ($hover_effect == 'move') {
                    $style .= 'transform: translateY(0);';
                }
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .client:hover .client-image{';
            if (($image_filter != 'none') && $remove_hover) {
                if ($image_filter == 'grayscale') {
                    $style .= 'filter: grayscale(0);';
                }
                else if ($image_filter == 'opacity') {
                    $style .= 'filter: opacity(100);';
                }
            }

            if ($hover_effect != 'none') {
                if ($hover_effect == 'scale') {
                    $style .= 'transform: scale(' . $scale_value . ');';
                }
                else if ($content->hover_effect == 'move') {
                    $style .= 'transform: translateY(-' . $scale_value . 'px);';
                }
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $carouselData = '';
        $columns = (object) ['xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => ''];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel client-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl . ' g-3' : '');

            if ($center) {
                $containerClass .= ' justify-content-center';
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-client-widget ' . ($content->use_border == 'yes' ? 'with-border' : '') . ' filter-' . $content->image_filter . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content ' . $containerClass . '" ' . $carouselData . '>';
        if (isset($content->items) && is_array($content->items)) {
            $i = 1;

            foreach ($content->items as $item) {
                $client_title = (isset($item->client_title) && $item->client_title ? $item->client_title : '');
                $client_alt = (isset($item->client_alt) && $item->client_alt ? $item->client_alt : '');
                $client_link = (isset($item->client_link) && $item->client_link ? $item->client_link : '');
                $link_target = (isset($item->link_target) && $item->link_target ? $item->link_target : '_self');
                $link_rel = (isset($item->link_rel) && $item->link_rel ? $item->link_rel : []);
                $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');

                if ($item->client_image) {
                    $item->client_image = static::assetLinkDetermine($item->client_image);
                }
                else {
                    $item->client_image = $lazyPlaceholder;
                }

                if (empty($client_alt)) {
                    if (!empty($client_title)) {
                        $client_alt = $client_title;
                    }
                    else {
                        $client_alt = basename($item->client_image);
                    }
                }

                if (empty($client_title)) {
                    if (!empty($client_alt)) {
                        $client_title = $client_alt;
                    }
                    else {
                        $client_title = basename($item->client_image);
                    }
                }

                $imageDimensions = static::getImageDimensions($item->client_image, $pageData['badress']);
                $lastClass = [];

                if (6 < $i) {
                    $i = 1;
                }

                if ($i == $columns->xs) {
                    $lastClass[] = 'last-xs';
                }
                else if ($i == $columns->sm) {
                    $lastClass[] = 'last-sm';
                }
                else if ($i == $columns->md) {
                    $lastClass[] = 'last-md';
                }
                else if ($i == $columns->lg) {
                    $lastClass[] = 'last-lg';
                }
                else if ($i == $columns->xl) {
                    $lastClass[] = 'last-xl';
                }

                if (!$isCarousel) {
                    $output .= '<div class="col ' . implode(' ', $lastClass) . ' ">';
                }

                $output .= '<div class="client transition-default">';

                if ($client_link) {
                    $output .= '<a class="d-block" href="' . $client_link . '" target="' . $link_target . '" ' . $link_rel . ' title="' . $client_title . '">';
                }

                if ($enableLazyLoading) {
                    $output .= '<img class="client-image h-auto" loading="lazy" decoding="async" src="' . $item->client_image . '" alt="' . $client_alt . '"  title="' . $client_title . '" ' . $imageDimensions . '/>';
                }
                else {
                    $output .= '<img class="client-image h-auto" src="' . $item->client_image . '" alt="' . $client_alt . '" title="' . $client_title . '" ' . $imageDimensions . '/>';
                }

                if ($show_title) {
                    $output .= '<h5 class="client-title">' . $client_title . '</h5>';
                }

                if ($client_link) {
                    $output .= '</a>';
                }

                $output .= '</div>';

                if (!$isCarousel) {
                    $output .= '</div>';
                }

                ++$i;
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function comparison_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $pageType = $pageData['page'] ?? ($content['page_type'] ?? 'custom');
        $show_free_label = !isset($content->show_free_label) || $content->show_free_label == 'yes';
        $free_label_text = self::getFieldMultilingualText($content->free_label_text ?? NULL, $this->lang, __('theme/is_free'));
        if ($show_free_label && empty($free_label_text)) {
            $free_label_text = __('theme/is_free');
        }
        $card_button_action_on_free = (isset($content->card_button_action_on_free) && $content->card_button_action_on_free ? $content->card_button_action_on_free : 'default');
        $enable_custom_card_button_label = isset($content->enable_custom_card_button_label) && $content->enable_custom_card_button_label == 'yes';
        $custom_card_button_label = self::getFieldMultilingualText($content->custom_card_button_label ?? NULL, $this->lang, __('website/index/add-basket-button'));
        $isProductPage = in_array($pageType, ['hosting' => true, 'server' => true, 'sms' => true, 'special' => true]);
        $show_price_type = (isset($content->show_price_type) && $content->show_price_type ? $content->show_price_type : 'default');

        if ($show_price_type == 'yes') {
            $show_price_type = 'month_year';
        }
        $price_calc = (isset($content->price_calc) && $content->price_calc ? $content->price_calc : 'default');
        $source = (isset($content->source) && $content->source ? $content->source : 'category');
        $source_category = (isset($content->category) && $content->category ? $content->category : '');
        $source_package = (isset($content->package) && $content->package ? $content->package : '');
        $name_widget = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        $desc_widget = (isset($content->desc_widget->{$this->lang}) && $content->desc_widget->{$this->lang} ? $content->desc_widget->{$this->lang} : array_values((array) $content->desc_widget)[0] ?? '');
        $catType = '';
        $currency_symbols = self::getCurrencySymbols();
        if ($isProductPage && isset($pageData['items'])) {
            $category = $pageData['items']['showCategory'] ?? [];
            $catType = $category['kind'] ?? '';

            if (!$category) {
                return '';
            }

            $list = $pageData['functions']['get_list']($category['id'], $category['kind']);

            if (!$list) {
                $categories = $pageData['functions']['get_categories']($category['id'], $category['kind']);

                if ($categories) {
                    $list = $pageData['functions']['get_list']($categories[0]['id'], $category['kind']);
                }
            }
        }
        else if (($source == 'category') && $source_category) {
            list($categoryType, $categoryId) = explode(':', $source_category);
            $catType = $categoryType ?? '';

            if ($categoryId == 'none') {
                $result = $this->getWidgetItems('products', $categoryId, $categoryType);

                if ($result) {
                    $category = ['kind' => $categoryType, 'title' => $name_widget];
                    $list = $result['items'];
                }
                else {
                    $category = [];
                    $list = [];
                }

                if (!$category) {
                    return '';
                }
            }
            else {
                $result = $this->getWidgetItems('products', 'cats: ' . $categoryId, $categoryType);

                if ($result) {
                    $category = $result['cats'][$categoryId];
                    $list = $result['items'][$categoryId];
                }
                else {
                    $category = [];
                    $list = [];
                }

                if (!$category) {
                    return '';
                }
            }
        }
        else if (($source == 'package') && $source_package) {
            list($packageType, $packageIds) = explode(':', $source_package);
            $catType = $packageType ?? '';
            $result = $this->getWidgetItems('products', 'items: ' . $packageIds, $packageType);

            if ($result) {
                $category = ['kind' => $packageType, 'title' => $name_widget];
                $list = $result['items'];
            }
            else {
                $category = [];
                $list = [];
            }

            if (!$category) {
                return '';
            }
        }
        else {
            return '';
        }
        $widgetStyle = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'default');
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $showCoupon = (isset($content->show_coupon) && $content->show_coupon == 'yes' ? true : false);
        $carouselDataBody = '';
        $carouselDataHeader = '';

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="no" data-autoplay="no" data-pause="yes" data-loop="no" data-row="no" data-rows="' . htmlspecialchars(Utility::jencode(['xl' => 1, 'lg' => 1, 'md' => 1, 'sm' => 1, 'xs' => 1]), ENT_QUOTES, 'UTF-8') . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-asnavfor="#ctHeaderSlide' . $widgetId . ',#ctBodySlide' . $widgetId . '"';
            $carouselDataBody = $carouselData . ' data-arrows="no"';
            $carouselDataHeader = $carouselData . ' data-arrows="' . $content->arrows . '"';
        }
        if (isset($category['kind']) && $category['kind'] == 'special') {
            $categortKind = $this->getCategory($category['id'], 'products', 'special');
            $categoryKindId = $categortKind['kind_id'] ?? ($categortKind['kind_id'] ?? 0);

            if ($categoryKindId) {
                $categoryCoupon = $this->couponCheck('category', $category['kind'], [$categoryKindId . '/' . $category['id']]);
            }
            else {
                $categoryCoupon = $this->couponCheck('category', $category['kind'], [$category['id']]);
            }
        }
        else {
            $categoryCoupon = $this->couponCheck('category', $category['kind'], [$category['id']]);
        }

        $productCoupons = [];
        $output = '';
        if (isset($list) && $list) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-comparison-widget  ' . $content->fon_class . '">';
            $output .= '<div class="fon-widget-content">';
            $allFeatures = [];
            $features = [];
            $periods = [];

            foreach ($list as $key => $product) {
                foreach ($product['prices'] as $spkey => $spprice) {
                    $periods[$spkey] = $spprice['time'] . ' ' . ___('date/period-' . $spprice['period']);
                }

                $featuresJson = true;
                if (isset($category['kind']) && $category['kind'] == 'special') {
                    $productCoupon = $this->couponCheck('product', $product['type'], [$categoryKindId, $product['id']]);
                }
                else {
                    $productCoupon = $this->couponCheck('product', $product['type'], [$category['id'], $product['id']]);
                }

                if ($productCoupon) {
                    $productCoupons[$product['id']] = $productCoupon;
                }

                $productFeatures = (self::isJSON($product['features']) ? Utility::jdecode($product['features'], true) : $product['features']);
                if (!is_array($productFeatures) && $productFeatures) {
                    $featuresJson = false;
                    $productFeatures = preg_split('/\\r\\n|\\r|\\n/', $productFeatures);
                }

                if (isset($productFeatures['features'])) {
                    if (count($features) < count($productFeatures['features'])) {
                        $features = $productFeatures['features'];
                    }

                    $allFeatures[$product['id']] = $productFeatures;
                    if (($catType == 'server') && $product['options']) {
                        $arrayFeature = [];

                        foreach (['processor', 'ram', 'disk-space', 'bandwidth', 'raid'] as $key) {
                            if (isset($product['options'][$key])) {

                                $arrayFeature[$key] = ['name' => match ($key) {
                                    processor => __('website/products/server-list-processor'),
                                    ram => __('website/products/server-list-ram'),
                                    disk-space => __('website/products/server-list-disk'),
                                    bandwidth => __('website/products/server-list-bandwidth'),
                                    raid => __('website/products/server-list-raid')
                                }, 'desc' => '', 'icon' => match ($key) {
                                    processor => 'fa-solid fa-microchip',
                                    ram => 'fa-solid fa-memory',
                                    disk-space => 'fa-solid fa-hard-drive',
                                    bandwidth => 'fa-solid fa-gauge-high',
                                    raid => 'fa-solid fa-server'
                                }, 'type' => 'text', 'text' => $product['options'][$key], 'exist' => true];
                            }
                        }

                        if (isset($product['options_lang']['location'])) {
                            $country = '-';
                            $code = NULL;

                            if ($product['options_lang']['location'] != '') {
                                if (strpos($product['options_lang']['location'], '-') !== false) {
                                    $parts = explode('-', $product['options_lang']['location']);
                                    $country = $parts[0];
                                    $code = end($parts);
                                }
                                else {
                                    $country = $product['options_lang']['location'];
                                    $code = NULL;
                                }
                            }

                            $arrayFeature['location'] = ['name' => __('website/products/server-list-location'), 'desc' => '', 'icon' => 'fa-solid fa-location-dot', 'type' => 'text', 'text' => ($code ? '<i class="flag flag-xs rounded-1 flag-country-' . strtolower($code) . ' me-1"></i>' . $country : $country), 'exist' => true];
                        }

                        if ($arrayFeature) {
                            $allFeatures[$product['id']]['features'] = array_merge($arrayFeature, $allFeatures[$product['id']]['features']);
                            $features = array_merge($arrayFeature, $features);
                        }
                    }
                }
                else if (is_array($productFeatures) && $catType == 'special' && isset($category['options_lang']['columns']) && $category['options_lang']['columns']) {
                    $features = [];

                    foreach ($category['options_lang']['columns'] as $column) {
                        $columnVal = $productFeatures[$column['id']] ?? NULL;
                        $columnFeature = ['name' => $column['name'], 'desc' => '', 'icon' => '', 'type' => 'text', 'text' => $columnVal];
                        $features[] = $columnFeature;
                        $allFeatures[$product['id']]['features'][] = $columnFeature;
                    }
                }
                else if (is_array($productFeatures) && $productFeatures) {
                    $features = [];

                    foreach ($productFeatures as $pf) {
                        $arrayFeature = ['name' => $pf, 'desc' => '', 'icon' => '', 'type' => 'select', 'text' => '', 'exist' => true];
                        $features[] = $arrayFeature;
                        $allFeatures[$product['id']]['features'][] = $arrayFeature;
                    }
                }
                else if (($catType == 'server') && $product['options']) {
                    $arrayFeature = [];

                    foreach (['processor', 'ram', 'disk-space', 'bandwidth', 'raid'] as $key) {
                        if (isset($product['options'][$key])) {

                            $arrayFeature[$key] = ['name' => match ($key) {
                                processor => __('website/products/server-list-processor'),
                                ram => __('website/products/server-list-ram'),
                                disk-space => __('website/products/server-list-disk'),
                                bandwidth => __('website/products/server-list-bandwidth'),
                                raid => __('website/products/server-list-raid')
                            }, 'desc' => '', 'icon' => match ($key) {
                                processor => 'fa-solid fa-microchip',
                                ram => 'fa-solid fa-memory',
                                disk-space => 'fa-solid fa-hard-drive',
                                bandwidth => 'fa-solid fa-gauge-high',
                                raid => 'fa-solid fa-server'
                            }, 'type' => 'text', 'text' => $product['options'][$key], 'exist' => true];
                        }
                    }

                    if (isset($product['options_lang']['location'])) {
                        $arrayFeature['location'] = ['name' => __('website/products/server-list-location'), 'desc' => '', 'icon' => 'fa-solid fa-location-dot', 'type' => 'text', 'text' => $product['options_lang']['location'], 'exist' => true];
                    }

                    $allFeatures[$product['id']] = ['features' => $arrayFeature];

                    if (empty($features)) {
                        $features = $arrayFeature;
                    }
                }
            }

            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'comparison' . DS . 'style_' . $widgetStyle . '.php';
            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function content_box_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $title_color = (isset($content->title_color) && $content->title_color ? $content->title_color : '');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : '');
        $desc_color = (isset($content->description_color) && $content->description_color ? $content->description_color : '');
        $desc_font = (isset($content->desc_font) && $content->desc_font ? $content->desc_font : '');
        $icon_color = (isset($content->icon_color) && $content->icon_color ? $content->icon_color : '');
        $icon_bg_color = (isset($content->icon_bg_color) && $content->icon_bg_color ? $content->icon_bg_color : '');
        $icon_class = (isset($content->icon_class) && $content->icon_class ? $content->icon_class : '');
        $item_class = (isset($content->item_class) && $content->item_class ? $content->item_class : '');
        $image_width = (isset($content->image_width) && $content->image_width ? $content->image_width : '');
        $style = '';
        if ($title_color || $desc_color || $icon_color || $icon_bg_color) {
            $style .= '#' . $widgetId . '.fon-content-box-widget{';

            if ($title_color) {
                $style .= '--title-color: ' . $title_color . ';';
            }

            if ($desc_color) {
                $style .= '--desc-color: ' . $desc_color . ';';
            }

            if ($icon_color) {
                $style .= '--icon-color: ' . $icon_color . ';';
            }

            if ($icon_bg_color) {
                $style .= '--icon-bg-color: ' . $icon_bg_color . ';';
            }

            $style .= '}';
        }
        if ($title_font || $desc_font) {
            if ($title_font) {
                $style .= '#' . $widgetId . ' .fon-contentbox-title{';
                $style .= self::parseFontProperties($title_font);
                $style .= '}';
            }

            if ($desc_font) {
                $style .= '#' . $widgetId . ' .fon-contentbox-content{';
                $style .= self::parseFontProperties($desc_font);
                $style .= '}';
            }
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = 'd-flex ';

        if ($content->media_position == 'top') {
            $attributes .= 'flex-column justify-content-center ';

            switch ($content->align) {
            case 'left':
                $attributes .= 'align-items-start text-start';
                break;
            case 'right':
                $attributes .= 'align-items-end text-end';
                break;
            case 'center':
                $attributes .= 'align-items-center text-center';
                break;
            }
        }
        else {
            if ($content->media_position == 'left') {
                $attributes .= 'justify-content-start text-start ';
            }
            else if ($content->media_position == 'right') {
                $attributes .= 'justify-content-end text-end ';
            }
            if (isset($content->vertical_align) && $content->vertical_align) {
                switch ($content->vertical_align) {
                case 'top':
                    $attributes .= 'align-items-start';
                    break;
                case 'bottom':
                    $attributes .= 'align-items-end';
                    break;
                case 'center':
                    $attributes .= 'align-items-center';
                    break;
                }
            }
        }

        $carouselData = '';
        $isCarousel = false;

        if ($content->use_carousel == 'yes') {
            $isCarousel = true;
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel contentbox-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl : '');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-content-box-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<div class="' . $containerClass . '" ' . $carouselData . '>';

        if ($content->items) {
            $cicount = 1;

            foreach ($content->items as $contentBox) {
                $show_icon = isset($contentBox->show_button_icon) && $contentBox->show_button_icon = ('yes' ? true : false);
                $link_icon = (isset($contentBox->button_icon) && $contentBox->button_icon ? $contentBox->button_icon : '');
                $link_target = (isset($contentBox->link_target) && $contentBox->link_target ? $contentBox->link_target : '_self');
                $link_icon_position = (isset($contentBox->button_icon_position) && $contentBox->button_icon_position ? $contentBox->button_icon_position : 'right');
                $contentBoxImage = '';

                if (is_object($contentBox->image)) {
                    $contentBoxImage = (isset($contentBox->image->{$this->lang}) && $contentBox->image->{$this->lang} ? $contentBox->image->{$this->lang} : array_values((array) $contentBox->image)[0] ?? '');
                }
                else if (is_string($contentBox->image)) {
                    $contentBoxImage = $contentBox->image;
                }

                $contentBox->image = ($contentBoxImage ? static::assetLinkDetermine($contentBoxImage) : $lazyPlaceholder);
                $imageDimensions = static::getImageDimensions($contentBox->image, $pageData['badress']);
                $content_box_title = (isset($contentBox->content_box_title->{$this->lang}) && $contentBox->content_box_title->{$this->lang} ? $contentBox->content_box_title->{$this->lang} : array_values((array) $contentBox->content_box_title)[0] ?? '');
                $content_box_title = self::getPriceHolders($content_box_title);
                $content_box_content = (isset($contentBox->content_box_content->{$this->lang}) && $contentBox->content_box_content->{$this->lang} ? $contentBox->content_box_content->{$this->lang} : array_values((array) $contentBox->content_box_content)[0] ?? '');
                $content_box_content = self::getPriceHolders($content_box_content);
                $content_box_link_text = (isset($contentBox->link_text->{$this->lang}) && $contentBox->link_text->{$this->lang} ? $contentBox->link_text->{$this->lang} : array_values((array) $contentBox->link_text)[0] ?? '');
                $image_alt = (isset($contentBox->image_alt->{$this->lang}) && $contentBox->image_alt->{$this->lang} ? $contentBox->image_alt->{$this->lang} : (isset($contentBox->image_alt) ? array_values((array) $contentBox->image_alt)[0] ?? '' : ''));
                $image_title = (isset($contentBox->image_title->{$this->lang}) && $contentBox->image_title->{$this->lang} ? $contentBox->image_title->{$this->lang} : (isset($contentBox->image_title) ? array_values((array) $contentBox->image_title)[0] ?? '' : ''));

                if (empty($image_alt)) {
                    if (!empty($content_box_title)) {
                        $image_alt = $content_box_title;
                    }
                    else if (!empty($image_title)) {
                        $image_alt = $image_title;
                    }
                    else {
                        $image_alt = basename($contentBox->image);
                    }
                }

                if (empty($image_title)) {
                    if (!empty($content_box_title)) {
                        $image_title = $content_box_title;
                    }
                    else if (!empty($image_alt)) {
                        $image_title = $image_alt;
                    }
                    else {
                        $image_title = basename($contentBox->image);
                    }
                }
                $link_rel = (isset($contentBox->link_rel) && $contentBox->link_rel ? $contentBox->link_rel : []);
                $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');

                if (!$isCarousel) {
                    $output .= '<div class="col">';
                }

                include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'content_box' . DS . 'style_' . $content->widget_style . '.php';

                if (!$isCarousel) {
                    $output .= '</div>';
                }

                ++$cicount;
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function countdown_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        $style .= '#' . $widgetId . ' .fon-countdown-timer {';
        if (isset($content->background) && $content->background) {
            $style .= '--fon-countdown-background: ' . $content->background . ';';
        }
        if (isset($content->number_size) && $content->number_size) {
            $style .= '--fon-countdown-number-size: ' . $content->number_size . 'px;';
        }
        if (isset($content->number_color) && $content->number_color) {
            $style .= '--fon-countdown-number-color: ' . $content->number_color . ';';
        }
        if (isset($content->text_size) && $content->text_size) {
            $style .= '--fon-countdown-text-size: ' . $content->text_size . 'px;';
        }
        if (isset($content->text_color) && $content->text_color) {
            $style .= '--fon-countdown-text-color: ' . $content->text_color . ';';
        }
        if (isset($content->padding) && $content->padding) {
            $style .= '--fon-countdown-padding: ' . $content->padding . 'px;';
        }
        if (isset($content->margin) && $content->margin) {
            $style .= '--fon-countdown-margin: ' . $content->padding . 'px;';
        }
        if (isset($content->border) && $content->border) {
            $style .= '--fon-countdown-border: ' . $content->border . ';';
        }
        if (isset($content->radius) && $content->radius) {
            $style .= '--fon-countdown-radius: ' . $content->radius . 'px;';
        }
        if (isset($content->shadow) && $content->shadow) {
            $style .= '--fon-countdown-shadow: ' . $content->shadow . ';';
        }
        if (isset($content->gap) && $content->gap) {
            $style .= '--fon-countdown-gap: ' . $content->gap . 'px;';
        }
        if (isset($content->divider_color) && $content->divider_color) {
            $style .= '--fon-countdown-divider-color: ' . $content->divider_color . ';';
        }
        if (isset($content->divider) && $content->divider != 'none') {
            $style .= '--fon-countdown-divider-right: -' . ($content->gap / 2) . 'px;';
        }

        $style .= '}';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = '';

        switch ($content->align) {
        case 'left':
            $attributes = 'justify-content-start text-start';
            break;
        case 'right':
            $attributes = 'justify-content-end text-end';
            break;
        case 'center':
            $attributes = 'justify-content-center text-center';
            break;
        }

        $output = '';
        $dateLangs = ['day' => ___('date/day'), 'hour' => ___('date/hour'), 'minute' => ___('date/minute'), 'second' => ___('date/second')];
        $dateString = $content->date . ' ' . $content->time . ':00';
        $dateString = date('Y/m/d H:i:s', strtotime($dateString));
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-countdown ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<div class="fon-countdown-timer ' . $attributes . ' divider-' . $content->divider . '  text-position-' . $content->text_position . '" data-enddate="' . $dateString . '" data-lang="' . htmlentities(json_encode($dateLangs), ENT_QUOTES, 'UTF-8') . '" data-message="' . strip_tags($content->message) . '"></div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function cost_calculator_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $class = (isset($content->fon_class) && $content->fon_class ? $content->fon_class : '');
        $show_title = (isset($content->show_name) && $content->show_name == 'yes' ? true : false);
        $title = __('website/account_sms/introduction-calculate-title');

        if ($show_title) {
            $title = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : $title);
        }

        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="card fon-cost-calculator rounded-4 text-center international-sms-calculate ' . $class . '">';
        $output .= '<div class="card-header bg-white py-3">';
        $output .= '<h3 class="card-title fs-5 fw-semibold text-theme-secondary mb-0">' . $title . '</h3>';
        $output .= '</div>';
        $output .= '<div class="card-body" style="background: url(' . $pageData['tadress'] . 'images/map.svg) no-repeat scroll center;">';
        $output .= '<select id="countries" class="form-select">';
        $output .= '<option value="">' . __('website/account_sms/introduction-calculate-select-country') . '</option>';

        foreach ($pageData['country_prices'] as $country) {
            $cc = $country['cc'];
            $prices = $country['prices'];
            $output .= '<option ' . ($cc == $pageData['default_country'] ? 'selected' : '') . "\n" . '                                value="' . $cc . '"' . "\n" . '                                data-prices=\'' . Utility::jencode($prices) . '\'' . "\n" . '                                data-pre-register="' . ($country['pre-register'] ? 'true' : 'false') . '"' . "\n" . '                                data-image="' . $pageData['sadress'] . 'assets/images/flags/' . $cc . '.svg' . '">' . $country['name'] . ' </option>';
        }

        $output .= '</select>';
        $output .= '<div id="calculateResult" style="display: none;">';
        $output .= '<p class="my-4">' . __('website/account_sms/introduction-calculate-note') . ' </p>';
        $currs = [];
        $defCurr = '';
        $currencies = [];

        foreach (Money::getCurrencies() as $row) {
            if ($row['id'] == $pageData['ucid']) {
                array_unshift($currencies, $row);
            }
            else {
                array_push($currencies, $row);
            }
        }

        $output .= '<div class="d-flex justify-content-center flex-wrap gap-2 mb-3">';

        foreach ($currencies as $curr) {
            $currs[] = $curr['code'];

            if ($curr['id'] == $pageData['ucid']) {
                $defCurr = $curr['code'];
            }

            $output .= '<a id="currency-button-' . $curr['code'] . ' " class="' . ($curr['id'] == $pageData['ucid'] ? 'active ' : '') . '  btn btn-outline-primary currency-button" href="javascript:setCurrency(\'' . $curr['code'] . '\');void(0);">' . $curr['code'] . ' </a>';
        }

        $output .= '</div>';
        $output .= '<h3 id="country-name">?</h3>';
        $output .= '<h4 class="fs-5">';

        foreach ($currs as $curr) {
            $output .= '<span id="currency-' . $curr . '" ' . ($defCurr == $curr ? '' : 'style="display: none;"') . '  class="currency-content">' . "\n" . '                            1 SMS = <span id="calculate-' . $curr . '-amount">0</span> <span style="font-size:20px;">' . $curr . '</span><br>' . "\n" . '                            <span class="amount-thousands">(1000 SMS = <span id="calculate-' . $curr . '-amount-thousands">0</span> ' . $curr . ' )</span>' . "\n" . '                            </span>';
        }

        $output .= '</h2>';
        $output .= '<div class="fs-12" id="country_pre_register">' . __('website/account_sms/introduction-calculate-pre-register-note') . ' </div>';
        $output .= '<input type="hidden" id="defCurrency" value="' . $defCurr . ' ">';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '<div class="card-footer bg-white d-grid">';
        $output .= '<a class="btn btn-secondary btn-lg" href="' . $pageData['download_prices'] . ' /' . $defCurr . ' " id="download_prices" target="_blank">' . __('website/account_sms/introduction-download-prices') . ' </a>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'default');
        $slogan = (isset($content->slogan) && $content->slogan ? (array) $content->slogan : [$this->lang => __('website/domain/slogan', ['{price}' => '{{domain:com:register}}'])]);
        $show_ai = (isset($content->show_ai) && $content->show_ai == 'yes' ? true : false);
        $ai_button_title = self::getFieldMultilingualText($content->ai_button_title, $this->lang, __('theme/domain/ai_button_title'));
        $classic_button_title = self::getFieldMultilingualText($content->classic_button_title, $this->lang, __('theme/domain/classic_button_title'));
        $contentTitle = self::getFieldMultilingualText($content->title, $this->lang, '');
        $button_text = self::getFieldMultilingualText($content->button_text, $this->lang, __('website/index/domain-check-query-button'));
        $tld_title = self::getFieldMultilingualText($content->tld_title, $this->lang, __('website/domain/meta/title'));
        $tld_register = self::getFieldMultilingualText($content->tld_register, $this->lang, __('admin/orders/create-domain-transaction-register'));
        $input_placeholders = self::getFieldMultilingualText($content->input_placeholders, $this->lang, __('theme/domain/input_placeholders'));

        if ($input_placeholders) {
            $input_placeholders = (!is_array($input_placeholders) ? explode(PHP_EOL, $input_placeholders) : $input_placeholders);
        }
        else {
            $input_placeholders = __('theme/domain/input_placeholders');
        }

        $input_placeholders = htmlspecialchars(json_encode($input_placeholders, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $assets = ['type-placeholder'];

        if ($show_ai) {
            $assets[] = 'fon-ai-domain-suggest';
            $aiConfig = Modules::Config('Addons', 'FonPageBuilder');
            if (isset($aiConfig['ai']['tlds']) && $aiConfig['ai']['tlds']) {
                $aiTlds = (is_string($aiConfig['ai']['tlds']) ? explode(',', $aiConfig['ai']['tlds']) : $aiConfig['ai']['tlds']);
                $aiTlds = array_map('trim', $aiTlds);
            }
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' && $content->show_tlds == 'yes' ? true : false);
        $carouselData = '';

        if ($isCarousel) {
            $assets[] = 'slick';
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
        }

        $this->addAsset($assets);
        $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
        $form_action = (isset($pageData['domain']) && $pageData['domain']['tlds'] ? $pageData['domain']['form_action'] : Controllers::$init->CRLink('domain'));

        if ($content->show_tlds == 'yes') {
            $spotlights = ($pageData['page'] == 'index' ? ___('blocks/home-domain-check/items', false, $this->lang) : __('website/domain/spotlight-tlds', false, $this->lang));
            if (is_array($spotlights) && !empty($spotlights)) {
                $wherein = implode('\',\'', $spotlights);
                $tlds = self::getTldList($wherein);
            }
            else {
                $tlds = [];
            }

            if ($tlds) {
                $firstPrice = self::getPriceHolders($slogan[$this->lang]);
            }
        }
        else if ($content->show_slogan) {
            $firstPrice = self::getPriceHolders($slogan[$this->lang]);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-widget ' . $content->fon_class . ' ' . ($show_ai ? 'domain-ai-enabled' : '') . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain' . DS . 'style_' . $widget_style . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_form_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $firstPrice = (isset($pageData['domain']['firstPrice']) ? $pageData['domain']['firstPrice'] : '');
        $box_tldList = (isset($pageData['domain']['tlds']) ? $pageData['domain']['tlds'] : false);
        $tldList = (isset($pageData['domain']['tldList']) ? $pageData['domain']['tldList'] : false);
        $tldList = ($tldList ? $tldList : self::getTldList());
        $captcha = (isset($pageData['domain']['captcha']) ? $pageData['domain']['captcha'] : false);
        $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
        $formAction = (isset($pageData['domain']['form_action']) ? $pageData['domain']['form_action'] : Controllers::$init->CRLink('domain'));
        $register_link = Controllers::$init->CRLink('domain');
        $transfer_link = Controllers::$init->CRLink('domain-transfer');
        $whois_link = Controllers::$init->CRLink('domain-whois');
        $show_ai = (isset($content->show_ai) && $content->show_ai == 'yes' ? true : false);
        $ai_button_title = self::getFieldMultilingualText($content->ai_button_title, $this->lang, __('theme/domain/ai_button_title'));
        $classic_button_title = self::getFieldMultilingualText($content->classic_button_title, $this->lang, __('theme/domain/classic_button_title'));
        $form_type = (isset($content->form_type) && $content->form_type ? $content->form_type : 'domain');
        $form_title = self::getFieldMultilingualText($content->form_title, $this->lang, '');
        $form_description = (isset($content->form_description->{$this->lang}) && $content->form_description->{$this->lang} ? self::getPriceHolders($content->form_description->{$this->lang}) : __('website/domain/slogan', ['{price}' => $firstPrice]));
        $form_align = (isset($content->form_align) && $content->form_align ? $content->form_align : (object) ['xl' => 'center', 'lg' => 'center', 'md' => 'center', 'sm' => 'center', 'xs' => 'center']);
        $show_tlds = (isset($content->show_tlds) && $content->show_tlds == 'yes' ? true : false);
        $widgetTlds = (isset($content->tld_list) && $content->tld_list != 'none' ? explode(',', trim(str_replace('items:', '', $content->tld_list))) : false);
        $show_register = (isset($content->show_register) && $content->show_register == 'yes' ? true : false);
        $register_title = self::getFieldMultilingualText($content->register_title, $this->lang, __('theme/domain/register-title'));
        $show_transfer = (isset($content->show_transfer) && $content->show_transfer == 'yes' ? true : false);
        $transfer_title = self::getFieldMultilingualText($content->transfer_title, $this->lang, __('theme/domain/transfer-title'));
        $show_whois = (isset($content->show_whois) && $content->show_whois == 'yes' ? true : false);
        $whois_title = self::getFieldMultilingualText($content->whois_title, $this->lang, __('theme/domain/whois-title'));
        $show_captcha = (isset($content->show_captcha) && $content->show_captcha == 'yes' ? true : false);
        $input_placeholders = self::getFieldMultilingualText($content->input_placeholders, $this->lang, __('theme/domain/input_placeholders'));

        if ($input_placeholders) {
            $input_placeholders = (!is_array($input_placeholders) ? explode(PHP_EOL, $input_placeholders) : $input_placeholders);
        }
        else {
            $input_placeholders = __('theme/domain/input_placeholders');
        }

        $input_placeholders = htmlspecialchars(json_encode($input_placeholders, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8');
        $alignClass = '';
        $justifyClass = '';

        foreach ($form_align as $key => $align) {
            $alignClass .= ($key == 'xs' ? 'text-' : 'text-' . $key . '-');
            $justifyClass .= ($key == 'xs' ? 'justify-content-' : 'justify-content-' . $key . '-');

            if ($align == 'left') {
                $alignClass .= 'start ';
                $justifyClass .= 'start ';
            }
            else if ($align == 'right') {
                $alignClass .= 'end ';
                $justifyClass .= 'end ';
            }
            else {
                $alignClass .= 'center ';
                $justifyClass .= 'center ';
            }
        }

        $style = '';
        $style .= '#' . $widgetId . ' .fon-domain-form-title{';
        if (isset($content->form_title_color) && $content->form_title_color) {
            $style .= 'color: ' . $content->form_title_color . ';';
        }
        if (isset($content->form_title_font) && $content->form_title_font) {
            $style .= self::parseFontProperties($content->form_title_font);
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-domain-form-description{';
        if (isset($content->form_description_color) && $content->form_description_color) {
            $style .= 'color: ' . $content->form_description_color . ';';
        }
        if (isset($content->form_description_font) && $content->form_description_font) {
            $style .= self::parseFontProperties($content->form_description_font);
        }

        $style .= '}';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        if ($show_ai) {
            $this->addAsset(['type-placeholder', 'fon-ai-domain-suggest']);
            $aiConfig = Modules::Config('Addons', 'FonPageBuilder');
            if (isset($aiConfig['ai']['tlds']) && $aiConfig['ai']['tlds']) {
                $aiTlds = (is_string($aiConfig['ai']['tlds']) ? explode(',', $aiConfig['ai']['tlds']) : $aiConfig['ai']['tlds']);
                $aiTlds = array_map('trim', $aiTlds);
            }
        }
        else {
            $this->addAsset('type-placeholder');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-form-widget ' . $form_type . ' ' . $content->fon_class . ' ' . ($show_ai ? 'domain-ai-enabled' : '') . '">';
        $output .= '<div class="fon-widget-content ' . $alignClass . '">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain_form' . DS . $form_type . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_tlds_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $currency_symbols = (isset($pageData['currency_symbols']) ? $pageData['currency_symbols'] : self::getCurrencySymbols());
        $tldList = (isset($pageData['domain']['tldList']) ? $pageData['domain']['tldList'] : false);
        $tldList = ($tldList ? $tldList : self::getTldList());
        $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'default');
        $widgetTlds = (isset($content->tld_list) && $content->tld_list != 'none' ? explode(',', trim(str_replace('items:', '', $content->tld_list))) : false);
        $tld_limit = (isset($content->tld_limit) && $content->tld_limit ? $content->tld_limit : 10);
        $tld_price_type = (isset($content->tld_price_type) && $content->tld_price_type ? $content->tld_price_type : 'register');
        $show_images = (isset($content->tld_images) && $content->tld_images == 'yes' ? true : false);
        $show_register = (isset($content->show_register) && $content->show_register == 'yes' ? true : false);
        $register_link = (isset($content->register_link) && $content->register_link ? $content->register_link : Controllers::$init->CRLink('domain'));
        $register_title = (isset($content->register_title->{$this->lang}) && $content->register_title->{$this->lang} ? $content->register_title->{$this->lang} : __('theme/domain/register-title'));
        $inline_register = false;
        if (strpos($register_link, 'http://') === false || strpos($register_link, 'https://') === false) {
            $inline_register = true;
        }
        $show_transfer = (isset($content->show_transfer) && $content->show_transfer == 'yes' ? true : false);
        $transfer_link = Controllers::$init->CRLink('domain-transfer');
        $transfer_title = (isset($content->transfer_title->{$this->lang}) && $content->transfer_title->{$this->lang} ? $content->transfer_title->{$this->lang} : __('theme/domain/transfer-title'));
        $show_slogan = (isset($content->show_slogan) && $content->show_slogan == 'yes' ? true : false);
        $tld_slogan = (isset($content->tld_slogan->{$this->lang}) && $content->tld_slogan->{$this->lang} ? $content->tld_slogan->{$this->lang} : __('website/domain/slogan'));
        $column = (isset($content->column) && $content->column ? $content->column : (object) ['xl' => 5, 'lg' => 4, 'md' => 3, 'sm' => 2, 'xs' => 1]);
        $row = (isset($content->row) && $content->row ? $content->row : (object) ['xl' => 1, 'lg' => 1, 'md' => 1, 'sm' => 1, 'xs' => 1]);
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $carouselData = '';
        $columns = [];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-row="' . $content->use_row . '" data-rows="' . htmlspecialchars(Utility::jencode($row, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel spotlight-tld-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl;
        }

        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-tlds-widget ' . $content->fon_class . '">';
        $output .= '<div class="spot-tld-list tld-image ' . $containerClass . '" ' . $carouselData . '  id="spot-tld-lists">';
        $count = 1;

        foreach ($tldList as $tld) {
            if ($widgetTlds && !in_array($tld['id'], $widgetTlds)) {
                continue;
            }
            if (!$widgetTlds && $tld_limit < $count) {
                break;
            }

            $tld_image = false;

            if ($show_images) {
                foreach (['svg', 'png', 'jpg'] as $ext) {
                    $img_path = 'images' . DS . 'tldlogos' . DS . $tld['name'] . '.' . $ext;

                    if (file_exists(View::$init->get_template_dir() . $img_path)) {
                        $tld_image = $img_path;
                        $imageDimensions = static::getImageDimensions($pageData['tadress'] . $img_path, $pageData['badress']);
                    }
                }
            }
            if ($tld['promo_status'] && (substr($tld['promo_duedate'], 0, 4) == '1881') || DateManager::strtotime() < DateManager::strtotime($tld['promo_duedate'] . ' 23:59:59')) {
                if (0 < $tld['promo_register_price']) {
                    if (0 < $tld['reg_price']['amount']) {
                        $tld['reg_price']['discount'] = round((($tld['reg_price']['amount'] - $tld['promo_register_price']) / $tld['reg_price']['amount']) * 100, 2);
                    }
                    else {
                        $tld['reg_price']['discount'] = 0;
                    }

                    $tld['reg_price']['amount'] = $tld['promo_register_price'];
                }

                if (0 < $tld['promo_transfer_price']) {
                    if (0 < $tld['tra_price']['amount']) {
                        $tld['tra_price']['discount'] = round((($tld['tra_price']['amount'] - $tld['promo_transfer_price']) / $tld['tra_price']['amount']) * 100, 2);
                    }
                    else {
                        $tld['tra_price']['discount'] = 0;
                    }

                    $tld['tra_price']['amount'] = $tld['promo_transfer_price'];
                }
            }

            $registerPrice = self::calculatePrices([$tld['reg_price']], $currency_symbols, $domain_override_uscurrency, 'domain');
            $transferPrice = self::calculatePrices([$tld['tra_price']], $currency_symbols, $domain_override_uscurrency, 'domain');
            $renewPrice = self::calculatePrices([$tld['ren_price']], $currency_symbols, $domain_override_uscurrency, 'domain');

            if ($tld_price_type == 'transfer') {
                $registerPrice = $transferPrice;
            }
            else if ($tld_price_type == 'renew') {
                $registerPrice = $renewPrice;
            }

            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain_tlds' . DS . 'style_' . $widget_style . '.php';
            ++$count;
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_prices_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $currency_symbols = (isset($pageData['currency_symbols']) ? $pageData['currency_symbols'] : self::getCurrencySymbols());
        $tldList = (isset($pageData['domain']['tldList']) ? $pageData['domain']['tldList'] : false);
        $tldList = ($tldList ? $tldList : self::getTldList());
        $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
        $show_search = (isset($content->show_search) && $content->show_search == 'yes' ? true : false);
        $use_pagination = (isset($content->use_pagination) && $content->use_pagination == 'yes' ? true : false);
        $pagination_type = (isset($content->pagination_type) && $content->pagination_type ? $content->pagination_type : 'pagination');
        $pagination_limit = (isset($content->pagination_limit) && $content->pagination_limit ? $content->pagination_limit : 10);
        $page_type = (isset($pageData['page']) ? $pageData['page'] : 'domain');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-prices-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain_prices' . DS . $page_type . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function domain_faqs_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $page_type = (isset($pageData['page']) ? $pageData['page'] : 'domain');
        $faqs = (isset($pageData['domain']['faqs']) ? $pageData['domain']['faqs'] : false);
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'default');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        if ($faqs && is_array($faqs) && count($faqs)) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-domain-faqs-widget ' . $content->fon_class . '">';
            $output .= '<div class="fon-widget-content">';
            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'domain_faqs' . DS . 'style_' . $widget_style . '.php';
            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function faqs_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $widget_style = 'default';
        $category = (isset($content->category) && $content->category ? $content->category : 'hosting:none');
        list($categoryType, $categoryId) = explode(':', $category);
        $faqs = ___('constants/category-' . $categoryType . '/faq');
        if ($categoryType && $categoryId) {
            if ($categoryId != 'none') {
                $categoryInfo = $this->getCategory($categoryId, 'products', $categoryType);
                if (isset($categoryInfo['faqs']) && !empty($categoryInfo['faqs'])) {
                    $faqs = Utility::jdecode($categoryInfo['faqs'], true);
                }
            }
        }

        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        if ($faqs && is_array($faqs) && count($faqs)) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-' . $categoryType . '-faqs-widget ' . $content->fon_class . '">';
            $output .= '<div class="fon-widget-content">';
            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'faqs' . DS . 'style_' . $widget_style . '.php';
            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function feature_box_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';

        if ($content->widget_style == 'custom') {
            if (($content->media_type != 'icon') && $content->image_width && $content->image_height) {
                $style .= '#' . $widgetId . ' .feature-image{';
                $style .= 'width:' . ($content->image_width && $content->image_width ? $content->image_width . 'px' : '100%') . ';';
                $style .= 'height:' . ($content->image_height && $content->image_height ? $content->image_height . 'px' : 'auto') . ';';
                $style .= '}';
            }

            if ($content->media_type != 'image') {
                $style .= '#' . $widgetId . ' .feature-icon{';
                if (isset($content->icon_size) && $content->icon_size) {
                    $style .= 'font-size:' . $content->icon_size . 'px;';
                    $style .= 'width:' . $content->icon_size . 'px;';
                    $style .= 'height:' . $content->icon_size . 'px;';
                    $style .= 'line-height:' . $content->icon_size . 'px;';
                }
                if (isset($content->icon_color_type) && $content->icon_color_type == 'flat') {
                    $style .= '--bs-normal-color:' . $content->icon_color->normal . ';';
                    $style .= '--bs-hover-color:' . $content->icon_color->hover . ';';
                }
                else if (isset($content->icon_color_type) && $content->icon_color_type == 'gradient') {
                    $style .= self::parseGradient($content->icon_gradient->normal, 'normal-color');
                    $style .= self::parseGradient($content->icon_gradient->hover, 'hover-color');
                }

                $style .= '}';
            }

            $style .= '#' . $widgetId . ' .feature-box-media-container{';
            if (isset($content->media_border->normal) && $content->media_border->normal) {
                $style .= '--bs-normal-border:' . $content->media_border->normal . ';';
            }
            if (isset($content->media_border->hover) && $content->media_border->hover) {
                $style .= '--bs-hover-border:' . $content->media_border->hover . ';';
            }
            if (isset($content->media_radius->normal) && $content->media_radius->normal) {
                $style .= '--bs-normal-radius:' . $content->media_radius->normal . 'px;';
            }
            if (isset($content->media_radius->hover) && $content->media_radius->hover) {
                $style .= '--bs-hover-radius:' . $content->media_radius->hover . 'px;';
            }
            if (isset($content->media_shadow->normal) && $content->media_shadow->normal) {
                $style .= '--bs-normal-shadow:' . $content->media_shadow->normal . ';';
            }
            if (isset($content->media_shadow->hover) && $content->media_shadow->hover) {
                $style .= '--bs-hover-shadow:' . $content->media_shadow->hover . ';';
            }
            if (isset($content->media_background_type) && $content->media_background_type == 'flat') {
                $style .= '--bs-normal-bg:' . $content->media_background->normal . ';';
                $style .= '--bs-hover-bg:' . $content->media_background->hover . ';';
            }
            else if (isset($content->media_background_type) && $content->media_background_type == 'gradient') {
                $style .= self::parseGradient($content->media_gradient->normal, 'normal-bg');
                $style .= self::parseGradient($content->media_gradient->hover, 'hover-bg');
            }
            if (isset($content->media_padding) && $content->media_padding) {
                $style .= 'padding:' . $content->media_padding . ';';
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .feature-box-title, #' . $widgetId . ' .feature-box-title a{';
            if (isset($content->title_color->normal) && $content->title_color->normal) {
                $style .= '--bs-normal-color:' . $content->title_color->normal . ';';
            }
            if (isset($content->title_color->hover) && $content->title_color->hover) {
                $style .= '--bs-hover-color:' . $content->title_color->hover . ';';
            }

            if (isset($content->title_font)) {
                $style .= self::parseFontProperties($content->title_font);
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .feature-box-desc{';
            if (isset($content->content_color->normal) && $content->content_color->normal) {
                $style .= '--bs-normal-color:' . $content->content_color->normal . ';';
            }
            if (isset($content->content_color->hover) && $content->content_color->hover) {
                $style .= '--bs-hover-color:' . $content->content_color->hover . ';';
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .feature-box{';
            if (isset($content->background_type) && $content->background_type == 'flat') {
                $style .= '--bs-normal-bg:' . $content->background->normal . ';';
                $style .= '--bs-hover-bg:' . $content->background->hover . ';';
            }
            else if (isset($content->background_type) && $content->background_type == 'gradient') {
                $style .= self::parseGradient($content->background_gradient->normal, 'normal-bg');
                $style .= self::parseGradient($content->background_gradient->hover, 'hover-bg');
            }
            else if (isset($content->background_type) && $content->background_type == 'image') {
                $style .= 'background:url(' . self::assetLinkDetermine($content->background_image) . ') no-repeat scroll center center / cover;';
            }
            if (isset($content->shadow->normal) && $content->shadow->normal) {
                $style .= '--bs-normal-shadow:' . $content->shadow->normal . ';';
            }
            if (isset($content->shadow->hover) && $content->shadow->hover) {
                $style .= '--bs-hover-shadow:' . $content->shadow->hover . ';';
            }
            if (isset($content->border_radius->normal) && $content->border_radius->normal) {
                $style .= '--bs-normal-radius:' . $content->border_radius->normal . 'px;';
            }
            if (isset($content->border_radius->hover) && $content->border_radius->hover) {
                $style .= '--bs-hover-radius:' . $content->border_radius->hover . 'px;';
            }
            if (isset($content->use_border) && $content->use_border == 'yes') {
                if (isset($content->border->normal) && $content->border->normal) {
                    $style .= '--bs-normal-border:' . $content->border->normal . ';';
                }
                if (isset($content->border->hover) && $content->border->hover) {
                    $style .= '--bs-hover-border:' . $content->border->hover . ';';
                }
            }
            if (isset($content->padding) && $content->padding) {
                $style .= 'padding:' . $content->padding . 'px;';
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = '';

        if ($content->media_position == 'top') {
            $attributes .= 'justify-content-center ';

            switch ($content->align) {
            case 'left':
                $attributes .= 'align-items-start ';
                break;
            case 'right':
                $attributes .= 'align-items-end ';
                break;
            case 'center':
                $attributes .= 'align-items-center ';
                break;
            }
        }
        else {
            if ($content->media_position == 'left') {
                $attributes .= 'justify-content-start ';
            }
            else if ($content->media_position == 'right') {
                $attributes .= 'justify-content-end ';
            }
            if (isset($content->vertical_align) && $content->vertical_align) {
                switch ($content->vertical_align) {
                case 'top':
                    $attributes .= 'align-items-start ';
                    break;
                case 'bottom':
                    $attributes .= 'align-items-end ';
                    break;
                case 'center':
                    $attributes .= 'align-items-center ';
                    break;
                }
            }
        }

        switch ($content->align) {
        case 'left':
            $attributes .= 'text-start';
            break;
        case 'right':
            $attributes .= 'text-end';
            break;
        case 'center':
            $attributes .= 'text-center';
            break;
        }

        if ($content->widget_style != 'custom') {
            if (isset($content->use_shadow) && $content->use_shadow == 'yes') {
                $attributes .= ' with-shadow';
            }
        }

        $image = '';

        if (is_object($content->image)) {
            $image = (isset($content->image->{$this->lang}) && $content->image->{$this->lang} ? $content->image->{$this->lang} : array_values((array) $content->image)[0] ?? '');
        }
        else if (is_string($content->image)) {
            $image = $content->image;
        }

        $content->image = ($image ? static::assetLinkDetermine($image) : $lazyPlaceholder);
        $imageDimensions = static::getImageDimensions($image, $pageData['badress']);
        $content_title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $content_title = self::getPriceHolders($content_title);
        $content_content = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');
        $content_content = self::getPriceHolders($content_content);
        $content_link = (isset($content->link->{$this->lang}) && $content->link->{$this->lang} ? $content->link->{$this->lang} : array_values((array) $content->link)[0] ?? '');
        $content_button_text = (isset($content->button_text->{$this->lang}) && $content->button_text->{$this->lang} ? $content->button_text->{$this->lang} : array_values((array) $content->button_text)[0] ?? '');
        $image_alt = (isset($content->image_alt->{$this->lang}) && $content->image_alt->{$this->lang} ? $content->image_alt->{$this->lang} : (isset($content->image_alt) ? array_values((array) $content->image_alt)[0] ?? '' : ''));
        $image_title = (isset($content->image_title->{$this->lang}) && $content->image_title->{$this->lang} ? $content->image_title->{$this->lang} : (isset($content->image_title) ? array_values((array) $content->image_title)[0] ?? '' : ''));
        $link_rel = (isset($content->link_rel) && $content->link_rel ? $content->link_rel : []);
        $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');

        if (empty($image_alt)) {
            if (!empty($content_title)) {
                $image_alt = $content_title;
            }
            else if (!empty($image_title)) {
                $image_alt = $image_title;
            }
            else {
                $image_alt = basename($content->image);
            }
        }

        if (empty($image_title)) {
            if (!empty($title)) {
                $image_title = $title;
            }
            else if (!empty($image_alt)) {
                $image_title = $image_alt;
            }
            else {
                $image_title = basename($content->image);
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-feature-box-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'feature_box' . DS . 'style_' . $content->widget_style . '.php';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function flipbox_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $front_text = (isset($content->front_text) && isset($content->front_text->{$this->lang}) && $content->front_text->{$this->lang} ? $content->front_text->{$this->lang} : (isset($content->front_text) ? array_values((array) $content->front_text)[0] ?? '' : ''));
        $front_align = (isset($content->front_align) && $content->front_align ? $content->front_align : 'center_center');
        $front_text_color = (isset($content->front_text_color) && $content->front_text_color ? $content->front_text_color : '');
        $front_bg_type = (isset($content->front_bg_type) && $content->front_bg_type ? $content->front_bg_type : 'color');
        $front_bg_color = (isset($content->front_bg_color) && $content->front_bg_color ? $content->front_bg_color : '');
        $front_bg_image = (isset($content->front_bg_image) && isset($content->front_bg_image->{$this->lang}) && $content->front_bg_image->{$this->lang} ? $content->front_bg_image->{$this->lang} : (isset($content->front_bg_image) ? array_values((array) $content->front_bg_image)[0] ?? '' : ''));
        $front_bg_image = ($front_bg_image ? static::assetLinkDetermine($front_bg_image) : $lazyPlaceholder);
        $front_bg_gradient = (isset($content->front_bg_gradient) && $content->front_bg_gradient ? $content->front_bg_gradient : '');
        $front_border = (isset($content->front_border) && $content->front_border ? $content->front_border : '');
        $front_radius = (isset($content->front_radius) && $content->front_radius ? $content->front_radius : 0);
        $front_shadow = (isset($content->front_shadow) && $content->front_shadow ? $content->front_shadow : '');
        $back_text = (isset($content->back_text) && isset($content->back_text->{$this->lang}) && $content->back_text->{$this->lang} ? $content->back_text->{$this->lang} : (isset($content->back_text) ? array_values((array) $content->back_text)[0] ?? '' : ''));
        $back_align = (isset($content->back_align) && $content->back_align ? $content->back_align : 'center_center');
        $back_text_color = (isset($content->back_text_color) && $content->back_text_color ? $content->back_text_color : '');
        $back_bg_type = (isset($content->back_bg_type) && $content->back_bg_type ? $content->back_bg_type : 'color');
        $back_bg_color = (isset($content->back_bg_color) && $content->back_bg_color ? $content->back_bg_color : '');
        $back_bg_image = (isset($content->back_bg_image) && isset($content->back_bg_image->{$this->lang}) && $content->back_bg_image->{$this->lang} ? $content->back_bg_image->{$this->lang} : (isset($content->back_bg_image) ? array_values((array) $content->back_bg_image)[0] ?? '' : ''));
        $back_bg_image = ($back_bg_image ? static::assetLinkDetermine($back_bg_image) : $lazyPlaceholder);
        $back_bg_gradient = (isset($content->back_bg_gradient) && $content->back_bg_gradient ? $content->back_bg_gradient : '');
        $back_border = (isset($content->back_border) && $content->back_border ? $content->back_border : '');
        $back_radius = (isset($content->back_radius) && $content->back_radius ? $content->back_radius : 0);
        $back_shadow = (isset($content->back_shadow) && $content->back_shadow ? $content->back_shadow : '');
        $flip_behavior = (isset($content->flip_behavior) && $content->flip_behavior ? $content->flip_behavior : 'hover');
        $flip_style = (isset($content->flip_style) && $content->flip_style ? $content->flip_style : 'rotate');
        $flip_direction = (isset($content->flip_direction) && $content->flip_direction ? $content->flip_direction : 'left');
        $height = (isset($content->height) && $content->height ? $content->height : '280');
        $fon_class = (isset($content->fon_class) && $content->fon_class ? $content->fon_class : '');
        $style = '';

        if (is_object($height)) {
            $responsiveItems = [
                '.fon-flipbox-panel' . ($flip_style == '3d' ? '-3d' : '') => [
                ['type' => 'height', 'unit' => 'px', 'value' => $height]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        else {
            $style .= '#' . $widgetId . ' .fon-flipbox-panel' . ($flip_style == '3d' ? '-3d' : '') . '{';
            $style .= 'height:' . $height . 'px;';
            $style .= '}';
        }

        $style .= '#' . $widgetId . ' .fon-flipbox-front' . ($flip_style == '3d' ? '-3d' : '') . '{';

        if ($front_text_color) {
            $style .= 'color: ' . $front_text_color . ';';
        }

        if ($front_border) {
            $style .= 'border: ' . $front_border . ';';
        }

        if ($front_radius) {
            $style .= 'border-radius: ' . $front_radius . 'px;';
        }

        if ($front_shadow) {
            $style .= 'box-shadow: ' . $front_shadow . ';';
        }

        if ($front_bg_type == 'color') {
            $style .= 'background-color: ' . $front_bg_color . ';';
        }
        else if ($front_bg_type == 'image') {
            $style .= 'background-color: ' . $front_bg_color . ';';
            $style .= 'background-image: url(' . $front_bg_image . ');';
        }
        else if ($front_bg_type == 'gradient') {
            $style .= 'background-color: ' . $front_bg_color . ';';
            $style .= self::parseGradient($front_bg_gradient) . ';';
        }

        switch ($front_align) {
        case 'top_left':
            $style .= 'justify-content: start;';
            $style .= 'text-align: start;';
            break;
        case 'top_center':
            $style .= 'justify-content: start;';
            $style .= 'text-align: center;';
            break;
        case 'top_right':
            $style .= 'justify-content: start;';
            $style .= 'text-align: end;';
            break;
        case 'center_left':
            $style .= 'justify-content: center;';
            $style .= 'text-align: start;';
            break;
        case 'center_center':
            $style .= 'justify-content: center;';
            $style .= 'text-align: center;';
            break;
        case 'center_right':
            $style .= 'justify-content: center;';
            $style .= 'text-align: end;';
            break;
        case 'bottom_left':
            $style .= 'justify-content: end;';
            $style .= 'text-align: start;';
            break;
        case 'bottom_center':
            $style .= 'justify-content: end;';
            $style .= 'text-align: center;';
            break;
        case 'bottom_right':
            $style .= 'justify-content: end;';
            $style .= 'text-align: end;';
            break;
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-flipbox-back' . ($flip_style == '3d' ? '-3d' : '') . '{';

        if ($back_text_color) {
            $style .= 'color: ' . $back_text_color . ';';
        }

        if ($back_border) {
            $style .= 'border: ' . $back_border . ';';
        }

        if ($back_radius) {
            $style .= 'border-radius: ' . $back_radius . 'px;';
        }

        if ($back_shadow) {
            $style .= 'box-shadow: ' . $back_shadow . ';';
        }

        if ($back_bg_type == 'color') {
            $style .= 'background-color: ' . $back_bg_color . ';';
        }
        else if ($back_bg_type == 'image') {
            $style .= 'background-color: ' . $back_bg_color . ';';
            $style .= 'background-image: url(' . $back_bg_image . ');';
        }
        else if ($back_bg_type == 'gradient') {
            $style .= 'background-color: ' . $back_bg_color . ';';
            $style .= self::parseGradient($back_bg_gradient) . ';';
        }

        switch ($back_align) {
        case 'top_left':
            $style .= 'justify-content: start;';
            $style .= 'text-align: start;';
            break;
        case 'top_center':
            $style .= 'justify-content: start;';
            $style .= 'text-align: center;';
            break;
        case 'top_right':
            $style .= 'justify-content: start;';
            $style .= 'text-align: end;';
            break;
        case 'center_left':
            $style .= 'justify-content: center;';
            $style .= 'text-align: start;';
            break;
        case 'center_center':
            $style .= 'justify-content: center;';
            $style .= 'text-align: center;';
            break;
        case 'center_right':
            $style .= 'justify-content: center;';
            $style .= 'text-align: end;';
            break;
        case 'bottom_left':
            $style .= 'justify-content: end;';
            $style .= 'text-align: start;';
            break;
        case 'bottom_center':
            $style .= 'justify-content: end;';
            $style .= 'text-align: center;';
            break;
        case 'bottom_right':
            $style .= 'justify-content: end;';
            $style .= 'text-align: end;';
            break;
        }

        $style .= '}';

        if ($flip_style == '3d') {
            $style .= '#' . $widgetId . ' .fon-flipbox-front-3d .fon-flipbox-inner-3d{';

            switch ($front_align) {
            case 'top_left':
            case 'top_center':
            case 'top_right':
                $style .= 'top: 25px;';
                break;
            case 'center_left':
            case 'center_center':
            case 'center_right':
                $style .= 'top: 50%;';
                $style .= 'transform: translateY(-50%) translateZ(60px)';
                break;
            case 'bottom_left':
            case 'bottom_center':
            case 'bottom_right':
                $style .= 'bottom: 25px;';
                break;
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-flipbox-back-3d .fon-flipbox-inner-3d{';

            switch ($back_align) {
            case 'top_left':
            case 'top_center':
            case 'top_right':
                $style .= 'top: 25px;';
                break;
            case 'center_left':
            case 'center_center':
            case 'center_right':
                $style .= 'top: 50%;';
                $style .= 'transform: translateY(-50%) translateZ(60px)';
                break;
            case 'bottom_left':
            case 'bottom_center':
            case 'bottom_right':
                $style .= 'bottom: 25px;';
                break;
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-flipbox flip-style-' . $flip_style . ' flip-direction-' . $flip_direction . ' flip-on-' . $flip_behavior . ' ' . $fon_class . '">';
        $output .= '<div class="fon-flipbox-panel' . ($flip_style == '3d' ? '-3d' : '') . '">';

        if ($flip_style == '3d') {
            $output .= '<div class="fon-flipbox-3d-item">';
        }

        $output .= '<div class="fon-flipbox-front' . ($flip_style == '3d' ? '-3d' : '') . ' flipbox">';
        $output .= '<div class="fon-flipbox-inner' . ($flip_style == '3d' ? '-3d' : '') . '">';
        $output .= $front_text;
        $output .= '</div>';
        $output .= '</div>';
        $output .= '<div class="fon-flipbox-back' . ($flip_style == '3d' ? '-3d' : '') . ' flipbox">';
        $output .= '<div class="fon-flipbox-inner' . ($flip_style == '3d' ? '-3d' : '') . '">';
        $output .= $back_text;
        $output .= '</div>';
        $output .= '</div>';

        if ($flip_style == '3d') {
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function formbuilder_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $email_addresses = Config::get('contact/email-addresses');
        $to_email = (isset($content->to_email) && $content->to_email ? $content->to_email : $email_addresses[0]);
        $email_subject = (isset($content->email_subject) && $content->email_subject ? $content->email_subject : '');
        $email_body = (isset($content->email_body) && $content->email_body ? $content->email_body : '');
        $hide_labels = (isset($content->hide_labels) && $content->hide_labels == 'yes' ? 1 : 0);
        $hidden_label_class = ($hide_labels ? 'visually-hidden' : '');
        $floating_labels = (isset($content->floating_labels) && $content->floating_labels == 'yes' ? 1 : 0);
        $captcha_status = (isset($content->enable_captcha) && $content->enable_captcha == 'yes' ? 1 : 0);
        $enable_policy = (isset($content->enable_policy) && $content->enable_policy == 'yes' ? 1 : 0);
        $enable_redirect = (isset($content->enable_redirect) && $content->enable_redirect == 'yes' ? 1 : 0);
        $redirect_link = (isset($content->redirect_link->{$this->lang}) && $content->redirect_link->{$this->lang} ? $content->redirect_link->{$this->lang} : '');
        $field_gap = (isset($content->field_gap) && $content->field_gap ? 'g-' . $content->field_gap : 'g-3');
        $required_message = (isset($content->required_message->{$this->lang}) && $content->required_message->{$this->lang} ? $content->required_message->{$this->lang} : __('theme/formbuilder/required_message'));
        $error_message = (isset($content->error_message->{$this->lang}) && $content->error_message->{$this->lang} ? $content->error_message->{$this->lang} : __('theme/formbuilder/error_message'));
        $success_message = (isset($content->success_message->{$this->lang}) && $content->success_message->{$this->lang} ? $content->success_message->{$this->lang} : __('theme/formbuilder/success_message'));
        $button_text = (isset($content->button_text->{$this->lang}) && $content->button_text->{$this->lang} ? $content->button_text->{$this->lang} : array_values((array) $content->button_text)[0] ?? '');
        $button_position = (isset($content->button_position) && $content->button_position ? $content->button_position : 'end');
        if (!$captcha_status && Config::get('options/captcha/status')) {
            $captcha_status = Config::get('options/captcha/status');
        }
        if (!$captcha_status && Config::get('options/BotShield/status')) {
            Helper::Load('BotShield');
            $captcha_status = BotShield::is_blocked('contact');
        }

        if ($captcha_status) {
            Helper::Load('Captcha');
            $captcha = Helper::get('Captcha');
        }

        $style = '';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-label{';
        if (isset($content->label_color) && $content->label_color) {
            $style .= 'color: ' . $content->label_color . ';';
        }
        if (isset($content->label_font) && $content->label_font) {
            $style .= self::parseFontProperties($content->label_font);
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-select, #' . $widgetId . ' .fon-formbuilder-form .form-control {';
        if (isset($content->field_color) && $content->field_color->normal) {
            $style .= 'color: ' . $content->field_color->normal . ';';
        }
        if (isset($content->field_background) && $content->field_background->normal) {
            $style .= 'background-color: ' . $content->field_background->normal . ';';
        }
        if (isset($content->field_border_width) && $content->field_border_width->normal) {
            $style .= 'border-width: ' . $content->field_border_width->normal . 'px;';
        }
        if (isset($content->field_border_color) && $content->field_border_color->normal) {
            $style .= 'border-color: ' . $content->field_border_color->normal . ';';
        }
        if (isset($content->field_border_radius) && 0 < $content->field_border_radius) {
            $style .= 'border-radius: ' . $content->field_border_radius . 'px;';
        }
        if (isset($content->field_padding) && $content->field_padding) {
            $padding = '';
            if (isset($content->field_padding->top) && $content->field_padding->top) {
                $padding .= $content->field_padding->top . 'px ';
            }
            if (isset($content->field_padding->right) && $content->field_padding->right) {
                $padding .= $content->field_padding->right . 'px ';
            }
            if (isset($content->field_padding->bottom) && $content->field_padding->bottom) {
                $padding .= $content->field_padding->bottom . 'px ';
            }
            if (isset($content->field_padding->left) && $content->field_padding->left) {
                $padding .= $content->field_padding->left . 'px ';
            }

            if ($padding) {
                $style .= 'padding: ' . $padding . ';';
            }
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-select:hover,#' . $widgetId . ' .fon-formbuilder-form .form-select:focus, #' . $widgetId . ' .fon-formbuilder-form .form-control:hover, #' . $widgetId . ' .fon-formbuilder-form .form-control:active, #' . $widgetId . ' .fon-formbuilder-form .form-control:focus{';
        if (isset($content->field_color) && $content->field_color->hover) {
            $style .= 'color: ' . $content->field_color->hover . ';';
        }
        if (isset($content->field_background) && $content->field_background->hover) {
            $style .= 'background-color: ' . $content->field_background->hover . ';';
        }
        if (isset($content->field_border_width) && $content->field_border_width->hover) {
            $style .= 'border-width: ' . $content->field_border_width->hover . 'px!important;';
        }
        if (isset($content->field_border_color) && $content->field_border_color->hover) {
            $style .= 'border-color: ' . $content->field_border_color->hover . '!important;';
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-select, #' . $widgetId . ' .fon-formbuilder-form .input-icon .from-control{';
        if (isset($content->field_padding) && $content->field_padding) {
            $padding = 0;
            if (isset($content->field_padding->left) && $content->field_padding->left) {
                $padding = $content->field_padding->left;
            }
            else if (isset($content->field_padding->right) && $content->field_padding->right) {
                $padding = $content->field_padding->right;
            }

            $style .= 'padding-left: ' . ($padding + 30) . 'px;';
        }

        $style .= '}';

        if (!$floating_labels) {
            $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-control:placeholder{';
            if (isset($content->field_placeholder) && $content->field_placeholder->normal) {
                $style .= 'color: ' . $content->field_placeholder->normal . ';';
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-formbuilder-form .form-control:hover::placeholder{';
            if (isset($content->field_placeholder) && $content->field_placeholder->hover) {
                $style .= 'color: ' . $content->field_placeholder->hover . ';';
            }

            $style .= '}';
        }
        if (isset($content->radio_color) && $content->radio_color) {
            $style .= '#' . $widgetId . ' .fon-formbuilder-form input[type="radio"].form-check-input:checked{';
            $style .= 'border-color: ' . $content->radio_color . ';';
            $style .= 'background-color: ' . $content->radio_color . ';';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-formbuilder-form input[type="radio"]:hover, #' . $widgetId . ' .fon-formbuilder-form input[type="radio"]:focus{';
            $style .= 'border-color: ' . $content->radio_color . ';';
            $style .= '}';
        }
        if (isset($content->checkbox_color) && $content->checkbox_color) {
            $style .= '#' . $widgetId . ' .fon-formbuilder-form input[type="checkbox"].form-check-input:checked{';
            $style .= 'border-color: ' . $content->checkbox_color . ';';
            $style .= 'background-color: ' . $content->checkbox_color . ';';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-formbuilder-form input[type="checkbox"]:hover,#' . $widgetId . ' .fon-formbuilder-form input[type="checkbox"]:focus{';
            $style .= 'border-color: ' . $content->checkbox_color . ';';
            $style .= '}';
        }

        $style .= '#' . $widgetId . ' .fon-formbuilder-form .input-group .input-group-text{';
        if (isset($content->input_group_color) && $content->input_group_color->normal) {
            $style .= 'color: ' . ($content->input_group_color->normal ?? 'var(--bs-body-color)') . ';';
        }
        if (isset($content->input_group_bg) && $content->input_group_bg->normal) {
            $style .= 'background-color: ' . ($content->input_group_bg->normal ?? 'var(--bs-body-color)') . ';';
        }
        if (isset($content->field_border_width) && $content->field_border_width->normal) {
            $style .= 'border-width: ' . $content->field_border_width->normal . 'px;';
        }
        if (isset($content->field_border_color) && $content->field_border_color->normal) {
            $style .= 'border-color: ' . $content->field_border_color->normal . ';';
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .fon-formbuilder-form .input-group:hover .input-group-text{';
        if (isset($content->input_group_color) && $content->input_group_color->hover) {
            $style .= 'color: ' . ($content->input_group_color->hover ?? 'var(--bs-body-color)') . ';';
        }
        if (isset($content->input_group_bg) && $content->input_group_bg->hover) {
            $style .= 'background-color: ' . ($content->input_group_bg->hover ?? 'var(--bs-body-color)') . ';';
        }
        if (isset($content->field_border_width) && $content->field_border_width->hover) {
            $style .= 'border-width: ' . $content->field_border_width->hover . 'px!important;';
        }
        if (isset($content->field_border_color) && $content->field_border_color->hover) {
            $style .= 'border-color: ' . $content->field_border_color->hover . '!important;';
        }

        $style .= '}';
        if (isset($content->field_background) && $content->field_background->hover) {
            $style .= '#' . $widgetId . ' form-floating>.form-control-plaintext~label::after, .form-floating>.form-control:focus~label::after, .form-floating>.form-control:not(:placeholder-shown)~label::after, .form-floating>.form-select~label::after {';
            $style .= 'background-color: ' . $content->field_background->hover . ';';
            $style .= '}';
        }

        $style .= "\n" . '            .fon-website-field {' . "\n" . '                opacity: 0;' . "\n" . '                position: absolute;' . "\n" . '                top: 0;' . "\n" . '                left: 0;' . "\n" . '                height: 0;' . "\n" . '                width: 0;' . "\n" . '                z-index: -1;' . "\n" . '                overflow: hidden;' . "\n" . '            }' . "\n" . '        ';

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-formbuilder-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<form class="fon-formbuilder-form row ' . $field_gap . ' needs-validation"  ' . ($enable_redirect && $redirect_link != '' ? 'data-redirect="true" data-redirect-link="' . $redirect_link . '"' : '') . ' method="post" action="' . APP_URI . '/addon/FonPageBuilder" id="fon-' . $moduleId . '" novalidate>';
        if (isset($content->items) && is_array($content->items)) {
            $increated_id = mt_rand(100000, 999999);

            foreach ($content->items as $item_key => $item_value) {
                if ($increated_id === $increated_id) {
                    ++$increated_id;
                }
                $field_type = (isset($item_value->field_type) && $item_value->field_type ? $item_value->field_type : 'text');
                $field_name = (isset($item_value->field_name) && $item_value->field_name ? $item_value->field_name : '');
                $field_title = (isset($item_value->field_title->{$this->lang}) && $item_value->field_title->{$this->lang} ? $item_value->field_title->{$this->lang} : array_values((array) $item_value->field_title)[0] ?? '');
                $field_placeholder = (isset($item_value->field_placeholder->{$this->lang}) && $item_value->field_placeholder->{$this->lang} ? $item_value->field_placeholder->{$this->lang} : array_values((array) $item_value->field_title)[0] ?? '');
                $field_is_required = (isset($item_value->field_is_required) && $item_value->field_is_required == 'yes' ? true : false);
                $field_required_star = (isset($item_value->field_required_star) && $item_value->field_required_star == 'yes' ? true : false);
                $item_name_id = ($field_type ? 'fon-formbuilder-field-' . $item_key . '-' . $moduleId : '');
                $field_number_min = (isset($item_value->field_number_min) && $item_value->field_number_min != '' ? $item_value->field_number_min : '');
                $field_number_max = (isset($item_value->field_number_max) && $item_value->field_number_max ? $item_value->field_number_max : '');
                $field_number_step = (isset($item_value->field_number_step) && $item_value->field_number_step ? $item_value->field_number_step : '');
                $field_height = (isset($item_value->field_height) && $item_value->field_height ? $item_value->field_height . 'px' : '100px');
                $field_is_resize = (isset($item_value->field_is_resize) && $item_value->field_is_resize == 'yes' ? true : false);
                $field_min_character = (isset($item_value->field_min_character) && $item_value->field_min_character ? ' minlength = ' . $item_value->field_min_character : '');
                $field_max_character = (isset($item_value->field_max_character) && $item_value->field_max_character ? ' maxlength = ' . $item_value->field_max_character : '');
                $field_width = (isset($item_value->field_width) && $item_value->field_width ? $item_value->field_width : (object) ['xl=>12', 'lg=>12', 'md=>12', 'sm=>12', 'xs=>12']);
                $field_width_class = 'col-' . $field_width->xs . ' col-sm-' . $field_width->sm . ' col-md-' . $field_width->md . ' col-lg-' . $field_width->lg . ' col-xl-' . $field_width->xl;
                $field_inline = (isset($item_value->field_inline) && $item_value->field_inline == 'yes' ? true : false);
                $field_hide_label = (isset($item_value->field_hide_label) && $item_value->field_hide_label == 'yes' ? true : false);
                $field_show_icon = (isset($item_value->field_show_icon) && $item_value->field_show_icon == 'yes' ? true : false);
                $field_icon = (isset($item_value->field_icon) && $item_value->field_icon ? $item_value->field_icon : '');

                if ($field_type == 'radio') {
                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$field_hide_label) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    $output .= '<div class="fon-formbuilder-radio-content">';
                    if (isset($item_value->field_radio_items) && is_array($item_value->field_radio_items)) {
                        $inner_values = $item_value->field_radio_items;

                        foreach ($inner_values as $inner_item_key => $inner_item_value) {
                            $inner_item_value_title = (isset($inner_item_value->title->{$this->lang}) && $inner_item_value->title->{$this->lang} ? $inner_item_value->title->{$this->lang} : array_values((array) $inner_item_value->title)[0] ?? '');

                            if ($inner_item_value_title) {
                                $output .= '<div class="form-check ' . ($field_inline ? 'form-check-inline' : '') . '">';
                                $inner_item_id = 'fon-form-' . $increated_id . '-radio-' . $inner_item_key;
                                $is_radio_checked = (isset($inner_item_value->is_checked) && $inner_item_value->is_checked == '1' ? true : false);
                                $output .= '<input type="radio" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" id="' . $inner_item_id . '" value="' . $inner_item_value->value . '" class="form-check-input"' . ($is_radio_checked ? ' checked' : '') . '' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                                $output .= '<label for="' . $inner_item_id . '" class="form-check-label">' . $inner_item_value_title . '</label>';
                                $output .= '</div>';
                            }
                        }
                    }

                    $output .= ($field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    $output .= '</div>';
                    $output .= '</div>';
                }
                else if ($field_type === 'checkbox') {
                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$field_hide_label) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    $output .= '<div class="fon-formbuilder-checkbox-content">';
                    if (isset($item_value->field_checkbox_items) && is_array($item_value->field_checkbox_items)) {
                        $inner_values = $item_value->field_checkbox_items;
                        $checkbocFieldName = 'formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']';
                        if (is_array($inner_values) && 1 < count($inner_values)) {
                            $checkbocFieldName .= '[]';
                        }

                        foreach ($inner_values as $inner_item_key => $inner_item_value) {
                            $inner_item_value_title = (isset($inner_item_value->title->{$this->lang}) && $inner_item_value->title->{$this->lang} ? $inner_item_value->title->{$this->lang} : array_values((array) $inner_item_value->title)[0] ?? '');

                            if ($inner_item_value_title) {
                                $output .= '<div class="form-check ' . ($field_inline ? 'form-check-inline' : '') . '">';
                                $inner_item_id = 'fon-form-' . $increated_id . '-checkbox-' . $inner_item_key;
                                $is_checkbox_checked = (isset($inner_item_value->is_checked) && $inner_item_value->is_checked == '1' ? true : false);
                                $output .= '<input type="checkbox" name="' . $checkbocFieldName . '" id="' . $inner_item_id . '" value="' . $inner_item_value->value . '" class="form-check-input ' . (1 < count($inner_values) ? 'multiple' : '') . '"' . ($is_checkbox_checked ? ' checked' : '') . '' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                                $output .= '<label for="' . $inner_item_id . '" class="form-check-label">' . $inner_item_value_title . '</label>';
                                $output .= '</div>';
                            }
                        }
                    }

                    $output .= ($field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    $output .= '</div>';
                    $output .= '</div>';
                }
                else if ($field_type == 'textarea') {
                    $invalidMessage = [];

                    if ($field_is_required) {
                        $invalidMessage[] = __('theme/required_field');
                    }

                    if ($field_min_character != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_min_char'), $item_value->field_min_character);
                    }

                    if ($field_max_character != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_max_char'), $item_value->field_max_character);
                    }

                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '<div class="input-group ' . ($field_is_required ? 'has-validation' : '') . '">';
                        $output .= '<span class="input-group-text"><i class="' . $field_icon . '"></i></span>';
                    }

                    if ($floating_labels) {
                        $output .= '<div class="form-floating">';
                    }
                    $output .= '<textarea name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" id="' . $item_name_id . '" rows="5" class="form-control' . ($field_is_resize ? '' : ' not-resize') . '" placeholder="' . ($field_placeholder && !$floating_labels ? $field_placeholder : $field_title) . '" ' . ($field_is_required ? ' aria-required="true" required' : '') . $field_max_character . $field_min_character . ' style="height:' . $field_height . '"></textarea>';
                    if ($field_title && $floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if (!$floating_labels && $field_is_required || $field_min_character != '' || $field_max_character != '') {
                        $output .= '<div class="invalid-feedback">' . implode(', ', $invalidMessage) . '</div>';
                    }

                    if ($floating_labels) {
                        $output .= '</div>';
                        if ($field_is_required || $field_min_character != '' || $field_max_character != '') {
                            $output .= '<div class="invalid-feedback">' . implode(', ', $invalidMessage) . '</div>';
                        }
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }
                else if ($field_type == 'select') {
                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '<div class="input-group ' . ($field_is_required ? 'has-validation' : '') . '">';
                        $output .= '<span class="input-group-text"><i class="' . $field_icon . '"></i></span>';
                    }

                    if ($floating_labels) {
                        $output .= '<div class="form-floating">';
                    }
                    if (isset($item_value->field_select_items) && is_array($item_value->field_select_items)) {
                        $inner_values = $item_value->field_select_items;
                        $output .= '<select class="form-select" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" id="' . $item_name_id . '"' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                        $output .= ($field_placeholder ? '<option value="">' . $field_placeholder . '</option>' : '');

                        foreach ($inner_values as $inner_item_key => $inner_item_value) {
                            $inner_item_value_title = (isset($inner_item_value->title->{$this->lang}) && $inner_item_value->title->{$this->lang} ? $inner_item_value->title->{$this->lang} : array_values((array) $inner_item_value->title)[0] ?? '');

                            if ($inner_item_value_title) {
                                $is_checked = (isset($inner_item_value->is_checked) && $inner_item_value->is_checked == '1' ? true : false);
                                $output .= '<option value="' . $inner_item_value->value . '"' . ($is_checked ? ' selected' : '') . '>' . $inner_item_value_title . '</option>';
                            }
                        }

                        $output .= '</select>';
                        $output .= (!$floating_labels && $field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    }
                    if ($field_title && $floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    if ($floating_labels) {
                        $output .= '</div>';
                        $output .= ($field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }
                else if ($field_type == 'number') {
                    $invalidMessage = [];

                    if ($field_is_required) {
                        $invalidMessage[] = __('theme/required_field');
                    }

                    if ($field_number_min != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_min'), $field_number_min);
                    }

                    if ($field_number_max != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_max'), $field_number_max);
                    }

                    if ($field_number_step != '') {
                        $invalidMessage[] = sprintf(__('theme/required_field_step'), $field_number_step);
                    }

                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '<div class="input-group ' . ($field_is_required ? 'has-validation' : '') . '">';
                        $output .= '<span class="input-group-text"><i class="' . $field_icon . '"></i></span>';
                    }

                    if ($floating_labels) {
                        $output .= '<div class="form-floating">';
                    }
                    $output .= '<input type="number" id="' . $item_name_id . '" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" class="form-control"' . ($field_number_min != '' ? ' min="' . $field_number_min . '"' : '') . '' . ($field_number_max ? ' max="' . $field_number_max . '"' : '') . '' . ($field_number_step ? ' step="' . $field_number_step . '"' : '') . ' placeholder="' . ($field_placeholder && !$floating_labels ? $field_placeholder : $field_title) . '" ' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                    if (!$floating_labels && $field_is_required || $field_number_min != '' || $field_number_max != '' || $field_number_step != '') {
                        $output .= '<div class="invalid-feedback">' . implode(', ', $invalidMessage) . '</div>';
                    }
                    if ($field_title && $floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    if ($floating_labels) {
                        $output .= '</div>';
                        if ($field_is_required || $field_number_min != '' || $field_number_max != '' || $field_number_step != '') {
                            $output .= '<div class="invalid-feedback">' . implode(', ', $invalidMessage) . '</div>';
                        }
                    }
                    if ($field_show_icon && $field_icon) {
                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }
                else if ($field_type == 'title') {
                    $font_style = self::parseFontProperties($item_value->heading_font);
                    $item_unique_class = 'fon-formbuilder-heading-' . $item_key;
                    $heading_selector = (isset($item_value->heading_selector) && $item_value->heading_selector ? $item_value->heading_selector : 'h3');
                    $output .= '<' . $heading_selector . ' class="fon-widget-title ' . $item_unique_class . '" style="' . $font_style . '">';
                    $output .= $field_title;
                    $output .= '</' . $heading_selector . '>';
                }
                else {
                    $output .= '<div class="' . $field_width_class . ' ' . $item_name_id . '">';
                    if ($field_title && !$floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }
                    if ($field_show_icon && $field_icon && !in_array($field_type, ['date' => true, 'time' => true, 'date-time' => true, 'tel' => true])) {
                        $output .= '<div class="input-group ' . ($field_is_required ? 'has-validation' : '') . '">';
                        $output .= '<span class="input-group-text"><i class="' . $field_icon . '"></i></span>';
                    }

                    if ($floating_labels) {
                        $output .= '<div class="form-floating">';
                    }

                    if ($field_type == 'tel') {
                        $output .= '<input type="hidden" id="' . $item_name_id . '-hidden" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']"/>';
                        $output .= '<input type="' . $field_type . '" id="' . $item_name_id . '" class="form-control" placeholder="' . ($field_placeholder && !$floating_labels ? $field_placeholder : $field_title) . '" ' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                    }
                    else {
                        $output .= '<input type="' . $field_type . '" id="' . $item_name_id . '" name="formbuilder[' . $field_name . '' . ($field_is_required ? '*' : '') . ']" class="form-control" placeholder="' . ($field_placeholder && !$floating_labels ? $field_placeholder : $field_title) . '" ' . ($field_is_required ? ' aria-required="true" required' : '') . '>';
                    }
                    $output .= (!$floating_labels && $field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    if ($field_title && $floating_labels) {
                        $output .= '<label class="form-label ' . $hidden_label_class . '" for="' . $item_name_id . '">' . $field_title . '' . ($field_required_star && $field_is_required ? '<span class="fon-field-required text-danger"> *</span>' : '') . '</label>';
                    }

                    if ($floating_labels) {
                        $output .= '</div>';
                        $output .= ($field_is_required ? '<div class="invalid-feedback">' . __('theme/required_field') . '</div>' : '');
                    }
                    if ($field_show_icon && $field_icon && !in_array($field_type, ['date' => true, 'time' => true, 'date-time' => true, 'tel' => true])) {
                        $output .= '</div>';
                    }

                    if ($field_type == 'email') {
                        $output .= '<input type="hidden" name="email_field" value="' . $field_name . '" >';
                    }

                    $output .= '</div>';
                }
            }
        }

        $required_fields_list = [];
        if (isset($content->items) && is_array($content->items)) {
            foreach ($content->items as $item) {
                $is_req = isset($item->field_is_required) && $item->field_is_required == 'yes';

                if ($is_req) {
                    $required_fields_list[] = $item->field_name;
                }
            }
        }

        $hidden_fields = ['to_email' => base64_encode($to_email), 'req_fields' => $required_fields_list];
        $hidden_fields_json = json_encode($hidden_fields);
        $hiddenFields = Crypt::encode($hidden_fields_json, Config::get('crypt/system'));
        $salt_key = md5('e5i6t8sev0e3ne2sur6mvpl3tx6oz2608u8llzr8w1czagy0jxff' . $hiddenFields);
        $output .= '<input type="hidden" name="form_features" value="' . $hiddenFields . ':' . $salt_key . '" >';
        $output .= '<input type="hidden" name="form_id" value="fon-' . $moduleId . '">';
        $output .= '<input type="hidden" name="email_subject" value="' . Crypt::encode($email_subject, Config::get('crypt/system')) . '">';
        $output .= '<textarea style="display:none;" name="email_body" aria-label="Not For Read">' . Crypt::encode($email_body, Config::get('crypt/system')) . '</textarea>';
        $output .= '<input type="hidden" name="success_message" value="' . Crypt::encode($success_message, Config::get('crypt/system')) . '">';
        $output .= '<input type="hidden" name="error_message" value="' . Crypt::encode($error_message, Config::get('crypt/system')) . '">';
        $output .= '<input type="hidden" name="module_operation" value="ajax_form_submit">';
        $output .= '<input type="hidden" name="lang" value="' . $this->lang . '">';
        $output .= '<input type="hidden" name="enable_captcha" value="' . $captcha_status . '">';
        $honeypot_name = 'formbuilder_' . md5(uniqid(mt_rand(), true));
        Session::set('formbuilder_honeypot_name', $honeypot_name, true);
        $output .= '<input type="hidden" name="' . $honeypot_name . '" value="">';
        $output .= Validation::get_csrf_token('formbuilder_form');
        $encrypted_time = Crypt::encode(time(), Config::get('crypt/system'));
        $output .= '<input type="hidden" name="form_loaded_at" value="' . $encrypted_time . '">';
        if (isset($captcha) && $captcha) {
            $output .= '<div class="' . ($captcha->input ? 'mb-3' : '') . '">';
            $output .= '<div class="input-group has-validation">';
            $output .= '<span class="input-group-text p-0 border-0 overflow-hidden">' . $captcha->getOutput() . '</span>';

            if ($captcha->input) {
                $output .= '<input name="' . $captcha->input_name . '" type="text"  class="form-control" aria-label="' . ___('needs/form-captcha-label') . '" placeholder="' . ___('needs/form-captcha-label') . '" required>';
                $output .= '<div class="invalid-feedback">' . __('theme/required_field') . '</div>';
            }

            $output .= '</div>';
            $output .= '</div>';
        }
        if ($enable_policy || Config::get('options/gdpr-status')) {
            $output .= '<div class="form-check">';
            $output .= '<input class="form-check-input" type="checkbox" name="policy" id="policy-' . $widgetId . '" value="Yes" aria-required="true" required onchange="if($(this).prop(\'checked\')) {$(\'#fon-btn-' . $moduleId . '\').removeClass(\'disabled\').removeAttr(\'role aria-disabled\')} else {$(\'#fon-btn-' . $moduleId . '\').addClass(\'disabled\').attr({\'role\':\'button\',\'aria-disabled\':\'true\'});}">';
            $output .= '<label class="form-check-label fs-12" for="policy-' . $widgetId . '">' . __('website/account_info/gdpr-tx4', ['{link}' => Controllers::$init->CRLink('contract2')]) . '</label>';
            $output .= '<input type="hidden" value="true" name="is_policy">';
            $output .= '</div>';
        }

        if ($button_text) {
            $output .= '<div class="fon-formbuilder-btn text-' . $button_position . '">';
            $btnProperties = ['is_btn' => true, 'type' => 'submit', 'disabled' => ($enable_policy || Config::get('options/gdpr-status') ? 'true' : 'false')];
            $output .= $this->parseButton($content, $moduleId, $pageData, $btnProperties);
            $output .= '</div>';
        }

        $output .= '<div class="fon-website-field" aria-hidden="true">' . "\n" . '                            <label for="website_control">Website</label>' . "\n" . '                            <input type="text" id="website_control" name="website_control" tabindex="-1" autocomplete="off">' . "\n" . '                        </div>';
        $output .= '</form>';
        $output .= '<div style="display:none;margin-top:10px;" class="fon-formbuilder-ajax-status"></div>';
        $output .= '</div>';
        $output .= '</div>';
        $this->addAsset('intlTelInput');
        $ipInfo = UserManager::ip_info();
        $countryCode = ($ipInfo && isset($ipInfo['countryCode']) ? $ipInfo['countryCode'] : ___('package/code'));
        if (!$countryCode || strlen($countryCode) !== 2) {
            $countryCode = 'TR';
        }
        $captchaJs = (isset($captcha) && $captcha ? $captcha->submit_after_js() : '');
        $selectedLangJs = (Language::selected() == 'tr' ? 'Ara' : 'Search');
        $pendingText = addslashes(__('website/others/button1-pending'));
        $js = '        <script>' . "\n" . '    function ' . $moduleId . '_submit(result){' . "\n" . '        ' . $captchaJs . "\n" . '                if(result != ""){' . "\n" . '                    var solve = typeof result === "string" ? getJson(result) : result;' . "\n" . '                    if(solve !==false && solve != undefined && typeof(solve) == "object"){                        ' . "\n" . '                        if(solve.status == "error"){' . "\n" . '                            if(solve.for != undefined && solve.for != ""){' . "\n" . '                        $("#fon-' . $moduleId . '").removeClass("was-validated");' . "\n" . '                        $("#fon-' . $moduleId . ' " +solve.for).focus();' . "\n" . '                        $("#fon-' . $moduleId . ' " +solve.for).addClass("is-invalid");' . "\n" . '                        $("#fon-' . $moduleId . ' " +solve.for).parent(".form-floating").addClass("is-invalid");' . "\n" . '                        $("#fon-' . $moduleId . ' " +solve.for).change(function(){' . "\n" . '                                    $(this).removeClass("is-invalid");' . "\n" . '                                     $(this).parent(".form-floating").removeClass("is-invalid");' . "\n" . '                                });' . "\n" . '                            }' . "\n" . '                            if(solve.fors != undefined && solve.fors.length > 0){' . "\n" . '                        $("#fon-' . $moduleId . '").removeClass("was-validated");' . "\n" . '                                for (var i = 0; i < solve.fors.length; i++) {' . "\n" . '                            $(\'#fon-' . $moduleId . ' [name="formbuilder[\' +solve.fors[i] + \']"]\').addClass("is-invalid");' . "\n" . '                            $(\'#fon-' . $moduleId . ' [name="formbuilder[\' +solve.fors[i] + \']"]\').parent(".form-floating").addClass("is-invalid");' . "\n" . '                            $(\'#fon-' . $moduleId . ' [name="formbuilder[\' +solve.fors[i] + \']"]\').change(function(){' . "\n" . '                                        $(this).removeClass("is-invalid");' . "\n" . '                                        $(this).parent(".form-floating").removeClass("is-invalid");' . "\n" . '                                    });' . "\n" . '                                }' . "\n" . '                            }' . "\n" . '                            alert_error(solve.message,{timer:3000});' . "\n" . '                        }' . "\n" . '                        else if(solve.status == "success"){ ' . "\n" . '                            alert_success(solve.message,{timer:3000});' . "\n" . '                            setTimeout(function(){' . "\n" . '                                location.reload();' . "\n" . '                            }, 3000);' . "\n" . '                        }' . "\n" . '                    }else {' . "\n" . '                        console.log(result);' . "\n" . '                    }' . "\n" . '                }' . "\n" . '            }' . "\n" . '            ' . "\n" . '            function initAllPhoneInputs() {' . "\n" . '                if (typeof window.intlTelInput !== "function") {' . "\n" . '                    return;' . "\n" . '                }' . "\n" . '                if (window.allPhonesInitialized) return;' . "\n" . '            ' . "\n" . '        const telInputs = document.querySelectorAll(\'input[type="tel"]\');' . "\n" . '                if (telInputs.length === 0) {' . "\n" . '                    return; ' . "\n" . '                }' . "\n" . '                ' . "\n" . '                const object_code = {' . "\n" . '                    geoIpLookup: function (callback) {' . "\n" . '                callback("' . $countryCode . '");' . "\n" . '                    },' . "\n" . '                    autoPlaceholder: "on",' . "\n" . '                    formatOnDisplay: true,' . "\n" . '                    initialCountry: "auto",                   ' . "\n" . '                    nationalMode: false,' . "\n" . '                    placeholderNumberType: "MOBILE",' . "\n" . '                    preferredCountries: ["tr","us", "gb", "ch", "ca", "de", "it"],' . "\n" . '                    showSelectedDialCode: true,' . "\n" . '                    countrySearch: true,' . "\n" . '                    strictMode: true,' . "\n" . '                    i18n: {' . "\n" . '                        tr: "Türkiye",' . "\n" . '                searchPlaceholder: "' . $selectedLangJs . '"' . "\n" . '                    },' . "\n" . '                    useFullscreenPopup: false,' . "\n" . '            utilsScript: "' . $pageData['tadress'] . 'js/intltelinput/js/utils.js"' . "\n" . '                };' . "\n" . '                telInputs.forEach(function(input) {' . "\n" . '                if (input.getAttribute("data-intl-initialized") === "true") return;' . "\n" . '                ' . "\n" . '                input.setAttribute("data-intl-initialized", "true");' . "\n" . '            ' . "\n" . '                const iti = window.intlTelInput(input, object_code);' . "\n" . '                ' . "\n" . '                if (iti.promise) {' . "\n" . '                    iti.promise.then(() => {' . "\n" . '                        const hiddenInputId = input.id + "-hidden";' . "\n" . '                        const hiddenInput = document.getElementById(hiddenInputId);' . "\n" . '            ' . "\n" . '                        const updateHidden = () => {' . "\n" . '                            if (hiddenInput) {' . "\n" . '                                hiddenInput.value = iti.getNumber();' . "\n" . '                            }' . "\n" . '                        };' . "\n" . '                            ' . "\n" . '                            updateHidden();' . "\n" . '                            input.addEventListener("input", updateHidden);' . "\n" . '                            input.addEventListener("countrychange", updateHidden);' . "\n" . '                        });' . "\n" . '                    }' . "\n" . '                });' . "\n" . '                window.allPhonesInitialized = true;' . "\n" . '            }' . "\n" . '            var phoneInitInterval = setInterval(function() {' . "\n" . '                if (typeof window.intlTelInput === "function") {' . "\n" . '                    initAllPhoneInputs();' . "\n" . '                    if (window.allPhonesInitialized) {' . "\n" . '                        clearInterval(phoneInitInterval);' . "\n" . '                    }' . "\n" . '                }' . "\n" . '            }, 200);' . "\n" . '            ' . "\n" . '            $(document).ready(function(){' . "\n" . '        $("#fon-btn-' . $moduleId . '").on("click",function(e){' . "\n" . '                    e.preventDefault();' . "\n" . '            var form = $("#fon-' . $moduleId . '");' . "\n" . '                    if (!form[0].checkValidity()) {' . "\n" . '                        e.preventDefault();' . "\n" . '                        e.stopPropagation();' . "\n" . '                        form.addClass("was-validated");' . "\n" . '                        form.find(":invalid").parent(".form-floating").addClass("is-invalid");' . "\n" . '                return (alert_error("' . $required_message . '",{timer:3000}));' . "\n" . '                    }' . "\n" . '                    MioAjaxElement($(this),{' . "\n" . '                waiting_text: "' . $pendingText . '",' . "\n" . '                result:"' . $moduleId . '_submit",' . "\n" . '                    });' . "\n" . '               });' . "\n" . '        if($("#fon-' . $moduleId . ' .form-check-input.multiple").length > 0){' . "\n" . '            var _requiredCheckboxes = $("#fon-' . $moduleId . ' .form-check-input.multiple:checkbox[required]");' . "\n" . '                    _requiredCheckboxes.each(function (i, el) {' . "\n" . '                      var _checkboxList = $(this).closest(".fon-formbuilder-checkbox-content");' . "\n" . '                ' . "\n" . '                      if (!_checkboxList.hasClass("rqCheckboxList")) {' . "\n" . '                        _checkboxList.addClass("rqCheckboxList");' . "\n" . '                      }' . "\n" . '                    });' . "\n" . '                ' . "\n" . '                    var _requiredCheckboxLists = $(".rqCheckboxList");' . "\n" . '                    ' . "\n" . '                    _requiredCheckboxLists.each(function (i, el) {' . "\n" . '                      var _checkboxList = $(this);' . "\n" . '                      _checkboxList.on("change", "input[type=\\"checkbox\\"]", function (e) {' . "\n" . '                        updateCheckboxesRequired($(this).parents(".rqCheckboxList"));' . "\n" . '                      });' . "\n" . '                ' . "\n" . '                      updateCheckboxesRequired(_checkboxList);' . "\n" . '                    });' . "\n" . '                    ' . "\n" . '                    function updateCheckboxesRequired(_checkboxList) {' . "\n" . '                      var _checkbox = _checkboxList.find("input[type=\\"checkbox\\"]").eq(0),' . "\n" . '                        checkboxName = _checkbox.attr("name"),' . "\n" . '                        checkboxNameAttr = "[name=\\"" + checkboxName + "\\"]",' . "\n" . '                        _checkBoxes = _checkboxList.find("input[type=\\"checkbox\\"]" + checkboxNameAttr);' . "\n" . '                ' . "\n" . '                      if (_checkboxList.find(checkboxNameAttr + ":checked").length > 0) {' . "\n" . '                        _checkBoxes.prop("required", false);' . "\n" . '                      } else {' . "\n" . '                        _checkBoxes.prop("required", true);' . "\n" . '                      }' . "\n" . '                    }' . "\n" . '                }' . "\n" . '                ' . "\n" . '                ' . "\n" . '            });' . "\n" . '            ' . "\n" . '         </script>';
        $this->addScript('footer', $pageData['page'], $js);
        return $output;
    }

    private function gallery_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $uploadDir = RESOURCE_DIR . 'uploads' . DIRECTORY_SEPARATOR . 'fonpagebuilder';
        $imageBaseDir = RESOURCE_DIR . 'uploads' . DIRECTORY_SEPARATOR . 'fonpagebuilder';
        $thumbBaseDir = RESOURCE_DIR . 'uploads' . DIRECTORY_SEPARATOR . 'fongallerythumb';
        $layout = (isset($content->layout) && $content->layout ? $content->layout : 'bootstrap');
        $thumb_width = (isset($content->thumb_width) && $content->thumb_width ? (int) $content->thumb_width : 600);
        $thumb_height = (isset($content->thumb_height) && $content->thumb_height ? (int) $content->thumb_height : 400);
        $border_radius = (isset($content->border_radius) && $content->border_radius ? (int) $content->border_radius : 0);
        $column = (isset($content->column) && $content->column ? (array) $content->column : ['xl' => 4, 'lg' => 4, 'md' => 3, 'sm' => 2, 'xs' => 2]);
        $method = (isset($content->method) && $content->method ? $content->method : 'folder');
        $folder = (isset($content->folder) && $content->folder ? trim((string) $content->folder) : '');
        $items = (isset($content->items) && $content->items ? $content->items : []);
        $fallbackImage = '/templates/website/Datawise/images/image-fallback.svg';
        $gridXs = min(6, max(1, (int) ($column['xs'] ?? 2)));
        $gridSm = min(6, max(1, (int) ($column['sm'] ?? 2)));
        $gridMd = min(6, max(1, (int) ($column['md'] ?? 3)));
        $gridLg = min(6, max(1, (int) ($column['lg'] ?? 4)));
        $gridXl = min(6, max(1, (int) ($column['xl'] ?? 4)));
        $gridRowClasses = sprintf('row g-3 row-cols-%d row-cols-sm-%d row-cols-md-%d row-cols-lg-%d row-cols-xl-%d', $gridXs, $gridSm, $gridMd, $gridLg, $gridXl);

        if ($layout === 'slide') {
            $gridRowClasses = 'flex-nowrap ' . $gridRowClasses;
        }

        $masonryColumnCounts = sprintf('--column-xs: %d; --column-sm: %d; --column-md: %d; --column-lg: %d; --column-xl: %d;', $gridXs, $gridSm, $gridMd, $gridLg, $gridXl);
        $images = [];
        if (($method == 'folder') && $folder) {
            $folder = trim($this->sanitizeRelativePath($folder), '/');
            $targetFolder = realpath($imageBaseDir . DIRECTORY_SEPARATOR . $folder);
            $baseRealPath = realpath($uploadDir);
            if ($targetFolder === false || $baseRealPath === false || strpos($targetFolder, $baseRealPath) !== 0) {
                return '<div class="alert alert-danger">Klasör bulunamadı veya erişim izni yok.</div>';
            }

            $extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif'];
            $files = scandir($targetFolder) ?: [];

            foreach ($files as $fileName) {
                if (($fileName === '.') || $fileName === '..') {
                    continue;
                }

                $fullPath = $targetFolder . DIRECTORY_SEPARATOR . $fileName;

                if (!is_file($fullPath)) {
                    continue;
                }

                $extension = strtolower((string) pathinfo($fileName, PATHINFO_EXTENSION));

                if (!in_array($extension, $extensions, true)) {
                    continue;
                }

                $imagePath = $folder . '/' . $fileName;
                $thumbs = $this->buildGalleryThumbForImage($imagePath, $imageBaseDir, $thumbBaseDir, $thumb_width, $thumb_height);
                $images[] = ['path' => static::assetLinkDetermine('resources/uploads/fonpagebuilder/' . $imagePath), 'title' => $this->buildGalleryPrettyTitle((string) pathinfo($fileName, PATHINFO_FILENAME)), 'thumb_crop' => static::assetLinkDetermine('resources/uploads/' . $thumbs['crop']), 'thumb_fit' => static::assetLinkDetermine('resources/uploads/' . $thumbs['fit'])];
            }
        }
        else if (($method == 'images') && is_array($items)) {
            foreach ($items as $item) {
                if (isset($item->gallery_image) && $item->gallery_image) {
                    $imagePath = trim((string) $item->gallery_image);

                    if (preg_match('/^https?:\\/\\//i', $imagePath)) {
                        $thumbs = ['crop' => $imagePath, 'fit' => $imagePath];
                    }
                    else {
                        $search = 'resources/uploads/fonpagebuilder/';
                        $cleanPath = str_replace($search, '', ltrim($imagePath, '/'));
                        $thumbs = $this->buildGalleryThumbForImage($cleanPath, $imageBaseDir, $thumbBaseDir, $thumb_width, $thumb_height);
                    }

                    $title = '';

                    if (is_object($item->image_title)) {
                        $title = (isset($item->image_title->{$this->lang}) && $item->image_title->{$this->lang} ? $item->image_title->{$this->lang} : array_values((array) $item->image_title)[0] ?? '');
                    }
                    else if (is_string($item->image_title)) {
                        $title = $item->image_title;
                    }

                    $images[] = ['path' => static::assetLinkDetermine($imagePath), 'title' => ($title ? $title : $this->buildGalleryPrettyTitle((string) pathinfo($imagePath, PATHINFO_FILENAME))), 'thumb_crop' => static::assetLinkDetermine('resources/uploads/' . $thumbs['crop']), 'thumb_fit' => static::assetLinkDetermine('resources/uploads/' . $thumbs['fit'])];
                }
            }
        }

        $style = '@keyframes _gallery-shimmer {' . "\n" . '            0%   { background-position: 200% 0; }' . "\n" . '            100% { background-position: -200% 0; }' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .horizontal-slider-viewport {' . "\n" . '            overflow: hidden;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] .gallery-item {' . "\n" . '            break-inside: avoid;' . "\n" . '            margin-bottom: 1rem;' . "\n" . '        }' . "\n" . '        ' . "\n" . '        .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="justified"] {' . "\n" . '            display: grid;' . "\n" . '            grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));' . "\n" . '            gap: 0.75rem;' . "\n" . '            align-items: start;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="metro"] {' . "\n" . '            display: grid;' . "\n" . '            grid-template-columns: repeat(2, minmax(0, 1fr));' . "\n" . '            gap: 15px;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item.is-loading {' . "\n" . '            background: linear-gradient(' . "\n" . '                90deg,' . "\n" . '                #e9ecef 25%,' . "\n" . '                #f4f5f6 50%,' . "\n" . '                #e9ecef 75%' . "\n" . '            );' . "\n" . '            background-size: 400% 100%;' . "\n" . '            animation: _gallery-shimmer 1.6s ease-in-out infinite;' . "\n" . '            min-height: 120px;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item.is-loading {' . "\n" . '            min-height: 0;' . "\n" . '            aspect-ratio: 4 / 3;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item.is-loading figcaption,' . "\n" . '        .gallery-css-pending.fon-gallery-widget .slider-nav-btn {' . "\n" . '            display: none;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item.is-loading img {' . "\n" . '            opacity: 0;' . "\n" . '        }' . "\n" . '        .gallery-css-pending.fon-gallery-widget .gallery-item img {' . "\n" . '            display: block;' . "\n" . '            width: 100%;' . "\n" . '            height: auto;' . "\n" . '            transition: opacity 0.35s ease;' . "\n" . '        }' . "\n" . '        @media (min-width: 576px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 2;' . "\n" . '            }' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="metro"] {' . "\n" . '                grid-template-columns: repeat(2, minmax(0, 1fr));' . "\n" . '            }' . "\n" . '        }' . "\n" . '        @media (min-width: 768px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 2;' . "\n" . '            }' . "\n" . '        }' . "\n" . '        @media (min-width: 992px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 3;' . "\n" . '            }' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="metro"] {' . "\n" . '                grid-template-columns: repeat(4, minmax(0, 1fr));' . "\n" . '            }' . "\n" . '        }' . "\n" . '        @media (min-width: 1200px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 4;' . "\n" . '            }' . "\n" . '        }' . "\n" . '        @media (min-width: 1400px) {' . "\n" . '            .gallery-css-pending.fon-gallery-widget .js-gallery-wrap[data-gallery-layout="masonry"] {' . "\n" . '                column-count: 4;' . "\n" . '            }' . "\n" . '        }';

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $this->addAsset('fon-gallery');
        $output = '';

        if ($images) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container gallery-css-pending fon-gallery-widget ' . ($content->fon_class ?? '') . '" data-gallery-widget data-widget-id="' . $widgetId . '">';
            $output .= '<div class="horizontal-slider js-horizontal-slider ' . ($layout === 'slide' ? 'is-active' : '') . '">';

            if ($layout === 'slide') {
                $output .= '<button type="button" class="btn btn-circle btn-default align-items-center justify-content-center slider-nav-btn slider-prev-btn js-horizontal-prev-btn" aria-label="Onceki" style="' . ($layout === 'slide' ? '' : 'display:none;') . '">';
                $output .= '<i class="fa-solid fa-chevron-left"></i>';
                $output .= '</button>';
            }

            $output .= '<div class="horizontal-slider-viewport js-horizontal-viewport">';
            $output .= '<div' . "\n" . '                                class="gallery-layout js-gallery-wrap ' . $layout . ' ' . (($layout === 'bootstrap') || $layout === 'slide' ? $gridRowClasses : '') . '" ' . "\n" . '                                data-gallery-layout="' . $layout . '"' . "\n" . '                                style="' . ($layout === 'masonry' ? $masonryColumnCounts : '') . '"' . "\n" . '                            >';

            foreach ($images as $index => $image) {
                $path = (string) ($image['path'] ?? '');
                $title = (string) ($image['title'] ?? '');
                $thumbCrop = (string) ($image['thumb_crop'] ?? '');
                $thumbFit = (string) ($image['thumb_fit'] ?? '');
                $useFitThumb = in_array($layout, ['masonry' => true, 'justified' => true]);
                $thumbPath = ($useFitThumb ? $thumbFit : $thumbCrop);
                if (($layout === 'bootstrap') || $layout === 'slide') {
                    $output .= '<div class="col">';
                }

                $output .= ' <figure class="gallery-item is-loading" style="' . (0 < $border_radius ? 'border-radius:' . (int) $border_radius . 'px;' : '') . '">';
                $output .= '<a' . "\n" . '                                            href="' . $path . '"' . "\n" . '                                            class="gallery-link js-gallery-link"' . "\n" . '                                            data-index="' . (int) $index . '"' . "\n" . '                                            data-title="' . $title . '"' . "\n" . '                                        style="' . (0 < $border_radius ? 'border-radius:' . (int) $border_radius . 'px;' : '') . '"' . "\n" . '                                        >';
                $output .= '<img' . "\n" . '                                                src="' . $thumbPath . '"' . "\n" . '                                                alt="' . ($title !== '' ? $title : 'Galeri gorseli') . '"' . "\n" . '                                                class="img-fluid rounded shadow-sm"' . "\n" . '                                                data-fallback="' . $fallbackImage . '"' . "\n" . '                                                onerror="this.onerror=null;this.src=this.dataset.fallback;"' . "\n" . '                                                ' . (0 < $thumb_width ? 'width="' . (int) $thumb_width . '"' : '') . ' ' . "\n" . '                                                ' . (0 < $thumb_height ? 'height="' . (int) $thumb_height . '"' : '') . ' ' . "\n" . '                                                loading="lazy"' . "\n" . '                                            >';
                $output .= '</a>';

                if ($title !== '') {
                    $output .= '<figcaption>' . $title . '</figcaption>';
                }

                $output .= '</figure>';
                if (($layout === 'bootstrap') || $layout === 'slide') {
                    $output .= '</div>';
                }
            }

            $output .= '</div>';
            $output .= '</div>';

            if ($layout === 'slide') {
                $output .= '<button type="button" class="btn btn-circle btn-default align-items-center justify-content-center slider-nav-btn slider-next-btn js-horizontal-next-btn" aria-label="Sonraki">';
                $output .= '<i class="fa-solid fa-chevron-right"></i>';
                $output .= '</button>';
            }

            $output .= '</div>';
            $output .= '<div class="modal fade gallery-modal js-gallery-modal" id="' . $widgetId . '-modal" tabindex="-1" aria-hidden="true">';
            $output .= '<div class="modal-dialog modal-xl modal-dialog-centered">';
            $output .= '<div class="modal-content bg-dark text-white">';
            $output .= '<div class="modal-header border-0">';
            $output .= '<h5 class="modal-title js-gallery-modal-title text-white" id="' . $widgetId . '-modal-title"></h5>';
            $output .= '<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Kapat"></button>';
            $output .= '</div>';
            $output .= '<div class="modal-body text-center position-relative">';
            $output .= '<button type="button" class="btn btn-light modal-nav-btn prev-btn js-prev-image-btn">';
            $output .= '<i class="fa-solid fa-chevron-left"></i>';
            $output .= '</button>';
            $output .= '<img src="" alt="" class="img-fluid rounded gallery-modal-image js-modal-image">';
            $output .= '<button type="button" class="btn btn-light modal-nav-btn next-btn js-next-image-btn">';
            $output .= '<i class="fa-solid fa-chevron-right"></i>';
            $output .= '</button>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function heading_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $title = '';

        if (is_object($content->title)) {
            $title = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        }
        else if (is_string($content->title)) {
            $title = $content->title;
        }

        $title_link = '';

        if (is_object($content->title_link)) {
            $title_link = (isset($content->title_link->{$this->lang}) && $content->title_link->{$this->lang} ? $content->title_link->{$this->lang} : array_values((array) $content->title_link)[0] ?? '');
        }
        else if (is_string($content->title_link)) {
            $title_link = $content->title_link;
        }
        $title_link_target = (isset($content->title_link_target) && $content->title_link_target ? $content->title_link_target : '_self');
        $title_link_rel = (isset($content->title_link_rel) && $content->title_link_rel ? $content->title_link_rel : []);
        $title_link_rel = ($title_link_rel ? ' rel="' . implode(' ', $title_link_rel) . '" ' : '');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $show_icon = (isset($content->show_icon) && $content->show_icon == 'yes' ? true : false);
        $icon_type = (isset($content->icon_type) && $content->icon_type ? $content->icon_type : 'icon');
        $title_icon = (isset($content->title_icon) && $content->title_icon ? $content->title_icon : '');
        $title_svg = (isset($content->title_svg) && $content->title_svg ? $content->title_svg : '');
        $title_icon_position = (isset($content->title_icon_position) && $content->title_icon_position ? $content->title_icon_position : 'before');
        $title_icon_color = (isset($content->title_icon_color) && $content->title_icon_color ? $content->title_icon_color : '');
        $scroll_effect = (isset($content->scroll_effect) && $content->scroll_effect == 'yes' ? true : false);
        $title_color = (isset($content->title_color) && $content->title_color ? $content->title_color : '');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : '');
        $title_text_shadow = (isset($content->title_text_shadow) && $content->title_text_shadow ? $content->title_text_shadow : '');
        $title_margin = (isset($content->title_margin) && $content->title_margin ? $content->title_margin : (object) ['xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => '']);
        $title_padding = (isset($content->title_padding) && $content->title_padding ? $content->title_padding : (object) ['xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => '']);
        $aligns = (isset($content->align) && $content->align ? $content->align : (object) ['xl' => 'left', 'lg' => 'left', 'md' => 'left', 'sm' => 'left', 'xs' => 'left']);
        $alignClass = [];

        if ($aligns) {
            foreach ($aligns as $key => $align) {
                $map = ['left' => 'start', 'right' => 'end', 'center' => 'center'];
                $val = $map[$align] ?? 'start';
                $prefix = ($key === 'xs' ? '' : '-' . $key);
                $alignClass[] = 'text' . $prefix . '-' . $val;
            }
        }

        $alignClass = implode(' ', $alignClass);
        $isScrolled = false;
        $scrollAlignsClass = [];
        if ($scroll_effect && is_string($title) && strpos($title, ':') !== false) {
            $title = explode(':', $title);
            $isScrolled = true;

            foreach ($aligns as $key => $align) {
                $prefix = ($key === 'xs' ? '' : '-' . $key);

                switch ($align) {
                case 'center':
                    $scrollAlignsClass[] = 'mx' . $prefix . '-auto';
                    break;
                case 'right':
                    $scrollAlignsClass[] = 'ms' . $prefix . '-auto';
                    $scrollAlignsClass[] = 'me' . $prefix . '-0';
                    break;
                case 'left':
                    $scrollAlignsClass[] = 'me' . $prefix . '-auto';
                    $scrollAlignsClass[] = 'ms' . $prefix . '-0';
                    break;
                }
            }
        }

        $scrollAlignsClass = implode(' ', $scrollAlignsClass);
        $style = '';

        if ($title) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';

            if ($title_color) {
                $style .= 'color: ' . $title_color . ';';
            }

            if ($title_text_shadow) {
                $style .= 'text-shadow: ' . $title_text_shadow . ';';
            }

            if ($title_font) {
                $style .= self::parseFontProperties($title_font);
            }

            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-widget-title a{';

            if ($title_color) {
                $style .= 'color: ' . $title_color . ';';
            }

            $style .= '}';
            if ($isScrolled && $title_color) {
                $style .= '#' . $widgetId . ' .scrolling-sector{';
                $style .= '--title-color: ' . $title_color . ';';
                $style .= '}';
            }
        }
        if ($show_icon && $title_icon) {
            $style .= '#' . $widgetId . ' .fon-widget-title i{';

            if ($title_icon_color) {
                $style .= 'color: ' . $title_icon_color . ';';
            }

            $style .= '}';
        }

        $responsiveItems = [
            '.fon-widget-title' => [
            ['type' => 'margin', 'unit' => '', 'value' => $title_margin],
            ['type' => 'padding', 'unit' => '', 'value' => $title_padding]
        ]
        ];
        $style .= self::parseResponsiveItems($responsiveItems, $widgetId);

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-heading-widget ' . ($content->fon_class ?? '') . '">';
        $output .= '<div class="fon-widget-content ' . ($isScrolled ? 'scrolling-sector-wrapper ' . $scrollAlignsClass : '') . '">';

        if ($title) {
            $output .= '<' . $heading_selector . ' class="fon-widget-title ' . ($isScrolled ? 'scrolling-sector-inner' : $alignClass) . '">';
            if ($title_link && !$scroll_effect) {
                $output .= '<a href="' . $title_link . '" target="' . $title_link_target . '" ' . $title_link_rel . '>';
            }
            if ($show_icon && $title_icon_position == 'before') {
                if ($icon_type == 'icon') {
                    $output .= '<i class="' . $title_icon . '"></i> ';
                }
                else if ($icon_type == 'svg') {
                    $output .= '<span class="me-2">' . $title_svg . '</span>';
                }
            }

            if ($isScrolled) {
                $output .= '<div class="scrolling-sector"><span>' . implode('</span><span>', $title) . '</span></div>';
            }
            else {
                $output .= self::getPriceHolders($title);
            }
            if ($show_icon && $title_icon_position == 'after') {
                if ($icon_type == 'icon') {
                    $output .= '<i class="' . $title_icon . ' me-2"></i>';
                }
                else if ($icon_type == 'svg') {
                    $output .= '<span class="me-2">' . $title_svg . '</span>';
                }
            }
            if ($title_link && !$scroll_effect) {
                $output .= '</a>';
            }

            $output .= '</' . $heading_selector . '>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function hosting_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetProducts($content, $moduleId, $pageData, $row, 'hosting');
    }

    private function image_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $title = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        $show_title = (isset($content->name_widget_status) && $content->name_widget_status == 'yes' ? true : false);
        $title_position = (isset($content->title_position) && $content->title_position ? $content->title_position : 'top');
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $alt_text = (isset($content->alt_text->{$this->lang}) && $content->alt_text->{$this->lang} ? $content->alt_text->{$this->lang} : array_values((array) $content->alt_text)[0] ?? '');
        $title_text = (isset($content->title_text->{$this->lang}) && $content->title_text->{$this->lang} ? $content->title_text->{$this->lang} : (isset($content->title_text) ? array_values((array) $content->title_text)[0] ?? '' : ''));
        $open_lightbox = (isset($content->open_lightbox) && $content->open_lightbox == 'yes' ? true : false);
        $overlay_type = (isset($content->overlay_type) && $content->overlay_type ? $content->overlay_type : 'none');
        $image_overlay = ($overlay_type != 'none' ? true : false);
        $link = (isset($content->link) && $content->link ? $content->link : '');
        $link_target = (isset($content->link_target) && $content->link_target ? $content->link_target : '_blank');
        $link_rel = (isset($content->link_rel) && $content->link_rel ? $content->link_rel : []);
        $link_rel = ($link_rel ? ' rel="' . implode(' ', $link_rel) . '" ' : '');
        $image = '';

        if (is_object($content->image)) {
            $image = (isset($content->image->{$this->lang}) && $content->image->{$this->lang} ? $content->image->{$this->lang} : array_values((array) $content->image)[0] ?? '');
        }
        else if (is_string($content->image)) {
            $image = $content->image;
        }

        $image_src = ($image ? static::assetLinkDetermine($image) : $lazyPlaceholder);
        $imageDimensions = static::getImageDimensions($image_src, $pageData['badress']);
        $image_width = (isset($content->image_width) && $content->image_width ? $content->image_width : false);
        $image_height = (isset($content->image_height) && $content->image_height ? $content->image_height : false);
        $align = (isset($content->align) && $content->align ? $content->align : 'center');
        $use_border = (isset($content->use_border) && $content->use_border == 'yes' ? true : false);
        $border = (isset($content->border) && $content->border ? $content->border : '');
        $padding = (isset($content->padding) && $content->padding ? $content->padding : '');
        $border_radius = (isset($content->border_radius) && $content->border_radius ? $content->border_radius : 0);
        $shadow = (isset($content->shadow) && $content->shadow ? $content->shadow : '');
        $disable_lazy = (isset($content->disable_lazy) && $content->disable_lazy == 'yes' ? true : false);

        if (empty($alt_text)) {
            if (!empty($title)) {
                $alt_text = $title;
            }
            else if (!empty($title_text)) {
                $alt_text = $title_text;
            }
            else {
                $alt_text = basename($image_src);
            }
        }

        if (empty($title_text)) {
            if (!empty($title)) {
                $title_text = $title;
            }
            else if (!empty($alt_text)) {
                $title_text = $alt_text;
            }
            else {
                $title_text = basename($image_src);
            }
        }

        if ($align == 'left') {
            $align = 'start';
        }
        else if ($align == 'right') {
            $align = 'end';
        }

        $style = '';

        if ($image) {
            $style .= '#' . $widgetId . ' .fon-image-widget-container img{';
            $style .= ($border && $use_border ? 'border:' . $border . ';' : '');
            $style .= ($padding && $use_border ? 'padding:' . $padding . 'px;' : '');
            $style .= ($border_radius ? 'border-radius:' . $border_radius . 'px;' : '');
            $style .= ($shadow ? 'box-shadow:' . $shadow . ';' : '');
            $style .= '}';
            $responsiveValues = [];

            if ($image_height) {
                $responsiveValues[] = ['type' => 'height', 'unit' => 'px', 'value' => $image_height];
            }

            if ($image_width) {
                $responsiveValues[] = ['type' => 'width', 'unit' => 'px', 'value' => $image_width];
            }

            $responsiveItems = ['#' . $widgetId . ' .fon-image-widget-container img' => $responsiveValues];
            $style .= self::parseResponsiveItems($responsiveItems);
        }
        if ($image_overlay && $open_lightbox) {
            $style .= '#' . $widgetId . ' .fon-image-widget-overlay{';

            if ($overlay_type == 'color') {
                $style .= (isset($content->color_overlay) && $content->color_overlay ? 'background-color:' . $content->color_overlay . ';' : '');
            }

            if ($overlay_type == 'gradient') {
                $style .= (isset($content->gradient_overlay) && $content->gradient_overlay ? self::parseGradient($content->gradient_overlay) : '');
            }
            if ($padding && $use_border) {
                $style .= ($image_width ? 'width:calc(100% - ' . ($padding * 2) . 'px);' : '');
                $style .= ($image_height ? 'height:calc(100% - ' . ($padding * 2) . 'px);' : '');
                $style .= 'left:' . $padding . 'px;';
                $style .= 'right:' . $padding . 'px;';
                $style .= 'top:' . $padding . 'px;';
                $style .= 'bottom:' . $padding . 'px;';
                $style .= ($border_radius ? 'border-radius:' . round($border_radius / 2) . 'px;' : '');
            }
            else {
                $style .= ($image_width ? 'width:100%;' : '');
                $style .= ($image_height ? 'height:100%;' : '');
                $style .= ($border_radius ? 'border-radius:' . $border_radius . 'px;' : '');
            }

            $style .= '}';
        }
        if ($show_title && $title) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';
            $style .= self::parseFontProperties($content->title_font);
            $style .= ($content->title_color ? 'color:' . $content->title_color . ';' : '');
            $style .= ($content->title_margin->top ? 'margin-top:' . $content->title_margin->top . 'px;' : '');
            $style .= ($content->title_margin->bottom ? 'margin-bottom:' . $content->title_margin->bottom . 'px;' : '');
            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        if ($isLCPCandidate && $image) {
            $this->addPreloadLink($image, $pageData['page']);
            self::$lcpHandled = true;
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-image-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content text-' . $align . '">';
        $output .= ($show_title && $title && $title_position != 'bottom' ? '<' . $heading_selector . ' class="fon-widget-title d-block">' . $title . '</' . $heading_selector . '>' : '');
        $output .= '<div class="fon-image-widget-container text-' . $align . '">';
        if ($image_overlay && $open_lightbox) {
            $output .= '<div class="fon-image-widget-overlay">';
            $output .= '</div>';
        }

        if ($open_lightbox) {
            $this->addAsset('magnific');
            $output .= '<a class="fon-magnific-popup fon-image-widget-overlay-icon" data-popuptype="image" data-mainclass="mfp-no-margins mfp-with-zoom" href="' . $image_src . '">+</a>';
        }

        if (!$open_lightbox) {
            $output .= (!empty($link) ? '<a href="' . $link . '" target="' . $link_target . '" ' . $link_rel . '>' : '');
        }

        $loadingAttr = 'loading="lazy" decoding="async"';
        $fetchPriority = 'low';
        if (($isLCPCandidate && $image_src) || $disable_lazy) {
            $loadingAttr = 'loading="eager"';
            $fetchPriority = 'high';
        }
        else if (!$enableLazyLoading) {
            $loadingAttr = 'loading="eager"';
            $fetchPriority = 'auto';
        }

        $output .= '<img class="img-fluid" src="' . $image_src . '" alt="' . $alt_text . '" title="' . $title_text . '" ' . $imageDimensions . ' ' . $loadingAttr . ' fetchpriority="' . $fetchPriority . '"/>';

        if (!$open_lightbox) {
            $output .= (!empty($link) ? '</a>' : '');
        }

        $output .= '</div>';
        $output .= ($show_title && $title && $title_position === 'bottom' ? '<' . $heading_selector . ' class="fon-widget-title d-block">' . $title . '</' . $heading_selector . '>' : '');
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function modal_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $modalUniqueId = 'fon-modal-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $modal_selector = (isset($content->modal_selector) && $content->modal_selector ? $content->modal_selector : 'image');
        $name_widget = '';

        if (is_object($content->name_widget)) {
            $name_widget = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        }
        else if (is_string($content->name_widget)) {
            $name_widget = $content->name_widget;
        }

        $image = '';

        if (is_object($content->image)) {
            $image = (isset($content->image->{$this->lang}) && $content->image->{$this->lang} ? $content->image->{$this->lang} : array_values((array) $content->image)[0] ?? '');
        }
        else if (is_string($content->image)) {
            $image = $content->image;
        }

        $image_src = ($image ? static::assetLinkDetermine($image) : static::assetLinkDetermine(self::$imagePlaceholder));
        $image_width = (isset($content->image_width) && $content->image_width ? $content->image_width : (object) ['xxl' => '100', 'xl' => '100', 'lg' => '100', 'md' => '100', 'sm' => '100', 'xs' => '100']);
        $image_height = (isset($content->image_height) && $content->image_height ? $content->image_height : (object) ['xxl' => '100', 'xl' => '100', 'lg' => '100', 'md' => '100', 'sm' => '100', 'xs' => '100']);
        $image_use_border = (isset($content->image_use_border) && $content->image_use_border == 'yes' ? true : false);
        $image_border = (isset($content->image_border) && $content->image_border ? $content->image_border : '2px solid #ffffff');
        $image_radius = (isset($content->image_radius) && $content->image_radius ? $content->image_radius : '');
        $image_show_icon = (isset($content->image_show_icon) && $content->image_show_icon == 'yes' ? true : false);
        $image_icon = (isset($content->image_icon) && $content->image_icon ? $content->image_icon : 'fa-solid fa-play');
        $image_icon_size = (isset($content->image_icon_size) && $content->image_icon_size ? $content->image_icon_size : '14');
        $image_icon_color = (isset($content->image_icon_color) && $content->image_icon_color ? $content->image_icon_color : '#fff');
        $button = ['button_text' => $content->button_text ?? '', 'button_target' => '', 'button_type' => $content->button_type ?? 'default', 'button_style' => $content->button_style ?? 'default', 'button_custom_style' => $content->button_custom_style ?? 'default', 'button_shape' => $content->button_shape ?? '', 'button_size' => $content->button_size ?? '', 'button_padding' => $content->button_padding ?? '', 'button_color_normal' => $content->button_color->normal ?? '', 'button_color_hover' => $content->button_color->hover ?? '', 'button_background_normal' => $content->button_background->normal ?? '', 'button_background_hover' => $content->button_background->hover ?? '', 'button_gradient_normal' => $content->button_gradient->normal ?? '', 'button_gradient_hover' => $content->button_gradient->hover ?? '', 'show_button_icon' => $content->show_button_icon ?? 'no', 'button_icon' => $content->button_icon ?? '', 'button_icon_position' => $content->button_icon_position ?? '', 'scroll_button' => 'no', 'block_button' => 'no', 'button_font' => $content->button_font ?? ''];
        $icon = (isset($content->icon) && $content->icon ? $content->icon : 'fa-solid fa-play');
        $icon_size = (isset($content->icon_size) && $content->icon_size ? $content->icon_size : (object) ['xxl' => '36', 'xl' => '36', 'lg' => '36', 'md' => '36', 'sm' => '36', 'xs' => '36']);
        $icon_color = (isset($content->icon_color) && $content->icon_color ? $content->icon_color : '#ffffff');
        $icon_bg_color = (isset($content->icon_bg_color) && $content->icon_bg_color ? $content->icon_bg_color : 'var(--theme-secondary)');
        $icon_width = (isset($content->icon_width) && $content->icon_width ? $content->icon_width : (object) ['xxl' => '100', 'xl' => '100', 'lg' => '100', 'md' => '100', 'sm' => '100', 'xs' => '100']);
        $icon_height = (isset($content->icon_height) && $content->icon_height ? $content->icon_height : (object) ['xxl' => '100', 'xl' => '100', 'lg' => '100', 'md' => '100', 'sm' => '100', 'xs' => '100']);
        $icon_use_border = (isset($content->icon_use_border) && $content->icon_use_border == 'yes' ? true : false);
        $icon_border = (isset($content->icon_border) && $content->icon_border ? $content->icon_border : '1px solid var(--theme-primary)');
        $icon_border_radius = (isset($content->icon_border_radius) && $content->icon_border_radius ? $content->icon_border_radius : '');
        $icon_shadow = (isset($content->icon_shadow) && $content->icon_shadow ? $content->icon_shadow : '');
        $selector_position_type = (isset($content->selector_position_type) && $content->selector_position_type ? $content->selector_position_type : 'none');
        $selector_position = (isset($content->selector_position) && $content->selector_position ? $content->selector_position : (object) ['left' => '', 'right' => '', 'top' => '', 'bottom' => '']);
        $center_selector = (isset($content->center_selector) && $content->center_selector == 'yes' ? true : false);
        $show_ripple_effect = (isset($content->show_ripple_effect) && $content->show_ripple_effect == 'yes' ? true : false);
        $ripple_effect_color = (isset($content->ripple_effect_color) && $content->ripple_effect_color ? $content->ripple_effect_color : '#000000');
        $ripple_effect_color = self::validateAndNormalizeColor($ripple_effect_color);
        $content_type = (isset($content->content_type) && $content->content_type ? $content->content_type : 'video');
        $video_source = (isset($content->video_source) && $content->video_source ? $content->video_source : 'youtube');
        $video_url = '';

        if (is_object($content->video_url)) {
            $video_url = (isset($content->video_url->{$this->lang}) && $content->video_url->{$this->lang} ? $content->video_url->{$this->lang} : array_values((array) $content->video_url)[0] ?? '');
        }
        else if (is_string($content->video_url)) {
            $video_url = $content->video_url;
        }

        $mp4_video = '';

        if (is_object($content->mp4_video)) {
            $mp4_video = (isset($content->mp4_video->{$this->lang}) && $content->mp4_video->{$this->lang} ? $content->mp4_video->{$this->lang} : array_values((array) $content->mp4_video)[0] ?? '');
        }
        else if (is_string($content->mp4_video)) {
            $mp4_video = $content->mp4_video;
        }

        if ($mp4_video) {
            $mp4_video = static::assetLinkDetermine($mp4_video);
        }
        $show_control = (isset($content->show_control) && $content->show_control == 'yes' ? true : false);
        $video_loop = (isset($content->video_loop) && $content->video_loop == 'yes' ? true : false);
        $video_mute = (isset($content->video_mute) && $content->video_mute == 'yes' ? true : false);
        $autoplay_video = (isset($content->autoplay_video) && $content->autoplay_video == 'yes' ? true : false);
        $text_content = '';

        if (is_object($content->text_content)) {
            $text_content = (isset($content->text_content->{$this->lang}) && $content->text_content->{$this->lang} ? $content->text_content->{$this->lang} : array_values((array) $content->text_content)[0] ?? '');
        }
        else if (is_string($content->text_content)) {
            $text_content = $content->text_content;
        }

        $image_content = '';

        if (is_object($content->image_content)) {
            $image_content = (isset($content->image_content->{$this->lang}) && $content->image_content->{$this->lang} ? $content->image_content->{$this->lang} : array_values((array) $content->image_content)[0] ?? '');
        }
        else if (is_string($content->image_content)) {
            $image_content = $content->image_content;
        }

        $image_content_src = ($image ? static::assetLinkDetermine($image_content) : static::assetLinkDetermine(self::$imagePlaceholder));
        $image_content_alt = '';

        if (is_object($content->image_content_alt)) {
            $image_content_alt = (isset($content->image_content_alt->{$this->lang}) && $content->image_content_alt->{$this->lang} ? $content->image_content_alt->{$this->lang} : array_values((array) $content->image_content_alt)[0] ?? '');
        }
        else if (is_string($content->image_content_alt)) {
            $image_content_alt = $content->image_content_alt;
        }
        $modal_popup_sizes = (isset($content->modal_popup_sizes) && $content->modal_popup_sizes ? $content->modal_popup_sizes : (object) ['width' => '760', 'height' => '400']);
        $modal_popup_overflow = (isset($content->modal_popup_overflow) && $content->modal_popup_overflow ? $content->modal_popup_overflow : 'auto');
        $style = '';
        if (($modal_selector == 'image') && $image) {
            if ($image_use_border) {
                $style .= '#' . $widgetId . ' .fon-modal-selector .fon-modal-image{';
                $style .= ($image_border ? 'border:' . $image_border . ';' : '');
                $style .= '}';
            }

            $style .= '#' . $widgetId . ' .fon-modal-selector, #' . $widgetId . ' .fon-modal-image, #' . $widgetId . ' .fon-ripple-effect{';
            $style .= ($image_radius ? 'border-radius:' . $image_radius . ';' : '');
            $style .= '}';
            $responsiveValues = [];

            if ($image_height) {
                $responsiveValues[] = ['type' => 'height', 'unit' => 'px', 'value' => $image_height];
            }

            if ($image_width) {
                $responsiveValues[] = ['type' => 'width', 'unit' => 'px', 'value' => $image_width];
            }

            $responsiveItems = ['#' . $widgetId . ' .fon-modal-selector, #' . $widgetId . ' .fon-modal-image, #' . $widgetId . ' .fon-modal-image img' => $responsiveValues];
            $style .= self::parseResponsiveItems($responsiveItems);
            if ($image_show_icon && $image_icon) {
                $style .= '#' . $widgetId . ' .fon-modal-image .fon-modal-image-icon{';
                $style .= ($image_icon_size ? 'font-size:' . $image_icon_size . 'px;' : '');
                $style .= ($image_icon_color ? 'color:' . $image_icon_color . ';' : '');
                $style .= 'position: absolute;';
                $style .= 'top: 50%;';
                $style .= 'left: 50%;';
                $style .= 'transform: translate(-50%, -50%);';

                if ($icon_shadow) {
                    $style .= 'text-shadow:' . $icon_shadow . ';';
                }

                $style .= '}';
            }
        }
        else if (($modal_selector == 'icon') && $icon) {
            $style .= '#' . $widgetId . ' .fon-modal-icon{';
            $style .= ($icon_color ? 'color:' . $icon_color . ';' : '');
            $style .= ($icon_bg_color ? 'background:' . $icon_bg_color . ';' : '');
            $style .= ($icon_border_radius ? 'border-radius:' . $icon_border_radius . ';' : '');
            $style .= ($icon_shadow ? 'box-shadow:' . $icon_shadow . ';' : '');
            $style .= ($icon_use_border && $icon_border ? 'border:' . $icon_border . ';' : '');
            $style .= 'aspect-ratio: 1 / 1;';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-ripple-effect{';
            $style .= ($icon_border_radius ? 'border-radius:' . $icon_border_radius . ';' : '');
            $style .= '}';
            $responsiveValues = [];

            if ($icon_size) {
                $responsiveValues[] = ['type' => 'font-size', 'unit' => 'px', 'value' => $icon_size];
            }

            if ($icon_height) {
                $responsiveValues[] = ['type' => 'height', 'unit' => 'px', 'value' => $icon_height];
            }

            if ($icon_width) {
                $responsiveValues[] = ['type' => 'width', 'unit' => 'px', 'value' => $icon_width];
            }

            $responsiveItems = ['#' . $widgetId . ' .fon-modal-icon' => $responsiveValues];
            $style .= self::parseResponsiveItems($responsiveItems);
        }

        if ($selector_position_type != 'none') {
            $style .= '#' . $widgetId . '{';
            if (in_array($selector_position_type, ['absolute' => true, 'relative' => true]) && $center_selector) {
                $style .= 'transform: translate(-50%, -50%);';
            }

            $style .= '}';
            $responsiveValues = [
                ['type' => 'left', 'unit' => '', 'value' => $selector_position->left],
                ['type' => 'right', 'unit' => '', 'value' => $selector_position->right],
                ['type' => 'top', 'unit' => '', 'value' => $selector_position->top],
                ['type' => 'bottom', 'unit' => '', 'value' => $selector_position->bottom]
            ];
            $responsiveItems = ['#' . $widgetId => $responsiveValues];
            $style .= self::parseResponsiveItems($responsiveItems);
        }

        if ($content_type != 'video') {
            $style .= '#' . $modalUniqueId . ' .fon-modal-inner-block {';
            $style .= 'width:' . $modal_popup_sizes->width . 'px;';
            $style .= 'height:' . $modal_popup_sizes->height . 'px;';
            $style .= 'max-width:100%!important;';

            if ($content_type != 'image') {
                $style .= 'overflow-y:' . $modal_popup_overflow . ';';
            }

            $style .= '}';
        }
        if ($show_ripple_effect && isset($ripple_effect_color['color']) && $ripple_effect_color['color']) {
            $style .= '#' . $widgetId . ' .fon-ripple-effect{';
            $style .= '--fon-effect-rgb:' . $ripple_effect_color['color'] . ';';
            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $this->addAsset('magnific');
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-modal-widget ' . ($content->fon_class ?? '') . ' position-' . $selector_position_type . '">';

        if ($content_type === 'text') {
            $url = '#' . $modalUniqueId;
            $output .= '<div id="' . $modalUniqueId . '" class="mfp-hide fon-modal-text-popup-block position-relative mx-auto" style="width:min-content;max-width:90%!important">';
            $output .= '<div class="fon-modal-inner-block position-relative p-4 rounded-3 overflow-x-hidden bg-white">';
            $output .= $text_content;
            $output .= '</div>';
            $output .= '</div>';
            $attribs = 'data-popup_type="inline" data-mainclass="mfp-no-margins mfp-with-zoom"';
        }
        else if ($content_type === 'video') {
            if ($video_source == 'mp4') {
                $url = $mp4_video;
                $attribs = 'data-popup_type="video" data-mainclass="mfp-no-margins mfp-with-zoom" data-show-control="' . $show_control . '" data-video-loop="' . $video_loop . '" data-video-mute="' . $video_mute . '" data-autoplay-video="' . $autoplay_video . '"';
            }
            else {
                $url = $video_url;
                $attribs = 'data-popup_type="iframe" data-mainclass="mfp-no-margins mfp-with-zoom"';
            }
        }
        else {
            if (empty($image_content_alt)) {
                $url_part_of_content = explode('/', $image_content_src);
                $modal_content_image_alt_text = end($url_part_of_content);
            }

            $url = '#' . $modalUniqueId;
            $imageDimensions = static::getImageDimensions($image_content_src, $pageData['badress']);
            $output .= '<div id="' . $modalUniqueId . '" class="mfp-hide fon-modal-popup-image-block position-relative mx-auto" style="width:fit-content; height:fit-content;">';
            $output .= '<div class="fon-modal-inner-block">';
            $output .= '<img class="mfp-img" src="' . $image_content_src . '" alt="' . $modal_content_image_alt_text . '" ' . $imageDimensions . '>';
            $output .= '</div>';
            $output .= '</div>';
            $attribs = 'data-popup_type="inline" data-mainclass="mfp-no-margins mfp-with-zoom"';
        }

        if ($modal_selector === 'image') {
            if ($image_src) {
                $imageDimensions = static::getImageDimensions($image_src, $pageData['badress']);
                $output .= '<a class="fon-modal-selector fon-magnific-popup d-inline-block position-relative" ' . $attribs . ' href="' . $url . '" id="' . $modalUniqueId . '-selector">';

                if ($show_ripple_effect) {
                    $output .= '<span class="fon-ripple-effect"></span>';
                }

                $output .= '<span class="fon-modal-image overflow-hidden d-block position-relative z-1">';
                $output .= '<img src="' . $image_src . '" class="img img-fluid object-fit-cover" alt="' . $name_widget . '" ' . $imageDimensions . '/>';
                $output .= ($image_show_icon ? '<span class="fon-modal-image-icon"><i class="' . $image_icon . '"></i></span>' : '');
                $output .= '</span>';
                $output .= '</a>';
            }
        }
        else if ($modal_selector === 'icon') {
            if ($icon) {
                $select_icon = explode(' ', $icon);

                if (count($select_icon) === 1) {
                    $icon = 'fa-solid ' . $icon;
                }

                $output .= '<a class="fon-modal-selector fon-magnific-popup d-inline-block position-relative" href="' . $url . '" ' . $attribs . ' id="' . $modalUniqueId . '-selector">';

                if ($show_ripple_effect) {
                    $output .= '<span class="fon-ripple-effect"></span>';
                }

                $output .= '<span class="fon-modal-icon d-inline-flex align-items-center justify-content-center position-relative z-1">';
                $output .= '<i class="' . $icon . '" aria-hidden="true"></i>';
                $output .= '</span>';
                $output .= '</a>';
            }
        }
        else {
            $button['button_link'] = $url;
            $modalButton = $this->parseButton((object) $button, $moduleId, $pageData, ['class' => 'fon-magnific-popup fon-modal-selector position-relative z-1', 'attributes' => $attribs, 'id' => $modalUniqueId . '-selector']);
            $output .= '<span class="fon-modal-button d-inline-block position-relative">';

            if ($show_ripple_effect) {
                $output .= '<span class="fon-ripple-effect rounded-4"></span>';
            }

            $output .= $modalButton;
            $output .= '</span>';
        }

        $output .= '</div>';
        return $output;
    }

    private function news_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetPages($content, $moduleId, $pageData, 'news');
    }

    private function number_box_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        $style .= '#' . $widgetId . ' .number-box .number{';
        if (isset($content->number_size) && $content->number_size) {
            $style .= 'font-size:' . $content->number_size . 'px;';
        }
        if (isset($content->number_weight) && $content->number_weight) {
            $style .= 'font-weight:' . $content->number_weight . ';';
        }

        $style .= 'width:' . $content->number_size . 'px;';
        $style .= 'height:' . $content->number_size . 'px;';
        $style .= 'line-height:' . $content->number_size . 'px;';
        if (isset($content->number_color_type) && $content->number_color_type == 'flat') {
            $style .= '--bs-normal-color:' . $content->number_color->normal . ';';
            $style .= '--bs-hover-color:' . $content->number_color->hover . ';';
        }
        else if (isset($content->number_color_type) && $content->number_color_type == 'gradient') {
            $style .= self::parseGradient($content->number_gradient->normal, 'normal-color');
            $style .= self::parseGradient($content->number_gradient->hover, 'hover-color');
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .number-container{';
        if (isset($content->number_size) && $content->number_size) {
            $style .= 'width:' . ($content->number_size + 30) . 'px;';
            $style .= 'height:' . ($content->number_size + 30) . 'px;';
        }
        if (isset($content->number_border->normal) && $content->number_border->normal) {
            $style .= '--bs-normal-border:' . $content->number_border->normal . ';';
        }
        if (isset($content->number_border->hover) && $content->number_border->hover) {
            $style .= '--bs-hover-border:' . $content->number_border->hover . ';';
        }
        if (isset($content->number_radius->normal) && $content->number_radius->normal) {
            $style .= '--bs-normal-radius:' . $content->number_radius->normal . 'px;';
        }
        if (isset($content->number_radius->hover) && $content->number_radius->hover) {
            $style .= '--bs-hover-radius:' . $content->number_radius->hover . 'px;';
        }
        if (isset($content->number_shadow->normal) && $content->number_shadow->normal) {
            $style .= '--bs-normal-shadow:' . $content->number_shadow->normal . ';';
        }
        if (isset($content->number_shadow->hover) && $content->number_shadow->hover) {
            $style .= '--bs-hover-shadow:' . $content->number_shadow->hover . ';';
        }
        if (isset($content->number_background_type) && $content->number_background_type == 'flat') {
            $style .= '--bs-normal-bg:' . $content->number_bg->normal . ';';
            $style .= '--bs-hover-bg:' . $content->number_bg->hover . ';';
        }
        else if (isset($content->number_background_type) && $content->number_background_type == 'gradient') {
            $style .= self::parseGradient($content->number_bg_gradient->normal, 'normal-bg');
            $style .= self::parseGradient($content->number_bg_gradient->hover, 'hover-bg');
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .number-box-title{';
        if (isset($content->title_color->normal) && $content->title_color->normal) {
            $style .= '--bs-normal-color:' . $content->title_color->normal . ';';
        }
        if (isset($content->title_color->hover) && $content->title_color->hover) {
            $style .= '--bs-hover-color:' . $content->title_color->hover . ';';
        }

        if (isset($content->title_font)) {
            $style .= self::parseFontProperties($content->title_font);
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .number-box-desc{';
        if (isset($content->content_color->normal) && $content->content_color->normal) {
            $style .= '--bs-normal-color:' . $content->content_color->normal . ';';
        }
        if (isset($content->content_color->hover) && $content->content_color->hover) {
            $style .= '--bs-hover-color:' . $content->content_color->hover . ';';
        }

        $style .= '}';
        $style .= '#' . $widgetId . ' .number-box{';
        if (isset($content->background_type) && $content->background_type == 'flat') {
            $style .= '--bs-normal-bg:' . $content->background->normal . ';';
            $style .= '--bs-hover-bg:' . $content->background->hover . ';';
        }
        else if (isset($content->background_type) && $content->background_type == 'gradient') {
            $style .= self::parseGradient($content->background_gradient->normal, 'normal-bg');
            $style .= self::parseGradient($content->background_gradient->hover, 'hover-bg');
        }
        if (isset($content->shadow->normal) && $content->shadow->normal) {
            $style .= '--bs-normal-shadow:' . $content->shadow->normal . ';';
        }
        if (isset($content->shadow->hover) && $content->shadow->hover) {
            $style .= '--bs-hover-shadow:' . $content->shadow->hover . ';';
        }
        if (isset($content->border_radius->normal) && $content->border_radius->normal) {
            $style .= '--bs-normal-radius:' . $content->border_radius->normal . 'px;';
        }
        if (isset($content->border_radius->hover) && $content->border_radius->hover) {
            $style .= '--bs-hover-radius:' . $content->border_radius->hover . 'px;';
        }
        if (isset($content->use_border) && $content->use_border == 'yes') {
            if (isset($content->border->normal) && $content->border->normal) {
                $style .= '--bs-normal-border:' . $content->border->normal . ';';
            }
            if (isset($content->border->hover) && $content->border->hover) {
                $style .= '--bs-hover-border:' . $content->border->hover . ';';
            }
        }
        if (isset($content->padding) && $content->padding) {
            $style .= 'padding:' . $content->padding . 'px;';
        }

        $style .= '}';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $attributes = '';

        if ($content->number_position == 'top') {
            $attributes .= 'align-items-center ';

            switch ($content->align) {
            case 'left':
                $attributes .= 'justify-content-start text-start';
                break;
            case 'right':
                $attributes .= 'justify-content-end text-end';
                break;
            case 'center':
                $attributes .= 'justify-content-center text-center';
                break;
            }
        }
        else {
            if ($content->number_position == 'left') {
                $attributes .= 'justify-content-start text-start ';
            }
            else if ($content->number_position == 'right') {
                $attributes .= 'justify-content-end text-end ';
            }
            if (isset($content->vertical_align) && $content->vertical_align) {
                switch ($content->vertical_align) {
                case 'top':
                    $attributes .= 'align-items-start';
                    break;
                case 'bottom':
                    $attributes .= 'align-items-end';
                    break;
                case 'center':
                    $attributes .= 'align-items-bottom';
                    break;
                }
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-number-box-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $output .= '<div class="number-box number-' . $content->number_position . ' ' . $attributes . ' ' . $content->background_type . '">';
        $output .= '<div class="number-box-number">';
        $output .= '<div class="number-container ' . $content->number_background_type . '">';
        $output .= '<div class="number ' . $content->number_color_type . '">';
        $output .= trim($content->number);
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '<div class="number-box-content">';
        $contentTitle = (isset($content->title->{$this->lang}) && $content->title->{$this->lang} ? $content->title->{$this->lang} : array_values((array) $content->title)[0] ?? '');
        $contentDesc = (isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : array_values((array) $content->content)[0] ?? '');

        if ($contentTitle) {
            $output .= '<' . $content->heading_selector . ' class="number-box-title">';
            $output .= $contentTitle;
            $output .= '</' . $content->heading_selector . '>';
        }

        if ($contentDesc) {
            $output .= '<div class="number-box-desc">';
            $output .= $contentDesc;
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function page_menu_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $items = (isset($content->items) && $content->items ? $content->items : []);
        $enable_fixed = (isset($content->enable_fixed) && $content->enable_fixed == 'yes' ? true : false);
        $menu_type = (isset($content->menu_type) && $content->menu_type ? $content->menu_type : 'menu');
        $menu_align = (isset($content->menu_align) && $content->menu_align ? $content->menu_align : 'start');
        $menu_position = (isset($content->menu_position) && $content->menu_position ? $content->menu_position : 'right');
        $menu_seperate = (isset($content->menu_seperate) && $content->menu_seperate == 'yes' ? true : false);
        $disable = (isset($content->disable) && $content->disable ? $content->disable : (object) ['xl' => 'block', 'lg' => 'block', 'md' => 'block', 'sm' => 'none', 'xs' => 'none']);
        $style = '';
        $style .= '#' . $widgetId . ' .nav-link{';
        if (isset($content->link_color->normal) && $content->link_color->normal) {
            $style .= '--link-color:' . $content->link_color->normal . ';';
        }
        if (isset($content->link_color->hover) && $content->link_color->hover) {
            $style .= '--link-color-hover:' . $content->link_color->hover . ';';
        }
        if (isset($content->link_backround->normal) && $content->link_backround->normal) {
            $style .= '--background-color:' . $content->link_backround->normal . ';';
        }
        if (isset($content->link_backround->hover) && $content->link_backround->hover) {
            $style .= '--background-color-hover:' . $content->link_backround->hover . ';';
        }
        if (isset($content->icon_color->normal) && $content->icon_color->normal) {
            $style .= '--icon-color:' . $content->icon_color->normal . ';';
        }
        if (isset($content->icon_color->hover) && $content->icon_color->hover) {
            $style .= '--icon-color-hover:' . $content->icon_color->hover . ';';
        }
        if (isset($content->link_font) && $content->link_font) {
            $style .= self::parseFontProperties($content->link_font);
        }

        $style .= '}';
        if (isset($content->link_padding) && $content->link_padding) {
            $responsiveItems = [
                '.nav-link' => [
                ['type' => 'padding', 'value' => $content->link_padding]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $menuClasses = ['page-inner-nav', 'gumshoe'];
        if ($enable_fixed && $menu_type != 'float') {
            $menuClasses[] = 'nav-fixed';
        }

        if ($menu_type == 'menu') {
            $menuClasses[] = 'nav-' . $menu_align;
        }

        if ($menu_type == 'float') {
            $menuClasses[] = 'nav-' . $menu_position;
        }

        if ($menu_type) {
            $menuClasses[] = 'nav-' . $menu_type;
        }

        if ($menu_type == 'menu') {
            $menuClasses[] = 'navbar navbar-expand-sm p-sm-0';
        }
        if ($menu_seperate && $menu_align != 'center') {
            $menuClasses[] = 'nav-seperate';
        }
        if (isset($content->fon_class) && $content->fon_class) {
            $menuClasses[] = $content->fon_class;
        }

        foreach ($disable as $k => $d) {
            if ($k == 'xs') {
                $menuClasses[] = 'd-' . $d;
            }
            else {
                $menuClasses[] = 'd-' . $k . '-' . $d;
            }
        }

        $this->addAsset('gumshoe');
        $output = '';

        if ($items) {
            $output .= '<div id="' . $widgetId . '" class="' . implode(' ', $menuClasses) . '">';

            if ($menu_type == 'menu') {
                $output .= '<div class="container">';
                $output .= '<a class="navbar-brand d-inline-block d-sm-none fs-16 fw-bold" href="javascript:void(0)">' . __('theme/quick_access') . '</a>';
                $output .= '<button class="navbar-toggler collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#' . $widgetId . 'navbar" aria-controls="navbarsExample03" aria-expanded="false" aria-label="Toggle navigation">' . "\n" . '                    <i class="fa-solid fa-bars"></i>';
                $output .= '</button>';
                $output .= '<div class="navbar-collapse collapse w-100" id="' . $widgetId . 'navbar" style="">';
            }

            $output .= '<ul class="nav ' . ($menu_type != 'menu' ? 'list-group' : 'w-100 flex-column flex-sm-row') . '">';

            foreach ($items as $key => $item) {
                if ($item) {
                    $menu_title = (isset($item->menu_title->{$this->lang}) && $item->menu_title->{$this->lang} ? $item->menu_title->{$this->lang} : array_values((array) $item->menu_title)[0] ?? '');
                    $menu_external = (isset($item->menu_external) && $item->menu_external == 'yes' ? true : false);
                    $menu_link = (isset($item->menu_link) && $item->menu_link ? $item->menu_link : '#');
                    $menu_external_link = (isset($item->menu_external_link->{$this->lang}) && $item->menu_external_link->{$this->lang} ? $item->menu_external_link->{$this->lang} : '#');
                    $menu_target = (isset($item->menu_target) && $item->menu_target ? $item->menu_target : '_self');
                    $show_icon = (isset($item->show_icon) && $item->show_icon == 'yes' ? true : false);
                    $menu_icon = (isset($item->menu_icon) && $item->menu_icon ? $item->menu_icon : '');

                    if ($menu_external) {
                        $menu_external_link = self::checkLink($menu_external_link);
                    }
                    $output .= '<li class="nav-item ' . (($key == 0) && !$menu_external ? 'active' : '') . ' ' . ($menu_type == 'list' ? 'list-group-item' : '') . '">';
                    $output .= '<a class="nav-link ' . ($menu_external ? 'external-link' : 'fon-scroll-button') . '" ' . (($key == 0) && !$menu_external ? 'aria-current="page"' : '') . ' href="' . ($menu_external ? $menu_external_link : $menu_link) . '" ' . ($menu_external ? 'target="' . $menu_target . '"' : '') . '>';

                    if ($menu_type == 'float') {
                        $output .= '<span class="nav-link-icon">';
                        if ($show_icon && $menu_icon) {
                            $output .= '<i class="' . $menu_icon . '"></i>';
                        }
                        else {
                            $output .= '<i class="fa-solid fa-circle"></i>';
                        }

                        $output .= '</span>';
                        $output .= '<span class="nav-link-text">';
                        $output .= $menu_title;
                        $output .= '</span>';
                    }
                    else {
                        $output .= ($show_icon && $menu_icon ? '<i class="' . $menu_icon . '"></i> ' : '');
                        $output .= $menu_title;
                    }

                    $output .= '</a>';
                    $output .= '</li>';
                }
            }

            $output .= '</ul>';

            if ($menu_type == 'menu') {
                $output .= '</div>';
                $output .= '</div>';
            }

            $output .= '</div>';
        }

        return $output;
    }

    private function product_wizard_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        require_once __DIR__ . '/builder/widget-styles/product_wizard.php';
        $widgetId = 'fon-widget-' . $moduleId;
        $scriptId = 'fon-widget-' . $moduleId . '-data';
        $display_mode = (isset($content->display_mode) && $content->display_mode ? $content->display_mode : 'inline');
        $trigger_class = (isset($content->trigger_class) && $content->trigger_class ? $content->trigger_class : 'btn btn-default btn-lg');
        $trigger_align = (isset($content->trigger_align) && $content->trigger_align ? $content->trigger_align : 'center');
        $container_width = (isset($content->container_width) && $content->container_width ? $content->container_width : '');
        $container_width = ProductWizardHelper::getValidatedMaxWidth($container_width);
        $accent_color = (isset($content->accent_color) && $content->accent_color ? $content->accent_color : '#4f46e5');
        $trigger_text = self::getFieldMultilingualText($content->trigger_text ?? NULL, $this->lang, 'Ürün Sihirbazı');
        $back_btn_text = self::getFieldMultilingualText($content->back_btn_text ?? NULL, $this->lang, 'Geri');
        $next_btn_text = self::getFieldMultilingualText($content->next_btn_text ?? NULL, $this->lang, 'Devam Et');
        $result_btn_text = self::getFieldMultilingualText($content->result_btn_text ?? NULL, $this->lang, 'Sonucu Görüntüle');
        $restart_btn_text = self::getFieldMultilingualText($content->restart_btn_text ?? NULL, $this->lang, 'Testi Yeniden Başlat');
        $result_badge_text = self::getFieldMultilingualText($content->result_badge_text ?? NULL, $this->lang, 'Analiz Tamamlandı');
        $result_title_text = self::getFieldMultilingualText($content->result_title_text ?? NULL, $this->lang, 'Sizin için en uygun plan');
        $result_subtitle_text = self::getFieldMultilingualText($content->result_subtitle_text ?? NULL, $this->lang, 'Verdiğiniz yanıtlara göre aşağıdaki paketi öneriyoruz.');
        $planIds = (isset($content->plans) && $content->plans ? $content->plans : 'none');
        $plans = [];
        $finalPlans = [];
        $scoresMap = [];

        if ($planIds != 'none') {
            $planIds = ProductWizardHelper::parsePlanSource($planIds);

            if ($planIds) {
                $plans = $this->getProducts('', $planIds, count($planIds), true);
            }
        }

        if ($plans) {
            $colorMap = ProductWizardHelper::generateColorClasses($plans);

            foreach ($plans as $k => $plan) {
                $scoresMap[$plan['id']] = 0;
                $id = $plan['id'];
                $type = $plan['type'] ?? '';
                $features = $plan['features'] ?? NULL;
                $options = $plan['options'] ?? [];
                $prices = $plan['prices'] ?? [];
                $currency_symbols = self::getCurrencySymbols();
                $productPrice = self::calculatePrices($prices, $currency_symbols, $plan['override_usrcurrency'], $type);
                $desc = '';
                $featuresArr = ProductWizardHelper::maybeJsonToArray($features);
                if ($featuresArr !== null && isset($featuresArr['slogan'])) {
                    $desc = $featuresArr['slogan'];
                }

                $featuresList = [];

                if ($type === 'server') {
                    $featuresList = ProductWizardHelper::parseFeaturesServer($options);
                }
                else if ($type === 'special') {
                    if ($featuresArr !== null) {
                        if (isset($featuresArr['features'])) {
                            $featuresList = ProductWizardHelper::parseFeaturesArray($featuresArr);
                        }
                        else {
                            $clOptions = ProductWizardHelper::maybeJsonToArray($plan['cl_options'] ?? NULL) ?? [];
                            $featuresList = ProductWizardHelper::parseFeaturesSpecialColumns($featuresArr, $clOptions);
                        }
                    }
                    else {
                        $featuresList = ProductWizardHelper::parseFeaturesString((string) $features);
                    }
                }
                else if ($featuresArr !== null) {
                    if (isset($featuresArr['features'])) {
                        $featuresList = ProductWizardHelper::parseFeaturesArray($featuresArr);
                    }
                }
                else if (is_string($features) && trim($features) !== '') {
                    $featuresList = ProductWizardHelper::parseFeaturesString($features);
                }
                if (isset($plan['options_lang']['external_link']) && $plan['options_lang']['external_link'] != '') {
                    $buy_link = $plan['options_lang'];
                }
                else if (isset($plan['options']['external_link']) && $plan['options']['external_link'] != '') {
                    $buy_link = $plan['options']['external_link'];
                }
                else {
                    $buy_link = Controllers::$init->CRLink('order-steps', [$type, $id]);
                }
                if (isset($plan['options_lang']['buy_button_name']) && $plan['options_lang']['buy_button_name'] != '') {
                    $buy_button_name = $plan['options_lang']['buy_button_name'];
                }
                else if (isset($plan['options']['buy_button_name']) && $plan['options']['buy_button_name'] != '') {
                    $buy_button_name = $plan['options']['buy_button_name'];
                }
                else {
                    $buy_button_name = __('website/index/add-basket-button');
                }
                $finalPlans[$id] = ['colorClass' => $colorMap[$id], 'name' => $plan['title'] ?? '', 'desc' => $desc, 'price' => (isset($productPrice['price']) && $productPrice['price'] ? strip_tags($productPrice['price']) : ''), 'period' => $productPrice['period'] ?? '', 'features' => $featuresList, 'buyLink' => $buy_link, 'buyButtonName' => $buy_button_name];
            }
        }
        $steps = (isset($content->questions) && $content->questions ? $content->questions : []);
        $finalSteps = [];
        $countSteps = count($steps);

        if ($steps) {
            foreach ($steps as $k => $step) {
                $title = self::getFieldMultilingualText($step->title ?? NULL, $this->lang, 'Soru ' . ($k + 1));
                $desc = self::getFieldMultilingualText($step->desc ?? NULL, $this->lang, '');
                $options = [];
                if (isset($step->options) && is_array($step->options) && 0 < count($step->options)) {
                    foreach ($step->options as $option) {
                        $optionTitle = self::getFieldMultilingualText($option->title ?? NULL, $this->lang, '');
                        $optionDesc = self::getFieldMultilingualText($option->desc ?? NULL, $this->lang, '');
                        $optionIcon = $option->icon ?? '';
                        $optionScores = $option->scores ?? '';
                        if (!empty($optionScores) && is_string($optionScores)) {
                            $optionScores = ProductWizardHelper::parseScores($optionScores);
                        }

                        $options[] = ['icon' => $optionIcon, 'title' => $optionTitle, 'desc' => $optionDesc, 'score' => $optionScores];
                    }
                }
                if ($title && $options) {
                    $finalSteps[] = ['question' => $title, 'desc' => $desc, 'options' => $options];
                }
            }
        }

        $payload = [
            'scriptId'  => $scriptId,
            'widgetId'  => $widgetId,
            'labels'    => ['resultBtn' => $result_btn_text, 'restartBtn' => $restart_btn_text, 'resultBadge' => $result_badge_text, 'resultTitle' => $result_title_text, 'resultSubtitle' => $result_subtitle_text, 'triggerText' => $trigger_text, 'triggerClass' => $trigger_class, 'backBtn' => $back_btn_text, 'nextBtn' => $next_btn_text, 'accentColor' => $accent_color],
            'steps'     => $finalSteps,
            'plans'     => $finalPlans,
            'scoresMap' => $scoresMap
        ];
        $encoded = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

        if (!is_string($encoded)) {
            $encoded = '{}';
        }

        $style = '';

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $this->addAsset('fon-product-wizard');
        $output = '';

        if ($steps) {
            $modalUid = 'fonPWModal_' . md5($widgetId);

            if ($display_mode === 'modal') {
                $output .= '<p class="text-' . $trigger_align . '">';
                $output .= '<button type="button" class="' . htmlspecialchars($trigger_class) . '" data-bs-toggle="modal" data-bs-target="#' . $modalUid . '">';
                $output .= '<i class="fa-solid fa-wand-magic-sparkles me-2"></i>' . $trigger_text;
                $output .= '</button>';
                $output .= '</p>';
                $output .= '<div class="modal fade" id="' . $modalUid . '" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-hidden="true">';
                $output .= '    <div class="modal-dialog modal-dialog-centered fon-wz-dialog">';
                $output .= '        <div class="modal-content border-0 p-0 rounded-4 overflow-hidden position-relative">';
                $output .= '            <button type="button" class="fon-wz-modal-close" data-bs-dismiss="modal" aria-label="Kapat">✕</button>';
            }

            $maxWidthStyle = ($display_mode === 'modal' ? '' : 'max-width:' . $container_width . ';');
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-product-wizard-widget ' . ($content->fon_class ?? '') . '" data-display="' . $display_mode . '" data-script-id="' . $scriptId . '" style="--fpw-accent:' . $accent_color . '; ' . $maxWidthStyle . '" ' . ($display_mode === 'modal' ? 'data-modal-id="' . $modalUid . '"' : '') . '>';
            $output .= '    <div class="fon-wizard-progress">';
            $output .= '        <div class="fon-wizard-progress-fill" style="width:25%"></div>';
            $output .= '    </div>';
            $output .= '    <div class="fon-wizard-header">';
            $output .= '        <div class="fon-wizard-step-label">' . __('theme/wizard-step') . ' <span class="fon-current-step">1</span> / ' . $countSteps . '</div>';
            $output .= '        <p class="fon-wizard-question"></p>';
            $output .= '        <p class="fon-wizard-desc"></p>';
            $output .= '    </div>';
            $output .= '    <div class="fon-wizard-body">';
            $output .= '        <div class="fon-wizard-options fon-step-panel"></div>';
            $output .= '    </div>';
            $output .= '    <div class="fon-wizard-footer">';
            $output .= '        <button type="button" class="fon-btn-back" disabled><i class="fa-solid fa-angle-left"></i> ' . $back_btn_text . '</button>';
            $output .= '        <div class="fon-wizard-dots"></div>';
            $output .= '        <button type="button" class="fon-btn-next" disabled>' . $next_btn_text . ' <i class="fa-solid fa-angle-right"></i> </button>';
            $output .= '    </div>';
            $output .= '</div>';

            if ($display_mode === 'modal') {
                $output .= '        </div>';
                $output .= '    </div>';
                $output .= '</div>';
            }

            $output .= '<script type="application/json" id="' . $scriptId . '">' . htmlspecialchars($encoded, ENT_NOQUOTES, 'UTF-8') . '</script>';
        }

        return $output;
    }

    private function progress_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $type = (isset($content->type) && $content->type ? $content->type : 'bar');
        $striped = (isset($content->striped) && $content->striped == 'yes' ? true : false);
        $animated = (isset($content->animated) && $content->animated == 'yes' ? true : false);
        $column = (isset($content->column) && $content->column ? (array) $content->column : ['xl' => 4, 'lg' => 4, 'md' => 3, 'sm' => 2, 'xs' => 1]);
        $width = (isset($content->width) && $content->width ? $content->width : '160');
        $items = (isset($content->items) && $content->items ? $content->items : []);
        $xs = min(6, max(1, (int) ($column['xs'] ?? 1)));
        $sm = min(6, max(1, (int) ($column['sm'] ?? 2)));
        $md = min(6, max(1, (int) ($column['md'] ?? 3)));
        $lg = min(6, max(1, (int) ($column['lg'] ?? 4)));
        $xl = min(6, max(1, (int) ($column['xl'] ?? 4)));
        $rowClasses = sprintf('row g-3 row-cols-%d row-cols-sm-%d row-cols-md-%d row-cols-lg-%d row-cols-xl-%d', $xs, $sm, $md, $lg, $xl);
        $style = '';

        if ($content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';

        if ($items) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-progress-widget ' . ($content->fon_class ?? '') . '">';

            if ($type == 'circle') {
                $output .= '<div class="fon-progress-circle-wrapper ' . $rowClasses . '">';
            }

            foreach ($items as $index => $item) {
                $title = '';

                if (is_object($item->title)) {
                    $title = (isset($item->title->{$this->lang}) && $item->title->{$this->lang} ? $item->title->{$this->lang} : array_values((array) $item->title)[0] ?? '');
                }
                else if (is_string($item->title)) {
                    $title = $item->title;
                }

                $subtitle = '';

                if (is_object($item->subtitle)) {
                    $subtitle = (isset($item->subtitle->{$this->lang}) && $item->subtitle->{$this->lang} ? $item->subtitle->{$this->lang} : array_values((array) $item->subtitle)[0] ?? '');
                }
                else if (is_string($item->subtitle)) {
                    $subtitle = $item->subtitle;
                }

                $description = '';

                if (is_object($item->description)) {
                    $description = (isset($item->description->{$this->lang}) && $item->description->{$this->lang} ? $item->description->{$this->lang} : array_values((array) $item->description)[0] ?? '');
                }
                else if (is_string($item->description)) {
                    $description = $item->description;
                }
                $value = (isset($item->value) && $item->value ? $item->value : '0');
                $color = (isset($item->color) && $item->color ? $item->color : 'var(--theme-primary)');

                if ($type == 'bar') {
                    $output .= '<div class="fon-progress-wrapper" data-value="' . $value . '">';
                    $output .= '<div class="fon-progress-info">';
                    $output .= '<h3 class="fon-progress-title">' . $title . '</h3>';

                    if ($subtitle) {
                        $output .= '<span class="fon-progress-percent"><span class="fon-progress-sub me-1 fw-normal">' . $subtitle . '</span><span class="fon-progress-rate" style="color: ' . $color . ';">0%</span></span>';
                    }
                    else {
                        $output .= '<span class="fon-progress-percent"><span class="fon-progress-rate" style="color: ' . $color . ';">0%</span></span>';
                    }

                    $output .= '</div>';
                    $output .= '<div class="progress fon-custom-progress">';
                    $output .= '<div class="progress-bar ' . ($striped ? 'progress-bar-striped' : '') . ' ' . ($striped && $animated ? 'progress-bar-animated' : '') . '" ' . "\n" . '                                    role="progressbar" ' . "\n" . '                                    style="width: 0%; background-color: ' . $color . ';"' . "\n" . '                                    aria-valuenow="' . $value . '" ' . "\n" . '                                    aria-valuemin="0" ' . "\n" . '                                    aria-valuemax="100">';
                    $output .= '</div>';
                    $output .= '</div>';

                    if ($description) {
                        $output .= '<p class="fon-progress-description mt-2">' . $description . '</p>';
                    }

                    $output .= '</div>';
                }
                else if ($type == 'circle') {
                    $output .= '<div class="col">';
                    $output .= '<div class="fon-circle-progress-wrapper text-center" data-value="' . $value . '">';
                    $output .= '<div class="fon-circle-progress-container mx-auto mb-3 position-relative" style="width: ' . $width . 'px;">';
                    $output .= '<svg viewBox="0 0 100 100">';
                    $output .= '<circle class="fon-circle-progress-bg" cx="50" cy="50" r="45"></circle>';
                    $output .= '<circle class="fon-circle-progress-bar is-striped is-animated" cx="50" cy="50" r="45" style="stroke: ' . $color . '"></circle>';
                    $output .= '</svg>';
                    $output .= '<div class="fon-circle-progress-info">';
                    $output .= '<span class="fon-circle-progress-percent">0%</span>';

                    if ($subtitle) {
                        $output .= '<span class="fon-progress-sub mx-auto">' . $subtitle . '</span>';
                    }

                    $output .= '</div>';
                    $output .= '</div>';

                    if ($title) {
                        $output .= '<h3 class="fon-progress-title d-inline-block my-2">' . $title . '</h3>';
                    }

                    if ($description) {
                        $output .= '<p class="fon-progress-description px-3">' . $description . '</p>';
                    }

                    $output .= '</div>';
                    $output .= '</div>';
                }
            }

            if ($type == 'circle') {
                $output .= '</div>';
            }

            $output .= '</div>';
        }

        return $output;
    }

    private function raw_content_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $raw_code = (isset($content->raw_code->{$this->lang}) && $content->raw_code->{$this->lang} ? $content->raw_code->{$this->lang} : array_values((array) $content->raw_code)[0] ?? '');

        if ($raw_code) {
            $raw_code = self::parseShortcodesToHtml($raw_code);
        }

        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="' . $content->fon_class . '">';
        $output .= $raw_code;
        $output .= '</div>';
        return $output;
    }

    private function references_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetPages($content, $moduleId, $pageData, 'references');
    }

    private function review_badge_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'micro_button');
        $value_display = (isset($content->value_display) && $content->value_display ? $content->value_display : 'both');
        $review_provider = (isset($content->review_provider) && $content->review_provider ? $content->review_provider : 'google');
        $review_title = (isset($content->review_title->{$this->lang}) && $content->review_title->{$this->lang} ? $content->review_title->{$this->lang} : $this->language['review_badge']['default_title']);
        $review_score = (isset($content->review_score) && $content->review_score ? $content->review_score : 0);
        $review_count = (isset($content->review_count) && $content->review_count ? $content->review_count : 0);
        $review_link = (isset($content->review_link) && $content->review_link ? $content->review_link : '');
        $review_link_rel = (isset($content->review_link_rel) && $content->review_link_rel ? $content->review_link_rel : []);
        $review_link_rel = ($review_link_rel ? ' rel="' . implode(' ', $review_link_rel) . '" ' : '');
        $color = ($review_provider == 'trustpilot' ? '#00B67A' : '#fbb004');
        $svgStyle = 'height: 25px;';
        $starSize = 18;
        $ticonfill = '#00b67a';
        $ticon2fill = '#005128';
        $ttextfill = '#191919';

        switch ($widget_style) {
        case 'micro_button':
            $ticonfill = $ttextfill = '#fff';
            $ticon2fill = '#00b67a';
            break;
        case 'micro_horizontal':
            break;
        case 'mini_box':
            $svgStyle = 'height: 35px;';
            $starSize = 25;
            break;
        case 'flex_box':
            $svgStyle = 'height: 35px;';
            $starSize = 20;
            $ttextfill = '#fff';
            break;
        case 'flex_mini':
            $svgStyle = 'height: 20px;';
            $starSize = 12;
            $ttextfill = '#fff';
            break;
        }

        $stars = self::getStarRating($review_score, $color, $starSize);
        $trustpilot = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1132.8 278.2" style="' . $svgStyle . '" preserveAspectRatio="xMidYMid" ><path d="M297.7 98.6h114.7V120h-45.1v120.3h-24.8V120h-44.9V98.6zm109.8 39.1h21.2v19.8h.4c.7-2.8 2-5.5 3.9-8.1 1.9-2.6 4.2-5.1 6.9-7.2 2.7-2.2 5.7-3.9 9-5.3 3.3-1.3 6.7-2 10.1-2 2.6 0 4.5.1 5.5.2s2 .3 3.1.4v21.8c-1.6-.3-3.2-.5-4.9-.7-1.7-.2-3.3-.3-4.9-.3-3.8 0-7.4.8-10.8 2.3-3.4 1.5-6.3 3.8-8.8 6.7-2.5 3-4.5 6.6-6 11s-2.2 9.4-2.2 15.1v48.8h-22.6V137.7zm164 102.6h-22.2V226h-.4c-2.8 5.2-6.9 9.3-12.4 12.4-5.5 3.1-11.1 4.7-16.8 4.7-13.5 0-23.3-3.3-29.3-10s-9-16.8-9-30.3v-65.1H504v62.9c0 9 1.7 15.4 5.2 19.1 3.4 3.7 8.3 5.6 14.5 5.6 4.8 0 8.7-.7 11.9-2.2 3.2-1.5 5.8-3.4 7.7-5.9 2-2.4 3.4-5.4 4.3-8.8.9-3.4 1.3-7.1 1.3-11.1v-59.5h22.6v102.5zm38.5-32.9c.7 6.6 3.2 11.2 7.5 13.9 4.4 2.6 9.6 4 15.7 4 2.1 0 4.5-.2 7.2-.5s5.3-1 7.6-1.9c2.4-.9 4.3-2.3 5.9-4.1 1.5-1.8 2.2-4.1 2.1-7-.1-2.9-1.2-5.3-3.2-7.1-2-1.9-4.5-3.3-7.6-4.5-3.1-1.1-6.6-2.1-10.6-2.9-4-.8-8-1.7-12.1-2.6-4.2-.9-8.3-2.1-12.2-3.4-3.9-1.3-7.4-3.1-10.5-5.4-3.1-2.2-5.6-5.1-7.4-8.6-1.9-3.5-2.8-7.8-2.8-13 0-5.6 1.4-10.2 4.1-14 2.7-3.8 6.2-6.8 10.3-9.1 4.2-2.3 8.8-3.9 13.9-4.9 5.1-.9 10-1.4 14.6-1.4 5.3 0 10.4.6 15.2 1.7 4.8 1.1 9.2 2.9 13.1 5.5 3.9 2.5 7.1 5.8 9.7 9.8 2.6 4 4.2 8.9 4.9 14.6h-23.6c-1.1-5.4-3.5-9.1-7.4-10.9-3.9-1.9-8.4-2.8-13.4-2.8-1.6 0-3.5.1-5.7.4-2.2.3-4.2.8-6.2 1.5-1.9.7-3.5 1.8-4.9 3.2-1.3 1.4-2 3.2-2 5.5 0 2.8 1 5 2.9 6.7 1.9 1.7 4.4 3.1 7.5 4.3 3.1 1.1 6.6 2.1 10.6 2.9 4 .8 8.1 1.7 12.3 2.6 4.1.9 8.1 2.1 12.1 3.4 4 1.3 7.5 3.1 10.6 5.4 3.1 2.3 5.6 5.1 7.5 8.5 1.9 3.4 2.9 7.7 2.9 12.7 0 6.1-1.4 11.2-4.2 15.5-2.8 4.2-6.4 7.7-10.8 10.3-4.4 2.6-9.4 4.6-14.8 5.8-5.4 1.2-10.8 1.8-16.1 1.8-6.5 0-12.5-.7-18-2.2-5.5-1.5-10.3-3.7-14.3-6.6-4-3-7.2-6.7-9.5-11.1-2.3-4.4-3.5-9.7-3.7-15.8H610zm74.6-69.7h17.1v-30.8h22.6v30.8h20.4v16.9h-20.4v54.8c0 2.4.1 4.4.3 6.2.2 1.7.7 3.2 1.4 4.4.7 1.2 1.8 2.1 3.3 2.7 1.5.6 3.4.9 6 .9 1.6 0 3.2 0 4.8-.1 1.6-.1 3.2-.3 4.8-.7v17.5c-2.5.3-5 .5-7.3.8-2.4.3-4.8.4-7.3.4-6 0-10.8-.6-14.4-1.7-3.6-1.1-6.5-2.8-8.5-5-2.1-2.2-3.4-4.9-4.2-8.2-.7-3.3-1.2-7.1-1.3-11.3v-60.5h-17.1v-17.1zm76.1 0h21.4v13.9h.4c3.2-6 7.6-10.2 13.3-12.8 5.7-2.6 11.8-3.9 18.5-3.9 8.1 0 15.1 1.4 21.1 4.3 6 2.8 11 6.7 15 11.7 4 5 6.9 10.8 8.9 17.4 2 6.6 3 13.7 3 21.2 0 6.9-.9 13.6-2.7 20-1.8 6.5-4.5 12.2-8.1 17.2-3.6 5-8.2 8.9-13.8 11.9-5.6 3-12.1 4.5-19.7 4.5-3.3 0-6.6-.3-9.9-.9-3.3-.6-6.5-1.6-9.5-2.9-3-1.3-5.9-3-8.4-5.1-2.6-2.1-4.7-4.5-6.5-7.2h-.4v51.2h-22.6V137.7zm79 51.4c0-4.6-.6-9.1-1.8-13.5-1.2-4.4-3-8.2-5.4-11.6-2.4-3.4-5.4-6.1-8.9-8.1-3.6-2-7.7-3.1-12.3-3.1-9.5 0-16.7 3.3-21.5 9.9-4.8 6.6-7.2 15.4-7.2 26.4 0 5.2.6 10 1.9 14.4 1.3 4.4 3.1 8.2 5.7 11.4 2.5 3.2 5.5 5.7 9 7.5 3.5 1.9 7.6 2.8 12.2 2.8 5.2 0 9.5-1.1 13.1-3.2 3.6-2.1 6.5-4.9 8.8-8.2 2.3-3.4 4-7.2 5-11.5.9-4.3 1.4-8.7 1.4-13.2zm39.9-90.5h22.6V120h-22.6V98.6zm0 39.1h22.6v102.6h-22.6V137.7zm42.8-39.1H945v141.7h-22.6V98.6zm91.9 144.5c-8.2 0-15.5-1.4-21.9-4.1-6.4-2.7-11.8-6.5-16.3-11.2-4.4-4.8-7.8-10.5-10.1-17.1-2.3-6.6-3.5-13.9-3.5-21.8 0-7.8 1.2-15 3.5-21.6 2.3-6.6 5.7-12.3 10.1-17.1 4.4-4.8 9.9-8.5 16.3-11.2 6.4-2.7 13.7-4.1 21.9-4.1s15.5 1.4 21.9 4.1c6.4 2.7 11.8 6.5 16.3 11.2 4.4 4.8 7.8 10.5 10.1 17.1 2.3 6.6 3.5 13.8 3.5 21.6 0 7.9-1.2 15.2-3.5 21.8-2.3 6.6-5.7 12.3-10.1 17.1-4.4 4.8-9.9 8.5-16.3 11.2-6.4 2.7-13.7 4.1-21.9 4.1zm0-17.9c5 0 9.4-1.1 13.1-3.2 3.7-2.1 6.7-4.9 9.1-8.3 2.4-3.4 4.1-7.3 5.3-11.6 1.1-4.3 1.7-8.7 1.7-13.2 0-4.4-.6-8.7-1.7-13.1s-2.9-8.2-5.3-11.6c-2.4-3.4-5.4-6.1-9.1-8.2-3.7-2.1-8.1-3.2-13.1-3.2s-9.4 1.1-13.1 3.2c-3.7 2.1-6.7 4.9-9.1 8.2-2.4 3.4-4.1 7.2-5.3 11.6-1.1 4.4-1.7 8.7-1.7 13.1 0 4.5.6 8.9 1.7 13.2 1.1 4.3 2.9 8.2 5.3 11.6 2.4 3.4 5.4 6.2 9.1 8.3 3.7 2.2 8.1 3.2 13.1 3.2zm58.4-87.5h17.1v-30.8h22.6v30.8h20.4v16.9h-20.4v54.8c0 2.4.1 4.4.3 6.2.2 1.7.7 3.2 1.4 4.4.7 1.2 1.8 2.1 3.3 2.7 1.5.6 3.4.9 6 .9 1.6 0 3.2 0 4.8-.1 1.6-.1 3.2-.3 4.8-.7v17.5c-2.5.3-5 .5-7.3.8-2.4.3-4.8.4-7.3.4-6 0-10.8-.6-14.4-1.7-3.6-1.1-6.5-2.8-8.5-5-2.1-2.2-3.4-4.9-4.2-8.2-.7-3.3-1.2-7.1-1.3-11.3v-60.5h-17.1v-17.1z" fill="' . $ttextfill . '"/><path fill="' . $ticonfill . '" d="M271.3 98.6H167.7L135.7 0l-32.1 98.6L0 98.5l83.9 61L51.8 258l83.9-60.9 83.8 60.9-32-98.5 83.8-60.9z"/><path fill="' . $ticon2fill . '" d="M194.7 181.8l-7.2-22.3-51.8 37.6z"/></svg>';
        $google = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 168" style="' . $svgStyle . '" preserveAspectRatio="xMidYMid"><g>' . "\n" . '                <path d="M496.052455,102.672055 L510.255737,112.140909 C505.6459,118.931075 494.619668,130.580258 475.557368,130.580258 C451.885231,130.580258 434.255719,112.2655 434.255719,88.967133 C434.255719,64.1736841 452.072116,47.3540078 473.563925,47.3540078 C495.180323,47.3540078 505.77049,64.5474546 509.19672,73.8294242 L511.065574,78.5638516 L455.373756,101.613038 C459.609823,109.960581 466.213103,114.196648 475.557368,114.196648 C484.901633,114.196648 491.380323,109.586811 496.052455,102.672055 L496.052455,102.672055 Z M452.383592,87.6589359 L489.573765,72.2097517 C487.518026,67.0392586 481.413107,63.3638478 474.124581,63.3638478 C464.842612,63.3638478 451.947526,71.5868007 452.383592,87.6589359 L452.383592,87.6589359 Z" fill="#FF302F"/>' . "\n" . '                <path d="M407.406531,4.93104632 L425.347519,4.93104632 L425.347519,126.780257 L407.406531,126.780257 L407.406531,4.93104632 L407.406531,4.93104632 Z" fill="#20B15A"/>' . "\n" . '                <path d="M379.124557,50.5933528 L396.442594,50.5933528 L396.442594,124.599929 C396.442594,155.311412 378.314721,167.957316 356.885207,167.957316 C336.701596,167.957316 324.554051,154.376986 320.00651,143.350753 L335.891759,136.747473 C338.757334,143.537639 345.67209,151.573706 356.885207,151.573706 C370.652424,151.573706 379.124557,143.039278 379.124557,127.091732 L379.124557,121.111404 L378.501606,121.111404 C374.39013,126.095011 366.540947,130.580258 356.573731,130.580258 C335.767169,130.580258 316.704869,112.452385 316.704869,89.0917231 C316.704869,65.6064713 335.767169,47.2917126 356.573731,47.2917126 C366.478652,47.2917126 374.39013,51.7146646 378.501606,56.5736822 L379.124557,56.5736822 L379.124557,50.5933528 L379.124557,50.5933528 Z M380.370459,89.0917231 C380.370459,74.3900801 370.590128,63.6753233 358.131109,63.6753233 C345.547499,63.6753233 334.957333,74.3900801 334.957333,89.0917231 C334.957333,103.606481 345.547499,114.134352 358.131109,114.134352 C370.590128,114.196648 380.370459,103.606481 380.370459,89.0917231 L380.370459,89.0917231 Z" fill="#3686F7"/>' . "\n" . '                <path d="M218.21632,88.7802476 C218.21632,112.763861 199.527791,130.393373 176.603195,130.393373 C153.678599,130.393373 134.990069,112.701565 134.990069,88.7802476 C134.990069,64.6720448 153.678599,47.1048274 176.603195,47.1048274 C199.527791,47.1048274 218.21632,64.6720448 218.21632,88.7802476 L218.21632,88.7802476 Z M200.026151,88.7802476 C200.026151,73.8294242 189.186804,63.5507331 176.603195,63.5507331 C164.019585,63.5507331 153.180238,73.8294242 153.180238,88.7802476 C153.180238,103.606481 164.019585,114.009763 176.603195,114.009763 C189.186804,114.009763 200.026151,103.606481 200.026151,88.7802476 L200.026151,88.7802476 Z" fill="#FF302F"/>' . "\n" . '                <path d="M309.104867,88.967133 C309.104867,112.950746 290.416338,130.580258 267.491742,130.580258 C244.567146,130.580258 225.878617,112.950746 225.878617,88.967133 C225.878617,64.8589302 244.567146,47.3540078 267.491742,47.3540078 C290.416338,47.3540078 309.104867,64.796635 309.104867,88.967133 L309.104867,88.967133 Z M290.852404,88.967133 C290.852404,74.0163095 280.013057,63.7376184 267.429447,63.7376184 C254.845837,63.7376184 244.00649,74.0163095 244.00649,88.967133 C244.00649,103.793366 254.845837,114.196648 267.429447,114.196648 C280.075352,114.196648 290.852404,103.731071 290.852404,88.967133 L290.852404,88.967133 Z" fill="#FFBA40"/>' . "\n" . '                <path d="M66.5900525,112.327794 C40.4884066,112.327794 20.0556146,91.2720515 20.0556146,65.1704056 C20.0556146,39.0687598 40.4884066,18.0130168 66.5900525,18.0130168 C80.6687446,18.0130168 90.9474357,23.5572805 98.5474373,30.6589216 L111.068752,18.137607 C100.478585,7.98350613 86.3375984,0.258913997 66.5900525,0.258913997 C30.8326666,0.258913997 0.744134408,29.4130196 0.744134408,65.1704056 C0.744134408,100.927792 30.8326666,130.081897 66.5900525,130.081897 C85.9015328,130.081897 100.478585,123.727797 111.878588,111.891729 C123.590067,100.180251 127.203183,83.7343447 127.203183,70.4031939 C127.203183,66.2294223 126.704822,61.9310606 126.144166,58.7540106 L66.5900525,58.7540106 L66.5900525,76.0720477 L109.013014,76.0720477 C107.767112,86.9113947 104.340882,94.3245113 99.2949785,99.3704142 C93.1900592,105.537629 83.534319,112.327794 66.5900525,112.327794 L66.5900525,112.327794 L66.5900525,112.327794 Z" fill="#3686F7"/>' . "\n" . '            </g>' . "\n" . '        </svg>';
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-review-badge ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';

        if ($widget_style == 'micro_button') {
            $output .= '<div class="fon-review-badge-micro-button position-relative d-flex align-items-center">';
            $output .= '<div class="fon-review-badge-logo py-2 px-3 rounded-start-3 d-flex align-items-center justify-content-center border flex-shrink-0" style="background-color:' . ($review_provider == 'trustpilot' ? $color : 'var(--bs-theme-light)') . '; border-color:' . ($review_provider == 'trustpilot' ? $color : 'var(--bs-theme-light-100)') . '; height:40px;min-width:135px;">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</div>';
            $output .= '<div class="fon-review-badge-review py-2 px-3 rounded-end d-flex align-items-center bg-white border-end border-top border-bottom" style="height:40px;">';

            if ($value_display == 'score') {
                $output .= '<span class="fon-review-badge-score fs-6 text-dark strong">' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</span>';
            }
            else if ($value_display == 'count') {
                $output .= '<span class="fon-review-badge-score fs-6 text-dark strong">' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }
            else if ($value_display == 'both') {
                $output .= '<span class="fon-review-badge-score fs-6 text-dark"><strong>' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</strong> | ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }

            $output .= '</div>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }
        else if ($widget_style == 'micro_horizontal') {
            $output .= '<div class="fon-review-badge-micro-horizontal position-relative d-flex align-items-' . ($review_provider == 'trustpilot' ? 'end' : 'center') . ' gap-3">';
            $output .= '<span class="fon-review-badge-logo">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</span>';
            $output .= '<strong class="fon-review-badge-title text-dark">';
            $output .= $review_title;
            $output .= '</strong>';
            $output .= '<span class="fon-review-badge-review">';

            if ($value_display == 'score') {
                $output .= '<span class="fon-review-badge-score">' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</span>';
            }
            else if ($value_display == 'count') {
                $output .= '<span class="fon-review-badge-score">' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }
            else if ($value_display == 'both') {
                $output .= '<span class="fon-review-badge-score">' . sprintf($this->language['review_badge']['score_short'], $review_score) . ' | ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }

            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars position-relative">';
            $output .= '<span class="fon-review-badge-stars-empty d-flex gap-1">';
            $output .= str_repeat('<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white" style="width:' . ($starSize + 8) . 'px;height:' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>', 5);
            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars-fill d-flex gap-1 position-absolute start-0 top-0">' . $stars . '</span>';
            $output .= '</span>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }
        else if ($widget_style == 'mini_box') {
            $output .= '<div class="fon-review-badge-mini-box d-flex flex-column align-items-center justify-content-center position-relative">';
            $output .= '<div class="fon-review-badge-logo mb-3">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</div>';
            $output .= '<span class="fon-review-badge-stars position-relative mb-2">';
            $output .= '<span class="fon-review-badge-stars-empty d-flex gap-1">';
            $output .= str_repeat('<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white"  style="width:' . ($starSize + 8) . 'px;height:' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>', 5);
            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars-fill d-flex gap-1 position-absolute start-0 top-0">' . $stars . '</span>';
            $output .= '</span>';
            $output .= '<div class="fon-review-badge-review fs-18 fw-semibold text-dark">';

            if ($value_display == 'score') {
                $output .= '<span class="fon-review-badge-score">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</span>';
            }
            else if ($value_display == 'count') {
                $output .= '<span class="fon-review-badge-score">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }
            else if ($value_display == 'both') {
                $output .= '<span class="fon-review-badge-score">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['score_short'], $review_score) . ' | ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</span>';
            }

            $output .= '</div>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }
        else if ($widget_style == 'flex_box') {
            $output .= '<div class="fon-review-badge-flex-box d-flex flex-column align-items-stretch justify-content-between position-relative bg-dark rounded-4 p-4 bg-theme-light-800 overflow-hidden" style="min-height:250px;max-width: 450px;">';
            $output .= '<div class="fon-review-badge-header d-flex align-items-center justify-content-between position-relative">';
            $output .= '<h5 class="fon-review-badge-score flex-shrink-1 w-50 text-white fw-light">' . sprintf($this->language['review_badge']['score_long'], $review_score) . '</h5>';
            $output .= '<span class="fon-review-badge-icon text-white me-4 mt-4"><i class="fa-solid fa-laptop fa-3x"></i></span>';
            $output .= '</div>';
            $output .= '<div class="flex-grow-1"></div>';
            $output .= '<div class="fon-review-badge-footer d-flex align-items-end justify-content-between position-relative">';
            $output .= '<div class="fon-review-badge-review d-flex flex-column align-items-start justify-content-start">';
            $output .= '<h6 class="fon-review-badge-score text-white fw-normal mb-0">' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</h6>';
            $output .= '<div class="fon-review-badge-stars position-relative my-2">';
            $output .= '<span class="fon-review-badge-stars-empty d-flex gap-1">';
            $output .= str_repeat('<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white"  style="width:' . ($starSize + 8) . 'px;height:' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>', 5);
            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars-fill d-flex gap-1 position-absolute start-0 top-0">' . $stars . '</span>';
            $output .= '</div>';
            $output .= '<div class="fon-review-badge-title text-white">';
            $output .= $review_title;
            $output .= '</div>';
            $output .= '</div>';
            $output .= '<div class="fon-review-badge-logo position-absolute end-0 bottom-0">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</div>';
            $output .= '</div>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }
        else if ($widget_style == 'flex_mini') {
            $output .= '<div class="fon-review-badge-flex-mini d-flex align-items-center justify-content-start position-relative bg-theme-light-800 rounded-4 p-3 overflow-hidden" style="min-height:50px;">';
            $output .= '<div class="fon-review-badge-icon text-white me-5 position-relative"><i class="fa-solid fa-laptop fa-2x"></i></div>';
            $output .= '<div class="fon-review-badge-review d-flex flex-column align-items-start justify-content-start position-relative">';

            if ($value_display == 'score') {
                $output .= '<h6 class="fon-review-badge-score fs-14 mb-1 text-white">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['score_short'], $review_score) . '</h6>';
            }
            else if ($value_display == 'count') {
                $output .= '<h6 class="fon-review-badge-score fs-14 mb-1 text-white">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</h6>';
            }
            else if ($value_display == 'both') {
                $output .= '<h6 class="fon-review-badge-score fs-14 mb-1 text-white">' . $this->language['review_badge']['score'] . ' ' . sprintf($this->language['review_badge']['score_short'], $review_score) . ' | ' . sprintf($this->language['review_badge']['review_count'], $review_count) . '</h6>';
            }

            $output .= '<div class="fon-review-badge-stars position-relative">';
            $output .= '<span class="fon-review-badge-stars-empty d-flex gap-1">';
            $output .= str_repeat('<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white"  style="width:' . ($starSize + 8) . 'px;height:' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>', 5);
            $output .= '</span>';
            $output .= '<span class="fon-review-badge-stars-fill d-flex gap-1 position-absolute start-0 top-0">' . $stars . '</span>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '<div class="fon-review-badge-logo ms-auto position-relative">';

            if ($review_provider == 'google') {
                $output .= $google;
            }
            else if ($review_provider == 'trustpilot') {
                $output .= $trustpilot;
            }

            $output .= '</div>';
            $output .= '<a href="' . $review_link . '" class="fon-review-badge-link stretched-link" target="_blank" ' . $review_link_rel . ' aria-label="' . $review_provider . '"></a>';
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function server_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetProducts($content, $moduleId, $pageData, $row, 'server');
    }

    private function sidebar_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        if ($pageData['sidebar'] && 0 < count($pageData['sidebar'])) {
            $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-sidebar-widget sidebar-' . $content->widget_style . ' ' . $content->fon_class . '">';
            $output .= '<div class="list-group ' . ($content->widget_style == 'horizontal' ? 'list-group-horizontal-md align-items-center justify-content-' . $content->align : '') . '">';

            foreach ($pageData['sidebar'] as $sidebar) {
                $output .= '<a href="' . $sidebar['link'] . '" class="list-group-item list-group-item-action">' . $sidebar['title'] . '</a>';
            }

            $output .= '</div>';
            $output .= '</div>';
        }

        return $output;
    }

    private function slideshow_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $autoplay = (isset($content->autoplay) && $content->autoplay == 'yes' ? 1 : 0);
        $pause_on_hover = (isset($content->pause) && $content->pause == 'yes' ? 1 : 0);
        $interval = (isset($content->interval) && $content->interval ? $content->interval : 5);
        $speed = (isset($content->speed) && $content->speed ? $content->speed : '800');
        $content_container_option = (isset($content->content_width) && $content->content_width ? $content->content_width : '');
        $slider_animation = (isset($content->animation_style) && $content->animation_style ? $content->animation_style : '');
        $content_vertical_center = (isset($content->content_vertical_center) && $content->content_vertical_center = 'yes' ? 1 : 0);
        $height = (isset($content->height) && $content->height ? $content->height : '');
        $custom_height = (isset($content->custom_height) && $content->custom_height ? $content->custom_height : (object) ['xl' => '750', 'lg' => '700', 'md' => '600', 'sm' => '500', 'xs' => '450']);
        $dot_controllers = (isset($content->dot_controllers) && $content->dot_controllers == 'yes' ? 1 : 0);
        $dot_position = (isset($content->dot_controllers_position) && $content->dot_controllers_position ? 'dot-' . $content->dot_controllers_position : 'dot-bottom_center');
        $arrow_controllers = (isset($content->arrow_controllers) && $content->arrow_controllers = 'yes' ? 1 : 0);
        $arrow_position = (isset($content->arrow_controllers_position) && $content->arrow_controllers_position ? 'arrow-' . $content->arrow_controllers_position : 'arrow-center');
        $arrow_on_hover = (isset($content->arrow_controllers_hover) && $content->arrow_controllers_hover = 'yes' ? 1 : 0);
        $arrow_class = $arrow_position;

        if ($arrow_on_hover) {
            $arrow_class .= ' arrow-show-on-hover';
        }

        $this->addAsset(['slick', 'slick-animate']);
        $style = '';
        $style .= '#' . $widgetId . '.fon-slider .fon-item:not(:first-child) { display: none; }';
        $style .= '#' . $widgetId . '.fon-slider.slick-initialized .fon-item { display: flex; }';

        if ($height == 'full') {
            $style .= '#' . $widgetId . '.fon-slider,#' . $widgetId . '.fon-slider .fon-item{';
            $style .= 'height: 100vh;';
            $style .= '}';
        }
        else {
            $responsiveItems = [
                '#' . $widgetId . ' .fon-item' => [
                ['type' => 'height', 'unit' => 'px!important', 'value' => $custom_height]
            ],
                '#' . $widgetId . '.fon-slider' => [
                ['type' => 'height', 'unit' => 'px!important', 'value' => $custom_height]
            ]
            ];
            $style .= self::parseResponsiveItems($responsiveItems);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-slideshow-widget fon-slider ' . $content->fon_class . ' ' . $dot_position . ' ' . $arrow_class . '"' . "\n\t\t" . '    data-id="fon-widget-slideshow-' . $moduleId . '"' . "\n\t\t" . '    data-effect="' . $slider_animation . '"' . "\n\t\t" . '    data-autoplay="' . ($autoplay ? 'true' : 'false') . '"' . "\n\t\t" . '    data-autoplay-speed="' . ($interval ? $interval * 1000 : '4000') . '"' . "\n\t\t" . '    data-speed="' . $speed . '"' . "\n\t\t" . '    data-dots="' . ($dot_controllers ? 'true' : 'false') . '"' . "\n\t\t" . '    data-arrows="' . ($arrow_controllers ? 'true' : 'false') . '"' . "\n\t\t" . '    data-pause="' . ($pause_on_hover && $autoplay ? 'true' : 'false') . '" style="overflow:hidden; ' . ($height != 'full' ? 'height:' . $custom_height->xl . 'px;' : '') . '">';
        if (isset($content->items) && is_array($content->items)) {
            foreach ($content->items as $item_key => $item_value) {
                $isFirstSlide = $item_key === 0;
                $uniqid = 'fon-slider-item-' . $moduleId . '-num-' . $item_key . '-key';
                $content_class = (isset($item_value->slide_class) && $item_value->slide_class ? ' ' . $item_value->slide_class : '');
                $patternStyle = $this->handlePatternImages($content_class, $pageData['page'], $pageData['tadress'], $isFirstSlide && $isLCPCandidate);
                $image_in_column = (isset($item_value->use_slide_image) && $item_value->use_slide_image == 'yes' ? 1 : 0);
                $image_column_width = (isset($item_value->slide_image_column) && $item_value->slide_image_column ? $item_value->slide_image_column : (object) []);
                $image_column_width_xl = (isset($image_column_width->xl) && $image_column_width->xl ? (int) $image_column_width->xl : 6);
                $image_column_width_lg = (isset($image_column_width->lg) && $image_column_width->lg ? (int) $image_column_width->lg : 6);
                $image_column_width_md = (isset($image_column_width->md) && $image_column_width->md ? (int) $image_column_width->md : 6);
                $image_column_width_sm = (isset($image_column_width->sm) && $image_column_width->sm ? (int) $image_column_width->sm : 6);
                $image_column_width_xs = (isset($image_column_width->xs) && $image_column_width->xs ? (int) $image_column_width->xs : 6);
                $slide_image_order = (isset($item_value->slide_image_order) && $item_value->slide_image_order ? $item_value->slide_image_order : (object) []);
                $slide_image_order_xl = (isset($slide_image_order->xl) && $slide_image_order->xl ? (int) $slide_image_order->xl : 2);
                $slide_image_order_lg = (isset($slide_image_order->lg) && $slide_image_order->lg ? (int) $slide_image_order->lg : 2);
                $slide_image_order_md = (isset($slide_image_order->md) && $slide_image_order->md ? (int) $slide_image_order->md : 2);
                $slide_image_order_sm = (isset($slide_image_order->sm) && $slide_image_order->sm ? (int) $slide_image_order->sm : 2);
                $slide_image_order_xs = (isset($slide_image_order->xs) && $slide_image_order->xs ? (int) $slide_image_order->xs : 2);
                $slide_content_order_xl = ($slide_image_order_xl == 2 ? 1 : 2);
                $slide_content_order_lg = ($slide_image_order_lg == 2 ? 1 : 2);
                $slide_content_order_md = ($slide_image_order_md == 2 ? 1 : 2);
                $slide_content_order_sm = ($slide_image_order_sm == 2 ? 1 : 2);
                $slide_content_order_xs = ($slide_image_order_xs == 2 ? 1 : 2);
                $slide_image_text_align = '';
                $slide_image_text_align .= ($slide_image_order_xl == 2 ? ' text-xl-end' : ' text-xl-start');
                $slide_image_text_align .= ($slide_image_order_lg == 2 ? ' text-lg-end' : ' text-lg-start');
                $slide_image_text_align .= ($slide_image_order_md == 2 ? ' text-md-end' : ' text-md-start');
                $slide_image_text_align .= ($slide_image_order_sm == 2 ? ' text-sm-end' : ' text-sm-start');
                $slide_image_text_align .= ($slide_image_order_xs == 2 ? ' text-end' : ' text-start');
                $aligns = (isset($item_value->slide_content_align) && $item_value->slide_content_align ? $item_value->slide_content_align : '');
                $alignClass = '';

                if ($aligns) {
                    foreach ($aligns as $ak => $av) {
                        if ($av) {
                            $alignClass .= ($ak == 'xs' ? 'text-' : 'text-' . $ak . '-');

                            if ($av == 'left') {
                                $alignClass .= 'start ';
                            }
                            else if ($av == 'right') {
                                $alignClass .= 'end ';
                            }
                            else {
                                $alignClass .= 'center ';
                            }
                        }
                    }
                }
                $slide_bg_color = (isset($item_value->slide_bg_color) && $item_value->slide_bg_color ? $item_value->slide_bg_color : '');
                $slide_bg_type = (isset($item_value->slide_bg_type) && $item_value->slide_bg_type ? $item_value->slide_bg_type : '');
                $slide_bg_image = '';

                if (is_object($item_value->slide_bg_image)) {
                    $slide_bg_image = (isset($item_value->slide_bg_image->{$this->lang}) && $item_value->slide_bg_image->{$this->lang} ? $item_value->slide_bg_image->{$this->lang} : array_values((array) $item_value->slide_bg_image)[0] ?? '');
                }
                else if (is_string($item_value->slide_bg_image)) {
                    $slide_bg_image = $item_value->slide_bg_image;
                }

                $slide_bg_color_code = '';
                $hasColor = $slide_bg_color && $slide_bg_type != 'none';
                if ($hasColor || $patternStyle) {
                    $slide_bg_color_code = 'style="';

                    if ($hasColor) {
                        $slide_bg_color_code .= 'background-color: ' . $slide_bg_color . '; ';
                    }

                    if ($patternStyle) {
                        $slide_bg_color_code .= $patternStyle;
                    }

                    $slide_bg_color_code .= '"';
                }
                $title = (isset($item_value->slide_title->{$this->lang}) && $item_value->slide_title->{$this->lang} ? $item_value->slide_title->{$this->lang} : array_values((array) $item_value->slide_title)[0] ?? '');
                $title = self::getPriceHolders($title);
                $title_heading_selector = (isset($item_value->slide_title_heading) && $item_value->slide_title_heading ? $item_value->slide_title_heading : 'h3');
                $title_font = (isset($item_value->slide_title_font) && $item_value->slide_title_font ? self::parseFontProperties($item_value->slide_title_font, false) : '');
                $title_color = (isset($item_value->slide_title_color) && $item_value->slide_title_color ? $item_value->slide_title_color : '');
                $title_animation = (isset($item_value->slide_title_animation) && $item_value->slide_title_animation ? $item_value->slide_title_animation : 'none');
                $subtitle = (isset($item_value->slide_subtitle->{$this->lang}) && $item_value->slide_subtitle->{$this->lang} ? $item_value->slide_subtitle->{$this->lang} : array_values((array) $item_value->slide_subtitle)[0] ?? '');
                $subtitle = self::getPriceHolders($subtitle);
                $subtitle_heading_selector = (isset($item_value->slide_subtitle_heading) && $item_value->slide_subtitle_heading ? $item_value->slide_subtitle_heading : 'h2');
                $subtitle_font = (isset($item_value->slide_subtitle_font) && $item_value->slide_subtitle_font ? self::parseFontProperties($item_value->slide_subtitle_font, false) : '');
                $subtitle_color = (isset($item_value->slide_subtitle_color) && $item_value->slide_subtitle_color ? $item_value->slide_subtitle_color : '');
                $subtitle_animation = (isset($item_value->slide_subtitle_animation) && $item_value->slide_subtitle_animation ? $item_value->slide_subtitle_animation : 'none');
                $content_text = (isset($item_value->slide_description->{$this->lang}) && $item_value->slide_description->{$this->lang} ? $item_value->slide_description->{$this->lang} : array_values((array) $item_value->slide_description)[0] ?? '');
                $content_text = self::getPriceHolders($content_text);
                $content_color = (isset($item_value->slide_description_color) && $item_value->slide_description_color ? $item_value->slide_description_color : '');
                $content_animation = (isset($item_value->slide_description_animation) && $item_value->slide_description_animation ? $item_value->slide_description_animation : 'none');
                $use_slide_features = (isset($item_value->use_slide_features) && $item_value->use_slide_features == 'yes' ? true : false);
                $slide_features = (isset($item_value->slide_features) && $item_value->slide_features ? $item_value->slide_features : []);
                $slide_features_type = (isset($item_value->slide_features_type) && $item_value->slide_features_type ? $item_value->slide_features_type : 'list');
                $slide_features_icon_color = (isset($item_value->slide_features_icon_color) && $item_value->slide_features_icon_color ? $item_value->slide_features_icon_color : '');
                $slide_features_title_color = (isset($item_value->slide_features_title_color) && $item_value->slide_features_title_color ? $item_value->slide_features_title_color : '');
                $slide_features_desc_color = (isset($item_value->slide_features_desc_color) && $item_value->slide_features_desc_color ? $item_value->slide_features_desc_color : '');
                $slide_features_animation = (isset($item_value->slide_features_animation) && $item_value->slide_features_animation ? $item_value->slide_features_animation : 'none');
                $output .= '<div class="' . $uniqid . ' fon-item ' . $content_class . ' ' . ($item_key == 0 ? ' active d-flex' : '') . ' ' . ($content_vertical_center ? 'slider-content-vertically-center' : '') . ' ' . ($image_in_column ? 'image-in-column' : '') . '" ' . $slide_bg_color_code . '>';

                if ($slide_bg_type == 'video') {
                    $videoType = '';
                    $videoSrc = '';
                    $slider_video = (isset($item_value->slider_video) && $item_value->slider_video ? $item_value->slider_video : '');
                    if (strpos($slider_video, 'http://') === false || strpos($slider_video, 'https://') === false) {
                        $slider_video = static::assetLinkDetermine($slider_video);
                    }
                    if ($slider_video && strpos($slider_video, 'http://') !== false || strpos($slider_video, 'https://') !== false && isset($item_value->use_youtube_vimeo) && $item_value->use_youtube_vimeo == 'no') {
                        $videoType = 'video';
                        $videoSrc = $slider_video;
                    }
                    else if (isset($item_value->youtube_vimeo_url) && $item_value->youtube_vimeo_url && $item_value->use_youtube_vimeo == 'yes' && strpos($item_value->youtube_vimeo_url, 'http://') !== false || strpos($item_value->youtube_vimeo_url, 'https://') !== false) {
                        $video = parse_url($item_value->youtube_vimeo_url);
                        if (strpos($video['host'], 'youtube.com') !== false || strpos($video['host'], 'youtu.be') !== false) {
                            $videoType = 'youtube';
                            $videoId = '';

                            switch ($video['host']) {
                            case 'www.youtu.be':
                            case 'youtu.be':
                                $videoId = trim($video['path'], '/');
                                break;
                            case 'www.youtube.com':
                            case 'youtube.com':
                                parse_str($video['query'], $query);
                                $videoId = $query['v'];
                                break;
                            }

                            $videoSrc = '//www.youtube-nocookie.com/embed/' . $videoId . '?enablejsapi=1&controls=0&fs=0&iv_load_policy=3&rel=0&showinfo=0&loop=1&playlist=' . $videoId . '&start=1';
                        }
                        else {
                            if (strpos($video['host'], 'vimeo.com') !== false) {
                                $videoType = 'vimeo';
                                $videoId = trim($video['path'], '/');
                                $videoSrc = '//player.vimeo.com/video/' . $videoId . '?api=1&byline=0&portrait=0&title=0&background=1&mute=1&loop=1&autoplay=0&id=' . $videoId;
                            }
                            else {
                                $videoType = 'unknown';
                                $videoSrc = $item_value->youtube_vimeo_url;
                            }
                        }
                    }
                }
                if ($slide_bg_image && $slide_bg_type == 'image') {
                    $slide_bg_image = static::assetLinkDetermine($slide_bg_image);
                    $isBgLcp = false;
                    if ($isFirstSlide && $isLCPCandidate && self::$lcpHandled === false) {
                        $this->addPreloadLink($slide_bg_image, $pageData['page']);
                        self::$lcpHandled = true;
                        $isBgLcp = true;
                    }

                    $output .= '<div class="fon-background image">';
                    $bg_attrs = 'src="' . $slide_bg_image . '" class="d-block w-100 h-100" style="object-fit: cover; position: absolute; top:0; left:0; z-index:0;" alt="' . $title . '"';

                    if ($isBgLcp) {
                        $bg_attrs .= ' fetchpriority="high" loading="eager" decoding="sync"';
                    }
                    else {
                        $bg_attrs .= ' loading="lazy" decoding="async"';
                    }

                    $output .= '<img ' . $bg_attrs . '>';
                    $output .= '</div>';
                }

                if ($slide_bg_type == 'video') {
                    if ($videoType == 'video') {
                        $output .= '<div class="fon-background video">';
                        $output .= '<video class="slide-video " autoplay muted loop playsinline preload="metadata">';
                        $output .= '<source src="' . $videoSrc . '" type="video/mp4" />';
                        $output .= '</video>';
                        $output .= '</div>';
                    }
                    else {
                        $output .= '<div class="fon-background ' . $videoType . '">';
                        $output .= '<iframe class="embed-player " width="980" height="520" src="' . $videoSrc . '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
                        $output .= '</div>';
                    }
                }

                if ($content_container_option === 'bootstrap') {
                    $output .= '<div class="container">';

                    if (!$image_in_column) {
                        $columnClass = 'col-12';

                        if ($aligns) {
                            foreach ($aligns as $ak => $av) {
                                if (!in_array($ak, ['xs' => true, 'sm' => true])) {
                                    $columnClass .= (($av == 'left') || $av == 'right' ? ' col-' . $ak . '-' . ($ak == 'md' ? '7' : '6') : '');
                                }
                            }
                        }

                        $output .= '<div class="row">';
                        $output .= '<div class="' . $columnClass . '">';
                    }
                }
                else {
                    $output .= '<div class="fon-slider-content-wrap">';
                }

                $inner_uniqid = 'fon-slider-inner-item-' . $moduleId . '-num-' . $item_key;

                if ($image_in_column) {
                    $output .= '<div class="row align-items-center">';
                    $output .= '<div class="col-' . ($image_column_width_xs === 12 ? 12 : 12 - $image_column_width_xs) . ' col-sm-' . ($image_column_width_sm === 12 ? 12 : 12 - $image_column_width_sm) . ' col-md-' . ($image_column_width_md === 12 ? 12 : 12 - $image_column_width_md) . ' col-lg-' . ($image_column_width_lg === 12 ? 12 : 12 - $image_column_width_lg) . ' col-xl-' . ($image_column_width_xl === 12 ? 12 : 12 - $image_column_width_xl) . ' order-' . $slide_content_order_xs . ' order-sm-' . $slide_content_order_sm . ' order-md-' . $slide_content_order_md . ' order-lg-' . $slide_content_order_lg . ' order-xl-' . $slide_content_order_xl . '">';
                }

                $output .= '<div class="fon-slider-content-align ' . $alignClass . '">';
                $primarySlideButton = '';

                if (is_object($item_value->slide_link)) {
                    $primarySlideButton = (isset($item_value->slide_link->{$this->lang}) && $item_value->slide_link->{$this->lang} ? $item_value->slide_link->{$this->lang} : array_values((array) $item_value->slide_link)[0] ?? '');
                }
                else if (is_string($item_value->slide_link)) {
                    $primarySlideButton = $item_value->slide_link;
                }

                if ($primarySlideButton) {
                    $button = ['button_text' => $item_value->button_text ?? '', 'button_link' => $item_value->slide_link ?? '', 'button_rel' => $item_value->button_rel ?? [], 'button_target' => $item_value->slide_link_target ?? '', 'button_type' => $item_value->button_type ?? 'default', 'button_style' => $item_value->button_style ?? 'default', 'button_custom_style' => $item_value->button_custom_style ?? 'default', 'button_shape' => $item_value->button_shape ?? '', 'button_size' => $item_value->button_size ?? '', 'button_padding' => $item_value->button_padding ?? '', 'button_color_normal' => $item_value->button_color_normal ?? '', 'button_color_hover' => $item_value->button_color_hover ?? '', 'button_background_normal' => $item_value->button_background_normal ?? '', 'button_background_hover' => $item_value->button_background_hover ?? '', 'button_gradient_normal' => $item_value->button_gradient_normal ?? '', 'button_gradient_hover' => $item_value->button_gradient_hover ?? '', 'show_button_icon' => $item_value->show_button_icon ?? 'no', 'button_icon' => $item_value->button_icon ?? '', 'button_icon_position' => $item_value->button_icon_position ?? '', 'scroll_button' => $item_value->scroll_button ?? 'no', 'block_button' => 'no'];
                    $button_animation = (isset($item_value->button_animation) && $item_value->button_animation ? $item_value->button_animation : 'none');
                }
                $showSecondaryButton = (isset($item_value->show_secondary_button) && $item_value->show_secondary_button == 'yes' ? true : false);

                if ($showSecondaryButton) {
                    $secondaryButton = ['button_text' => $item_value->secondary_button_text ?? '', 'button_link' => $item_value->secondary_slide_link ?? '', 'button_rel' => $item_value->secondary_button_rel ?? [], 'button_target' => $item_value->secondary_slide_link_target ?? '', 'button_type' => $item_value->secondary_button_type ?? 'default', 'button_style' => $item_value->secondary_button_style ?? 'default', 'button_custom_style' => $item_value->secondary_button_custom_style ?? 'default', 'button_shape' => $item_value->secondary_button_shape ?? '', 'button_size' => $item_value->secondary_button_size ?? '', 'button_padding' => $item_value->secondary_button_padding ?? '', 'button_color_normal' => $item_value->secondary_button_color_normal ?? '', 'button_color_hover' => $item_value->secondary_button_color_hover ?? '', 'button_background_normal' => $item_value->secondary_button_background_normal ?? '', 'button_background_hover' => $item_value->secondary_button_background_hover ?? '', 'button_gradient_normal' => $item_value->secondary_button_gradient_normal ?? '', 'button_gradient_hover' => $item_value->secondary_button_gradient_hover ?? '', 'show_button_icon' => $item_value->secondary_show_button_icon ?? 'no', 'button_icon' => $item_value->secondary_button_icon ?? '', 'button_icon_position' => $item_value->secondary_button_icon_position ?? '', 'scroll_button' => $item_value->secondary_scroll_button ?? 'no', 'block_button' => 'no'];
                    $secondary_button_animation = (isset($item_value->secondary_button_animation) && $item_value->secondary_button_animation ? $item_value->secondary_button_animation : 'none');
                }

                $output .= '<' . $title_heading_selector . ' class="fon-slider-title ' . ($title_animation != 'none' ? 'animated' : '') . ' ' . $inner_uniqid . '-title" ' . ($title_animation != 'none' ? 'data-animation-in="' . $title_animation . '" data-delay-in="0"' : '') . '>';
                $output .= $title;
                $output .= '</' . $title_heading_selector . '>';
                $output .= '<' . $subtitle_heading_selector . ' class="fon-slider-title fon-slider-subtitle ' . ($subtitle_animation != 'none' ? 'animated' : '') . ' ' . $inner_uniqid . '-subtitle" ' . ($subtitle_animation != 'none' ? 'data-animation-in="' . $subtitle_animation . '"  data-delay-in="0.1"' : '') . '>';
                $output .= $subtitle;
                $output .= '</' . $subtitle_heading_selector . '>';
                $output .= '<div class="fon-slider-text ' . $inner_uniqid . '-description ' . ($content_animation != 'none' ? 'animated' : '') . '" ' . ($content_animation != 'none' ? 'data-animation-in="' . $content_animation . '"  data-delay-in="0.2"' : '') . '>';
                $output .= $content_text;
                $output .= '</div>';
                if ($slide_features && $use_slide_features) {
                    $output .= '<div id="' . $inner_uniqid . '-features" class="fon-slider-features ' . ($slide_features_animation != 'none' ? 'animated' : '') . ' d-none d-md-block" ' . ($slide_features_animation != 'none' ? 'data-animation-in="' . $slide_features_animation . '" data-delay-in="0.3"' : '') . '>';
                    $output .= '<ul class="list-unstyled ' . ($slide_features_type == 'column' ? 'row align-items-start' : '') . '">';

                    foreach ($slide_features as $sfkey => $slide_feature) {
                        $slide_feature_icon = (isset($slide_feature->icon) && $slide_feature->icon ? $slide_feature->icon : '');
                        $slide_feature_title = (isset($slide_feature->title->{$this->lang}) && $slide_feature->title->{$this->lang} ? $slide_feature->title->{$this->lang} : array_values((array) $slide_feature->title)[0] ?? '');
                        $slide_feature_desc = (isset($slide_feature->desc->{$this->lang}) && $slide_feature->desc->{$this->lang} ? $slide_feature->desc->{$this->lang} : array_values((array) $slide_feature->desc)[0] ?? '');
                        $output .= '<li class="' . ($slide_features_type == 'column' ? 'col-md-6' : '') . '">';
                        $output .= '<div class="fon-slider-feature">';

                        if ($slide_feature_icon) {
                            $output .= '<div class="fon-slider-feature-icon" style="' . ($slide_features_icon_color ? 'color:' . $slide_features_icon_color : '') . '"><i class="' . $slide_feature_icon . ' fa-fw"></i></div>';
                        }

                        $output .= '<div class="fon-slider-feature-text">';

                        if ($slide_feature_title) {
                            $output .= '<h4 class="fon-slider-feature-title fw-semibold mb-1" style="' . ($slide_features_title_color ? 'color:' . $slide_features_title_color : '') . '">' . $slide_feature_title . '</h4>';
                        }

                        if ($slide_feature_desc) {
                            $output .= '<p class="fon-slider-feature-desc" style="' . ($slide_features_desc_color ? 'color:' . $slide_features_desc_color : '') . '">' . $slide_feature_desc . '</span>';
                        }

                        $output .= '</div>';
                        $output .= '</div>';
                        $output .= '</li>';
                    }

                    $output .= '</ul>';
                    $output .= '</div>';
                }
                if ($primarySlideButton || $showSecondaryButton) {
                    $output .= '<div class="fon-slide-button-container ' . ($showSecondaryButton ? 'd-flex gap-3 justify-content-center justify-content-md-start' : '') . ' ' . ($use_slide_features ? 'mt-3' : 'mt-3 mt-lg-5') . ' ' . ($button_animation != 'none' ? 'animated' : '') . '" ' . ($button_animation != 'none' ? 'data-animation-in="' . $button_animation . '" data-delay-in="0.4"' : '') . '>';

                    if ($primarySlideButton) {
                        $output .= self::parseButton((object) $button, $moduleId . '-' . $inner_uniqid, $pageData);
                    }

                    if ($showSecondaryButton) {
                        $output .= self::parseButton((object) $secondaryButton, $moduleId . '-' . $inner_uniqid . '-secondary', $pageData);
                    }

                    $output .= '</div>';
                }

                $output .= '</div>';

                if ($image_in_column) {
                    $output .= '</div>';
                    $image_content = '';

                    if (is_object($item_value->slide_image)) {
                        $image_content = (isset($item_value->slide_image->{$this->lang}) && $item_value->slide_image->{$this->lang} ? $item_value->slide_image->{$this->lang} : array_values((array) $item_value->slide_image)[0] ?? '');
                    }
                    else if (is_string($item_value->slide_image)) {
                        $image_content = $item_value->slide_image;
                    }

                    $image_content_src = ($image_content ? static::assetLinkDetermine($image_content) : $lazyPlaceholder);
                    $imageDimensions = static::getImageDimensions($image_content_src, $pageData['badress']);
                    $isContentLcp = false;
                    if ($image_content && $isFirstSlide && $isLCPCandidate && self::$lcpHandled === false) {
                        $this->addPreloadLink($image_content, $pageData['page']);
                        self::$lcpHandled = true;
                        $isContentLcp = true;
                    }
                    $image_height = (isset($item_value->slide_image_height) && $item_value->slide_image_height ? $item_value->slide_image_height : false);
                    $image_animation = (isset($item_value->slide_image_animation) && $item_value->slide_image_animation ? $item_value->slide_image_animation : 'none');
                    $img_attrs = 'class="img-fluid fon-slider-image-entity d-inline" src="' . $image_content_src . '" alt="' . strip_tags($title) . '" ' . $imageDimensions;

                    if ($isFirstSlide) {
                        $img_attrs .= ' loading="eager" ';

                        if ($isContentLcp) {
                            $img_attrs .= ' fetchpriority="high" decoding="sync" ';
                        }
                        else {
                            $img_attrs .= ' fetchpriority="auto" decoding="async" ';
                        }
                    }
                    else {
                        $img_attrs .= ' loading="lazy" decoding="async" ';
                    }

                    $output .= '<div class="col-' . $image_column_width_xs . ' col-sm-' . $image_column_width_sm . ' col-md-' . $image_column_width_md . ' col-lg-' . $image_column_width_lg . ' col-xl-' . $image_column_width_xl . ' order-' . $slide_image_order_xs . ' order-sm-' . $slide_image_order_sm . ' order-md-' . $slide_image_order_md . ' order-lg-' . $slide_image_order_lg . ' order-xl-' . $slide_image_order_xl . '">';
                    $output .= '<div class="fon-slider-image-align">';
                    $output .= '<div class="fon-slider-image text-center ' . ($image_animation != 'none' ? 'animated' : '') . ' ' . $inner_uniqid . '-image" ' . ($image_animation != 'none' ? 'data-animation-in="' . $image_animation . '" data-delay-in="0.5"' : '') . '>';
                    $output .= '<img ' . $img_attrs . '>';
                    $output .= '</div>';
                    $output .= '</div>';
                    $output .= '</div>';
                    $output .= '</div>';
                }

                if ($content_container_option === 'bootstrap') {
                    if (!$image_in_column) {
                        $output .= '</div>';
                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }
                else {
                    $output .= '</div>';
                }
                if (isset($item_value->slider_overlay_type) && $item_value->slider_overlay_type == 'color') {
                    if (isset($item_value->slider_color_overlay) && $item_value->slider_color_overlay) {
                        $style .= '.fon-item.' . $uniqid . ' .fon-background:after{';
                        $style .= 'background-color:' . $item_value->slider_color_overlay . ';';
                        $style .= '}';
                    }
                }
                if (isset($item_value->slider_overlay_type) && $item_value->slider_overlay_type == 'gradient') {
                    if (isset($item_value->slider_gradient_overlay) && $item_value->slider_gradient_overlay) {
                        $item_value->slider_gradient_overlay = self::parseGradient($item_value->slider_gradient_overlay);
                        $style .= '.fon-item.' . $uniqid . ' .fon-background:after{';
                        $style .= $item_value->slider_gradient_overlay;
                        $style .= '}';
                    }
                }
                if ($title_font || $title_color) {
                    $style .= '.' . $inner_uniqid . '-title{';

                    if ($title_font) {
                        $style .= $title_font;
                    }

                    if ($title_color) {
                        $style .= 'color: ' . $title_color . ';';
                    }

                    $style .= '}';
                }
                if ($subtitle_font || $subtitle_color) {
                    $style .= '.' . $inner_uniqid . '-subtitle{';

                    if ($subtitle_font) {
                        $style .= $subtitle_font;
                    }

                    if ($subtitle_color) {
                        $style .= 'color: ' . $subtitle_color . ';';
                    }

                    $style .= '}';
                }

                if ($content_color) {
                    $style .= '.fon-slider .fon-slider-text.' . $inner_uniqid . '-description{';
                    $style .= 'color: ' . $content_color . ';';
                    $style .= '}';
                }
                if ($image_in_column && $image_content) {
                    if (isset($image_height) && $image_height) {
                        $responsiveItems = [
                            '.' . $inner_uniqid . '-image img' => [
                            ['type' => 'max-height', 'unit' => 'px', 'value' => $image_height]
                        ]
                        ];
                        $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
                    }
                    else {
                        $style .= '.' . $inner_uniqid . '-image img{';
                        $style .= 'max-height: 90%;';
                        $style .= '}';
                    }
                }

                $output .= '</div>';
            }
        }

        $output .= '</div>';

        if ($content_container_option !== 'bootstrap') {
            $style .= '#' . $widgetId . '.fon-slider .fon-slider-content-wrap{';
            $style .= 'margin: 0 auto;';
            $style .= 'width: ' . $content->content_custom_width . '%;';
            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        return $output;
    }

    private function sms_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetProducts($content, $moduleId, $pageData, $row, 'sms');
    }

    private function software_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetPages($content, $moduleId, $pageData, 'software');
    }

    private function social_share_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $social_networks = [
            'facebook'  => [
            'url'   => 'https://www.facebook.com/sharer.php?u={url}',
            'icon'  => 'fa-brands fa-facebook-f',
            'label' => 'Facebook',
            'popup' => ['width' => 600, 'height' => 300],
            'color' => ['normal' => '#306199', 'hover' => '#244872']
        ],
            'twitter'   => [
            'url'   => 'https://twitter.com/share?url={url}&text={title}',
            'icon'  => 'fa-brands fa-x-twitter',
            'label' => 'X (Twitter)',
            'popup' => ['width' => 600, 'height' => 300],
            'color' => ['normal' => '#000000c7', 'hover' => '#000']
        ],
            'linkedin'  => [
            'url'   => 'https://www.linkedin.com/shareArticle?mini=true&url={url}',
            'icon'  => 'fa-brands fa-linkedin',
            'label' => 'LinkedIn',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#007bb6', 'hover' => '#005983']
        ],
            'pinterest' => [
            'url'   => 'https://pinterest.com/pin/create/button/?url={url}&description={title}',
            'icon'  => 'fa-brands fa-pinterest',
            'label' => 'Pinterest',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#b81621', 'hover' => '#8a1119']
        ],
            'tumblr'    => [
            'url'   => 'https://tumblr.com/share?s=&v=3&t={title}&u={url}',
            'icon'  => 'fa-brands fa-tumblr',
            'label' => 'Tumblr',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#32506d', 'hover' => '#22364a']
        ],
            'getpocket' => [
            'url'   => 'https://getpocket.com/save?url={url}',
            'icon'  => 'fa-brands fa-get-pocket',
            'label' => 'Pocket',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#ed4054', 'hover' => '#e4162d']
        ],
            'reddit'    => [
            'url'   => 'https://www.reddit.com/submit?url={url}',
            'icon'  => 'fa-brands fa-reddit',
            'label' => 'Reddit',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#ff4500', 'hover' => '#e83f00']
        ],
            'vk'        => [
            'url'   => 'https://vk.com/share.php?url={url}',
            'icon'  => 'fa-brands fa-vk',
            'label' => 'VK',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#597ba5', 'hover' => '#3d5f88']
        ],
            'xing'      => [
            'url'   => 'https://www.xing.com/spi/shares/new?cb=0&url={url}',
            'icon'  => 'fa-brands fa-xing',
            'label' => 'Xing',
            'popup' => ['width' => 585, 'height' => 666],
            'color' => ['normal' => '#005658', 'hover' => '#004748']
        ],
            'whatsapp'  => [
            'url'   => 'https://api.whatsapp.com/send?text={url}',
            'icon'  => 'fa-brands fa-whatsapp',
            'label' => 'WhatsApp',
            'popup' => false,
            'color' => ['normal' => '#00d66e', 'hover' => '#00b55d']
        ],
            'telegram'  => [
            'url'   => 'https://t.me/share/url?url={url}&text={title}',
            'icon'  => 'fa-brands fa-telegram',
            'label' => 'Telegram',
            'popup' => false,
            'color' => ['normal' => '#54a9eb', 'hover' => '#4998d5']
        ],
            'bluesky'   => [
            'url'   => 'https://bsky.app/intent/compose?text={url}',
            'icon'  => 'fa-brands fa-bluesky',
            'label' => 'Bluesky',
            'popup' => false,
            'color' => ['normal' => '#0285ff', 'hover' => '#2566a4']
        ],
            'email'     => [
            'url'   => 'mailto:?subject={title}&body={url}',
            'icon'  => 'fa-solid fa-envelope',
            'label' => 'E-Mail',
            'popup' => false,
            'color' => ['normal' => '#7d7d7d', 'hover' => '#4d4d4d']
        ]
        ];
        $widgetId = 'fon-widget-' . $moduleId;
        $social_media = (isset($content->social_media) && $content->social_media ? $content->social_media : []);
        $widget_style = (isset($content->widget_style) && $content->widget_style ? $content->widget_style : 'button');
        $dropdown_title = (isset($content->dropdown_title) && isset($content->dropdown_title->{$this->lang}) && $content->dropdown_title->{$this->lang} ? $content->dropdown_title->{$this->lang} : (isset($content->dropdown_title) ? array_values((array) $content->dropdown_title)[0] ?? '' : ''));
        $show_label = (isset($content->show_label) && $content->show_label == 'yes' ? true : false);
        $color_scheme = (isset($content->color_scheme) && $content->color_scheme ? $content->color_scheme : 'default');
        $text_color_normal = (isset($content->text_color) && isset($content->text_color->normal) && $content->text_color->normal ? $content->text_color->normal : '#000000');
        $text_color_hover = (isset($content->text_color) && isset($content->text_color->hover) && $content->text_color->hover ? $content->text_color->hover : '#ffffff');
        $background_color_normal = (isset($content->background_color) && isset($content->background_color->normal) && $content->background_color->normal ? $content->background_color->normal : '#f9f9f9');
        $background_color_hover = (isset($content->background_color) && isset($content->background_color->hover) && $content->background_color->hover ? $content->background_color->hover : '#000000');
        $border_radius = (isset($content->border_radius) && $content->border_radius ? $content->border_radius : 0);
        $fon_class = (isset($content->fon_class) && $content->fon_class ? $content->fon_class : '');
        $align = (isset($content->align) && $content->align ? $content->align : 'center');

        switch ($align) {
        case 'left':
            $align = 'start';
            break;
        case 'right':
            $align = 'end';
            break;
        case 'center':
            $align = 'center';
            break;
        }

        $style = '';

        if ($widget_style != 'dropdown') {
            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a{';

            if ($widget_style == 'button') {
                $style .= 'color:#fff;';

                if ($show_label) {
                    $style .= 'padding: .375rem .75rem;';
                }
                else {
                    $style .= 'padding: .75rem;';
                }

                $style .= 'font-size: .875rem;';

                if ($color_scheme == 'default') {
                    $style .= '--normal-color:var(--fon-link-color);';
                    $style .= '--hover-color:var(--fon-hover-color);';
                }
                else if ($color_scheme == 'primary') {
                    $style .= '--normal-color:var(--theme-primary);';
                    $style .= '--hover-color:var(--theme-secondary);';
                }
                else if ($color_scheme == 'secondary') {
                    $style .= '--normal-color:var(--theme-secondary);';
                    $style .= '--hover-color:var(--theme-primary);';
                }
                else if ($color_scheme == 'custom') {
                    $style .= '--normal-color:' . $background_color_normal . ';';
                    $style .= '--hover-color:' . $background_color_hover . ';';
                    $style .= 'color:' . $text_color_normal . ';';
                }

                $style .= 'background-color:var(--normal-color);';
            }
            else if ($widget_style == 'list') {
                $style .= 'color:var(--fon-link-color);';
            }

            $style .= 'cursor:pointer;';
            $style .= 'border-radius: ' . $border_radius . 'px;';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a:hover{';

            if ($widget_style == 'button') {
                $style .= 'background-color:var(--hover-color);';

                if ($color_scheme == 'custom') {
                    $style .= 'color:' . $text_color_hover . ';';
                }
            }
            else if ($widget_style == 'list') {
                $style .= 'color:var(--fon-hover-color);';
            }

            $style .= '}';
        }
        else {
            if (!$show_label) {
                $style .= '#' . $widgetId . ' .dropdown-menu{';
                $style .= 'text-align: center;';
                $style .= 'min-width: 56px;';
                $style .= '--bs-dropdown-item-padding-x: 0.5rem;';
                $style .= '}';
            }

            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a{';
            $style .= 'cursor:pointer;';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a > i{';
            $style .= 'color:var(--fon-link-color);';
            $style .= '}';
            $style .= '#' . $widgetId . ' .fon-social-share-list > li > a:hover > i{';
            $style .= 'color:var(--fon-hover-color);';
            $style .= '}';

            if ($color_scheme == 'default') {
                $dropdownBtnClass = 'btn-outline-dark';
            }
            else if ($color_scheme == 'primary') {
                $dropdownBtnClass = 'btn-default';
            }
            else if ($color_scheme == 'secondary') {
                $dropdownBtnClass = 'btn-secondary';
            }
            else if ($color_scheme == 'custom') {
                $dropdownBtnClass = 'btn-custom';
                $style .= '#' . $widgetId . ' .btn-custom.dropdown-toggle{';
                $style .= 'color:' . $text_color_normal . ';';
                $style .= 'background-color:' . $background_color_normal . ';';
                $style .= 'border-color:' . $background_color_normal . ';';
                $style .= '}';
                $style .= '#' . $widgetId . ' .btn-custom.dropdown-toggle:hover{';
                $style .= 'color:' . $text_color_hover . ';';
                $style .= 'background-color:' . $background_color_hover . ';';
                $style .= 'border-color:' . $background_color_hover . ';';
                $style .= '}';
            }
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-social-share-widget ' . $fon_class . '">';
        $output .= '<script>var socialSharePageTitle=encodeURIComponent(document.title); var socialSharepageLink = encodeURIComponent(window.location.href);</script>';
        $output .= '<div class="fon-widget-content ' . ($widget_style == 'dropdown' ? 'text-' . $align : '') . '">';

        if ($widget_style == 'dropdown') {
            $output .= '<div class="btn-group position-relative">';
            $output .= '<button class="btn ' . $dropdownBtnClass . ' dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="fa-solid fa-share-nodes"></i>' . ($show_label ? ' ' . $dropdown_title : '') . '</button>';
        }

        $output .= '<ul class="fon-social-share-list ' . ($widget_style != 'dropdown' ? 'list-unstyled d-flex flex-wrap align-item-center justify-content-' . $align . ' gap-3' : 'dropdown-menu dropdown-menu-' . $align) . '">';

        foreach ($social_media as $network_key) {
            if (isset($social_networks[$network_key])) {
                $network = $social_networks[$network_key];
                $link_action = '';

                if ($network_key == 'email') {
                    $url_template = str_replace(['{title}', '{url}'], ['\' + socialSharePageTitle + \'', '\' + socialSharepageLink + \''], $network['url']);
                    $link_action = 'onClick="window.location.href = \'' . $url_template . '\'; return false"';
                }
                else if (isset($network['popup']) && $network['popup']) {
                    $url_template = str_replace(['{title}', '{url}'], ['\' + socialSharePageTitle + \'', '\' + socialSharepageLink + \''], $network['url']);
                    $w = $network['popup']['width'];
                    $h = $network['popup']['height'];
                    $link_action = 'onClick="window.open(\'' . $url_template . '\', \'' . $network['label'] . '\', \'width=' . $w . ',height=' . $h . ',left=\'+(screen.availWidth/2-' . ($w / 2) . ')+\',top=\'+(screen.availHeight/2-' . ($h / 2) . ')+\'\'); return false;"';
                }
                else {
                    $url_template = str_replace(['{title}', '{url}'], ['\' + socialSharePageTitle + \'', '\' + socialSharepageLink + \''], $network['url']);
                    $link_action = 'onClick="window.open(\'' . $url_template . '\'); return false;"';
                }

                $output .= '<li class="fon-social-share-' . htmlspecialchars($network_key) . '">';
                $output .= '<a ' . $link_action . ' style="--fon-link-color:' . $social_networks[$network_key]['color']['normal'] . ';--fon-hover-color:' . $social_networks[$network_key]['color']['hover'] . ';--fon-active-color:' . $social_networks[$network_key]['color']['hover'] . ';" ' . ($widget_style == 'dropdown' ? 'class="dropdown-item"' : '') . '>';
                $output .= '<i class="' . htmlspecialchars($network['icon']) . ' fa-fw" aria-hidden="true" title="' . htmlspecialchars($network['label']) . '"></i>';

                if ($show_label) {
                    $output .= '<span class="fon-social-share-title ms-1">' . htmlspecialchars($network['label']) . '</span>';
                }

                $output .= '</a>';
                $output .= '</li>';
            }
        }

        $output .= '</ul>';

        if ($widget_style == 'dropdown') {
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function special_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        return $this->getWidgetProducts($content, $moduleId, $pageData, $row, 'special');
    }

    private function tabs_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $align = '';
        if (isset($content->direction) && $content->direction == 'horizontal') {
            if (isset($content->align) && $content->align == 'right') {
                $align = 'justify-content-end';
            }
            else if (isset($content->align) && $content->align == 'center') {
                $align = 'justify-content-center';
            }
            else if (isset($content->align) && $content->align == 'justify') {
                $align = 'nav-justified';
            }
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-tabs-widget ' . ($content->dark_container == 'yes' ? 'dark-container' : '') . ' ' . $content->direction . ' style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        if (isset($content->items) && is_array($content->items)) {
            $output .= '<ul class="nav nav-tabs widget-tabs ' . $align . '">';

            foreach ($content->items as $tbkey => $tbitem) {
                $title = (isset($tbitem->tab_title->{$this->lang}) && $tbitem->tab_title->{$this->lang} ? $tbitem->tab_title->{$this->lang} : array_values((array) $tbitem->tab_title)[0] ?? '');
                $subtitle = (isset($tbitem->tab_subtitle->{$this->lang}) && $tbitem->tab_subtitle->{$this->lang} ? $tbitem->tab_subtitle->{$this->lang} : array_values((array) $tbitem->tab_subtitle)[0] ?? '');

                if ($title) {
                    $output .= '<li class="nav-item">';
                    $output .= '<a class="nav-link widget-nav-link ' . ($tbkey == 0 ? 'active' : '') . '" data-bs-toggle="tab" href="#' . $moduleId . '-tab-' . $tbkey . '">';
                    if (isset($content->show_icon) && $content->show_icon == 'yes') {
                        $output .= '<i class="' . $tbitem->tab_icon . ' fa-fw ' . (isset($content->show_subtitle) && $content->show_subtitle == 'yes' && $subtitle ? 'subtitle' : '') . '"></i>';
                    }

                    $output .= '<span class="tab-titles">';
                    $output .= "\t" . '<span class="tab-title">' . $title . '</span>';
                    if (isset($content->show_subtitle) && $content->show_subtitle == 'yes' && $subtitle) {
                        $output .= '<span class="tab-subtitle">' . $subtitle . '</span>';
                    }

                    $output .= '</span>';
                    $output .= '</a>';
                    $output .= '</li>';
                }
            }

            $output .= '</ul>';
            $output .= '<div class="tab-content">';

            foreach ($content->items as $tckey => $tcitem) {
                $tabContent = (isset($tcitem->tab_content->{$this->lang}) && $tcitem->tab_content->{$this->lang} ? $tcitem->tab_content->{$this->lang} : array_values((array) $tcitem->tab_content)[0] ?? '');
                $output .= '<div id="' . $moduleId . '-tab-' . $tckey . '" class="tab-pane fade ' . ($tckey == 0 ? 'active show' : '') . '">';

                if ($tabContent) {
                    $output .= $tabContent;
                }

                $output .= '</div>';
            }

            $output .= '</div>';
        }

        $output .= '</div>';
        return $output;
    }

    private function team_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';

        if (isset($content->image_overlay_type)) {
            $style .= '#' . $widgetId . ' .team{';

            if ($content->image_overlay_type == 'color') {
                $style .= '--bs-bg-overlay-color: ' . $content->image_color_overlay . ';';
            }
            else {
                $style .= self::parseGradient($content->image_gradient_overlay, 'bg-overlay');
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $carouselData = '';
        $columns = [];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-row="' . $content->use_row . '" data-rows="' . htmlspecialchars(Utility::jencode($content->row, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel team-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl : '');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-team-widget overlay-' . $content->image_overlay_type . ' style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content ' . $containerClass . '" ' . $carouselData . '>';
        if (isset($content->items) && is_array($content->items)) {
            foreach ($content->items as $item) {
                if ($item->team_image) {
                    $item->team_image = static::assetLinkDetermine($item->team_image);
                }
                else {
                    $item->team_image = $lazyPlaceholder;
                }

                $imageDimensions = static::getImageDimensions($item->team_image, $pageData['badress']);

                if (!$isCarousel) {
                    $output .= '<div class="col">';
                }

                if (self::isJSON($item->team_socials)) {
                    $item->team_socials = Utility::jdecode($item->team_socials);
                }
                $team_position = (isset($item->team_position->{$this->lang}) && $item->team_position->{$this->lang} ? $item->team_position->{$this->lang} : array_values((array) $item->team_position)[0] ?? '');
                include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'team' . DS . 'style_' . $content->widget_style . '.php';

                if (!$isCarousel) {
                    $output .= '</div>';
                }
            }
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function testimonial_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $source = (isset($content->source) && $content->source ? $content->source : 'manuel');
        $show_form = (isset($content->show_form) && $content->show_form == 'yes' ? true : false);
        $form_style = (isset($content->form_style) && $content->form_style ? $content->form_style : 'modal');
        $form_title = (isset($content->form_title) && isset($content->form_title->{$this->lang}) && $content->form_title->{$this->lang} ? $content->form_title->{$this->lang} : (isset($content->form_title) ? array_values((array) $content->form_title)[0] ?? '' : ''));
        $form_desc = (isset($content->form_desc) && isset($content->form_desc->{$this->lang}) && $content->form_desc->{$this->lang} ? $content->form_desc->{$this->lang} : (isset($content->form_desc) ? array_values((array) $content->form_desc)[0] ?? '' : ''));
        $form_button = (isset($content->form_button) && isset($content->form_button->{$this->lang}) && $content->form_button->{$this->lang} ? $content->form_button->{$this->lang} : (isset($content->form_button) ? array_values((array) $content->form_button)[0] ?? '' : ''));
        $form_position = (isset($content->form_position) && $content->form_position ? $content->form_position : 'after');
        $limit = (isset($content->limit) && $content->limit ? $content->limit : 8);
        $feedbackConfig = ___('blocks/customer-feedback');
        $form_action = Controllers::$init->CRLink('cfeedback-send');

        if ($source == 'wisecp') {
            $contentItems = self::getTestimonials($limit);
            $content->items = [];

            if ($contentItems) {
                foreach ($contentItems as $contentItem) {
                    $tci = new stdClass();
                    $tci->testimonial_author = $contentItem['full_name'];
                    $tci->testimonial_avatar = ($contentItem['image'] ? 'resources/uploads/customer-feedback/' . $contentItem['image'] : '');
                    $tci->testimonial_position = new stdClass();
                    $tci->testimonial_position->{$this->lang} = $contentItem['company_name'];
                    $tci->testimonial_message = new stdClass();
                    $tci->testimonial_message->{$this->lang} = $contentItem['message'];
                    $tci->testimonial_star = 5;
                    $tci->testimonial_star_style = 'google';
                    $content->items[] = $tci;
                }
            }
        }

        $carouselData = '';
        $columns = [];

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-row="' . $content->use_row . '" data-rows="' . htmlspecialchars(Utility::jencode($content->row, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" id="carousel-' . $widgetId . '"';
            $containerClass = 'fon-content-carousel testimonial-carousel';
        }
        else {
            $columns = $content->column;
            $containerClass = (1 < count($content->items) ? 'row g-4 row-cols-' . $columns->xs . ' row-cols-sm-' . $columns->sm . ' row-cols-md-' . $columns->md . ' row-cols-lg-' . $columns->lg . ' row-cols-xl-' . $columns->xl : '');
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-testimonial-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        if (($source == 'wisecp') && $show_form && $form_style != 'inline' && $form_position == 'before') {
            $output .= '<p class="text-center"><button class="btn btn-default" type="button" data-bs-toggle="' . $form_style . '" data-bs-target="#' . $widgetId . '-feedback-form" ' . ($form_style == 'collapse' ? 'aria-expanded="false" aria-controls="collapseExample"' : '') . '><i class="fa-solid fa-comment"></i> ' . $form_button . '</button></p>';
        }

        $output .= '<div class="fon-widget-content ' . $containerClass . '" ' . $carouselData . '>';
        if (isset($content->items) && is_array($content->items)) {
            $even = true;

            foreach ($content->items as $item) {
                $testimonial_position = (isset($item->testimonial_position->{$this->lang}) && $item->testimonial_position->{$this->lang} ? $item->testimonial_position->{$this->lang} : array_values((array) $item->testimonial_position)[0] ?? '');
                $testimonial_message = (isset($item->testimonial_message->{$this->lang}) && $item->testimonial_message->{$this->lang} ? $item->testimonial_message->{$this->lang} : array_values((array) $item->testimonial_message)[0] ?? '');

                if ($content->display_avatar == 'yes') {
                    if ($item->testimonial_avatar) {
                        $item->testimonial_avatar = static::assetLinkDetermine($item->testimonial_avatar);
                    }
                    else {
                        $item->testimonial_avatar = $lazyPlaceholder;
                    }

                    $imageDimensions = static::getImageDimensions($item->testimonial_avatar, $pageData['badress']);
                }

                if (!$isCarousel) {
                    $output .= '<div class="col">';
                }

                include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'testimonial' . DS . 'style_' . $content->widget_style . '.php';

                if (!$isCarousel) {
                    $output .= '</div>';
                }

                $even = !$even;
            }
        }

        $output .= '</div>';
        if (($source == 'wisecp') && $show_form && $form_style != 'inline' && $form_position == 'after') {
            $output .= '<p class="text-center"><button class="btn btn-default" type="button" data-bs-toggle="' . $form_style . '" data-bs-target="#' . $widgetId . '-feedback-form" ' . ($form_style == 'collapse' ? 'aria-expanded="false" aria-controls="collapseExample"' : '') . '><i class="fa-solid fa-comment"></i> ' . $form_button . '</button></p>';
        }

        $output .= '</div>';
        if (($source == 'wisecp') && $show_form) {
            $captcha_status = (Config::get('options/captcha/status') == 1) && Config::get('options/captcha/customer-feedback') == 1;
            if (!$captcha_status && Config::get('options/BotShield/status')) {
                if (!class_exists('BotShield')) {
                    Helper::Load('BotShield');
                }

                $captcha_status = BotShield::is_blocked('customer-feedback');
            }

            if ($captcha_status) {
                if (!class_exists('Captcha')) {
                    Helper::Load('Captcha');
                }

                $feedbackCaptcha = Helper::get('Captcha');
            }

            $output .= '<div id="' . $widgetId . '-feedback-form" class="' . $form_style . '" ' . ($form_style == 'modal' ? 'tabindex="-1" aria-labelledby="' . $widgetId . 'ModalLabel" aria-hidden="true"' : '') . '>';

            if ($form_style == 'modal') {
                $output .= '<div class="modal-dialog modal-dialog-centered">';
                $output .= '<div class="modal-content">';
                $output .= '<div class="modal-header">';
                $output .= '<h3 class="modal-title fs-5" id="' . $widgetId . 'ModalLabel">' . $form_title . '</h3>';
                $output .= '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>';
                $output .= '</div>';
            }

            $output .= '<div class="modal-body ' . ($form_style != 'modal' ? 'rounded-4 bg-theme-light p-3 p-lg-4' : '') . '">';
            if (($form_style != 'modal') && $form_title) {
                $output .= '<h3 class="text-center my-3">' . $form_title . '</h3>';
            }

            if ($form_desc) {
                $output .= '<p class="text-center">' . $form_desc . '</p>';
            }

            $output .= '<form action="' . $form_action . '" method="POST" id="' . $widgetId . 'FeedbackForm" enctype="multipart/form-data" class="cFeedBackForm">';
            $output .= Validation::get_csrf_token('cfeedback');
            $output .= '<div class="row g-3 mb-3">';
            $output .= '<div class="col-12 col-lg-' . ($form_style == 'modal' ? '6' : '4') . '">';
            $output .= '<input type="text" class="form-control" name="full_name" placeholder="' . __('website/cfeedback/form-fullname') . '" aria-label="' . __('website/cfeedback/form-fullname') . '" id="' . $widgetId . '-full-name">';
            $output .= '</div>';
            $output .= '<div class="col-12 col-lg-' . ($form_style == 'modal' ? '6' : '4') . '">';
            $output .= '<input type="text" class="form-control" name="company_name" placeholder="' . __('website/cfeedback/form-company_name') . '" aria-label="' . __('website/cfeedback/form-company_name') . '" id="' . $widgetId . '-company-name">';
            $output .= '</div>';
            $output .= '<div class="col-12 col-lg-' . ($form_style == 'modal' ? '12' : '4') . '">';
            $output .= '<input type="text" class="form-control" name="email" placeholder="' . __('website/cfeedback/form-email') . '" aria-label="' . __('website/cfeedback/form-email') . '"  id="' . $widgetId . '-email">';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '<div class="mb-3">';
            $output .= '<textarea class="form-contol w-100" rows="5" style="resize: none;" maxlength="425" name="message" placeholder="' . __('website/cfeedback/form-message') . '" id="' . $widgetId . '-message"></textarea>';
            $output .= '</div>';
            $output .= '<div class="mb-3">';
            $output .= '<label for="' . $widgetId . '-file" class="form-label">' . __('website/cfeedback/form-image') . '</label>';
            $output .= '<input class="form-control" type="file"  name="image" id="' . $widgetId . '-file" accept=".jpg,.jpeg,.png">';
            $output .= '</div>';
            if (isset($feedbackCaptcha) && $feedbackCaptcha) {
                $output .= '<div class="input-group mb-3">';
                $output .= '<span class="input-group-text p-0 bg-white">' . $feedbackCaptcha->getOutput() . '</span>';

                if ($feedbackCaptcha->input) {
                    $output .= '<input id="requiredinput" name="' . $feedbackCaptcha->input_name . '" type="text"  class="form-control form-control-lg" aria-label="' . ___('needs/form-captcha-label') . '" placeholder="' . ___('needs/form-captcha-label') . '">';
                }

                $output .= '</div>';
            }

            $output .= '<p class="text-end">';
            $output .= '<a class="btn btn-success" id="' . $widgetId . 'FeedbackForm_submit" href="javascript:void(0);"><i class="fa-solid fa-paper-plane"></i> ' . $form_button . '</a>';
            $output .= '</p>';
            $output .= '<div id="' . $widgetId . 'FeedbackForm_output" class="text-danger fw-bold" style="display:none"></div>';
            $output .= '</form>';
            $output .= '<div id="' . $widgetId . 'FeeadbackForm_Successful" style="display: none">';
            $output .= '<div class="text-center my-5">';
            $output .= '<i class="fa-solid fa-check-circle fa-5x mb-3 text-success"></i>';
            $output .= '<h4 class="text-success fw-bold">' . __('website/cfeedback/successful-text1') . '</h4>';
            $output .= '<h5>' . __('website/cfeedback/successful-text2') . '</h5>';
            $output .= '</div>';
            $output .= '</div>';
            $output .= '</div>';

            if ($form_style == 'modal') {
                $output .= '</div>';
                $output .= '</div>';
            }

            $output .= '</div>';
            $output .= '<script type="text/javascript">' . "\n" . '                            $(document).ready(function(){' . "\n" . '                                $("#' . $widgetId . 'FeedbackForm_submit").on("click",function(){' . "\n" . '                                    MioAjaxElement($(this),{' . "\n" . '                                        waiting_text: \'' . __('website/others/button1-pending') . '\',' . "\n" . '                                        progress_text: \'' . __('website/others/button1-upload') . '\',' . "\n" . '                                        result:"' . $moduleId . 'feedback_result",' . "\n" . '                                    });' . "\n" . '                                });' . "\n" . '                                $("#' . $widgetId . '-feedback-form").on("shown.bs.collapse", function () {' . "\n" . '                                    this.scrollIntoView({ behavior: "smooth", block: "start" });' . "\n" . '                                });' . "\n" . '                            });' . "\n" . '                            function ' . $moduleId . 'feedback_result(result) {';

            if (isset($feedbackCaptcha)) {
                $output .= $feedbackCaptcha->submit_after_js();
            }

            $output .= 'if(result != ""){' . "\n" . '                                    var solve = getJson(result);' . "\n" . '                                    if(solve !== false){' . "\n" . '                                        if(solve.status == "error"){' . "\n" . '                                            if(solve.for != undefined && solve.for != ""){' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm "+solve.for).focus();' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm "+solve.for).addClass("is-invalid");' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm "+solve.for).change(function(){' . "\n" . '                                                    $(this).removeClass("is-invalid");' . "\n" . '                                                });' . "\n" . '                                            }' . "\n" . '    ' . "\n" . '                                            if(solve.message != undefined && solve.message != ""){' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm_output").fadeIn(500).html(solve.message);' . "\n" . '                                            }else{' . "\n" . '                                                $("#' . $widgetId . 'FeedbackForm_output").fadeOut(500).html("");' . "\n" . '                                            }' . "\n" . '                                        }else if(solve.status == "successful"){' . "\n" . '                                            $("#' . $widgetId . 'FeedbackForm_output").fadeOut(500).html("");' . "\n" . '                                            $("#' . $widgetId . 'FeedbackForm").slideUp(200,function(){' . "\n" . '                                                $("#' . $widgetId . 'FeeadbackForm_Successful").slideDown(200);' . "\n" . '                                            });' . "\n" . '                                        }' . "\n" . '                                    }else{' . "\n" . '                                        console.log(result);' . "\n" . '                                    }' . "\n" . '                                }' . "\n" . '                            }' . "\n" . '                        </script>';
        }

        return $output;
    }

    private function text_html_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $name_widget = (isset($content->name_widget) && isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : (isset($content->name_widget) ? array_values((array) $content->name_widget)[0] ?? '' : ''));
        $content_text = (isset($content->content) && isset($content->content->{$this->lang}) && $content->content->{$this->lang} ? $content->content->{$this->lang} : (isset($content->content) ? array_values((array) $content->content)[0] ?? '' : ''));
        $show_name = (isset($content->show_name) && $content->show_name == 'yes' ? true : false);
        $heading_selector = (isset($content->heading_selector) && $content->heading_selector ? $content->heading_selector : 'h3');
        $title_color = (isset($content->title_color) && $content->title_color ? $content->title_color : '');
        $title_font = (isset($content->title_font) && $content->title_font ? $content->title_font : []);
        $title_margin = (isset($content->title_margin) && $content->title_margin ? $content->title_margin : (object) ['xl' => '', 'lg' => '', 'md' => '', 'sm' => '', 'xs' => '']);
        $column_count = (isset($content->column_count) && $content->column_count ? $content->column_count : []);
        $column_gap = (isset($content->column_gap) && $content->column_gap ? $content->column_gap : []);
        $content_truncation = (isset($content->content_truncation) && $content->content_truncation == 'yes' ? true : false);
        $truncation_max_word = (isset($content->truncation_max_word) && $content->truncation_max_word ? $content->truncation_max_word : 50);
        $truncation_action_color = (isset($content->truncation_action_color) && $content->truncation_action_color ? $content->truncation_action_color : '#0000ff');
        $truncation_action_font = (isset($content->truncation_action_font) && $content->truncation_action_font ? $content->truncation_action_font : []);
        $truncation_action_text = (isset($content->truncation_action_text) && isset($content->truncation_action_text->{$this->lang}) && $content->truncation_action_text->{$this->lang} ? $content->truncation_action_text->{$this->lang} : (isset($content->truncation_action_text) ? array_values((array) $content->truncation_action_text)[0] ?? '' : ''));
        $dropcap = (isset($content->dropcap) && $content->dropcap == 'yes' ? true : false);
        $dropcap_color = (isset($content->dropcap_color) && $content->dropcap_color ? $content->dropcap_color : '');
        $dropcap_size = (isset($content->dropcap_size) && $content->dropcap_size ? $content->dropcap_size : []);
        $widget_content_classes = '';

        if ($column_count) {
            $widget_content_classes .= ' fon-widget-content-column';
        }

        if ($dropcap) {
            $widget_content_classes .= ' fon-widget-content-drop-cap';
        }

        $style = '';
        if ($show_name && $name_widget) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';

            if ($title_color) {
                $style .= 'color: ' . $title_color . ';';
            }

            if ($title_font) {
                $style .= self::parseFontProperties($title_font);
            }

            $style .= '}';
        }

        if ($title_margin) {
            $titleMarginResponsiveItems = [
                '.fon-widget-title' => [
                ['type' => 'margin-bottom', 'unit' => 'px', 'value' => $title_margin]
            ]
            ];
            $style .= self::parseResponsiveItems($titleMarginResponsiveItems, $widgetId);
        }
        if ($column_count || $column_gap || $dropcap) {
            if ($column_count || $column_gap) {
                $widget_content_classes .= ' fon-widget-content-column';
                $columnResponsiveItems = [
                    '.fon-widget-content-column' => [
                    ['type' => 'column-count', 'unit' => false, 'value' => $column_count],
                    ['type' => 'column-gap', 'unit' => 'px', 'value' => $column_gap]
                ]
                ];
                $style .= self::parseResponsiveItems($columnResponsiveItems, $widgetId);
            }

            if ($dropcap) {
                $widget_content_classes .= ' fon-widget-content-drop-cap';
                $style .= '#' . $widgetId . ' .fon-widget-content-drop-cap:first-letter,#' . $widgetId . ' .fon-widget-content-drop-cap>*:first-child:first-letter{';
                $style .= 'color: ' . $dropcap_color . ';';
                $style .= '}';
                $dropcapResponsiveItems = [
                    '.fon-widget-content-drop-cap:first-letter,.fon-widget-content-drop-cap>*:first-child:first-letter' => [
                    ['type' => 'font-size', 'unit' => 'px', 'value' => $dropcap_size]
                ]
                ];
                $style .= self::parseResponsiveItems($dropcapResponsiveItems, $widgetId);
            }
        }

        if ($content_truncation) {
            $style .= '#' . $widgetId . ' .fon-widget-content-truncation-show{';
            $style .= 'color: ' . $truncation_action_color . ';';

            if ($truncation_action_font) {
                $style .= self::parseFontProperties($truncation_action_font);
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-text-html-widget ' . $content->fon_class . '">';
        if ($show_name && $name_widget) {
            $output .= '<' . $heading_selector . ' class="fon-widget-title">';
            $output .= self::getPriceHolders($name_widget);
            $output .= '</' . $heading_selector . '>';
        }

        $content_text = self::getPriceHolders($content_text);
        $plain_text = html_entity_decode($content_text, ENT_QUOTES | ENT_HTML5);
        $plain_text = strip_tags($plain_text);

        if (trim(str_replace([' ', ' '], '', $plain_text)) === '') {
            $content_text = '';
        }

        if ($content_text) {
            $output .= '<div class="fon-widget-content' . $widget_content_classes . '">';
            $text_block_text = $content_text;
            if ($content_truncation && !empty($truncation_max_word) && (int) $truncation_max_word < (int) self::wordCount($plain_text)) {
                $arrayString = explode(' ', $content_text);
                $text_block_text = implode(' ', array_slice($arrayString, 0, (int) $truncation_max_word));
                $text_block_text .= '<template class="fon-widget-content-full-text">' . $content_text . '</template>';
                $text_block_text .= '<div class="fon-widget-content-btn-container fon-widget-content-truncation-show"><div role="button" class="fon-widget-content-btn-show-more"><i class="fa-solid fa-plus"></i> ' . $truncation_action_text . '</div></div>';
            }

            $output .= $text_block_text;
            $output .= '</div>';
        }

        $output .= '</div>';
        return $output;
    }

    private function timeline_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        if (in_array($content->widget_style, ['5'])) {
            $this->addAsset('slick');
        }
        $mediaType = (isset($content->media_type) && $content->media_type ? $content->media_type : 'icon');
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-timeline-widget style-' . $content->widget_style . ' ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content ' . (in_array($content->widget_style, ['default', '1']) ? 'row' : '') . ' py-4">';
        if (isset($content->items) && is_array($content->items)) {
            include __DIR__ . DS . 'builder' . DS . 'widget-styles' . DS . 'timeline' . DS . 'style_' . $content->widget_style . '.php';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function vector_map_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $map_type = (isset($content->map_type) && $content->map_type ? $content->map_type : 'world');
        $show_zooms = (isset($content->show_zooms) && $content->show_zooms == 'yes' ? 'true' : 'false');
        $region_fill = (isset($content->region_fill) && $content->region_fill ? $content->region_fill : '#d1d5db');
        $region_stroke = (isset($content->region_stroke) && $content->region_stroke ? $content->region_stroke : '#e5e7eb');
        $region_stroke_width = (isset($content->region_stroke_width) && $content->region_stroke_width ? $content->region_stroke_width : 1);
        $markerItems = (isset($content->items) && $content->items && is_array($content->items) ? $content->items : []);
        $marker_stroke = (isset($content->marker_stroke) && $content->marker_stroke ? $content->marker_stroke : '#ffffff');
        $marker_label = (isset($content->marker_label) && $content->marker_label ? $content->marker_label : 13);
        $marker_radius = (isset($content->marker_radius) && $content->marker_radius ? $content->marker_radius : 6);
        $marker_stroke_width = (isset($content->marker_stroke_width) && $content->marker_stroke_width ? $content->marker_stroke_width : 5);
        $hover_marker_radius = $marker_radius + 3;
        $hover_marker_stroke_width = $marker_stroke_width + 3;
        $show_tooltip = (isset($content->show_tooltip) && $content->show_tooltip == 'yes' ? 'true' : 'false');
        $tooltip_bg = (isset($content->tooltip_bg) && $content->tooltip_bg ? $content->tooltip_bg : '#010101');
        $tooltip_color = (isset($content->tooltip_color) && $content->tooltip_color ? $content->tooltip_color : '#ffffff');
        $show_lines = (isset($content->show_lines) && $content->show_lines == 'yes' ? true : false);
        $animate_lines = (isset($content->animate_lines) && $content->animate_lines == 'yes' ? 'true' : 'false');
        $curvature_lines = (isset($content->curvature_lines) && $content->curvature_lines == 'yes' ? true : false);
        $line_curvature = (isset($content->line_curvature) && $content->line_curvature != '' ? $content->line_curvature : -0.7);
        $line_stroke = (isset($content->line_stroke) && $content->line_stroke ? $content->line_stroke : '#818187');
        $line_stroke_width = (isset($content->line_stroke_width) && $content->line_stroke_width ? $content->line_stroke_width : 1);
        $defaultMarkerFillNormal = '#3b82f6';
        $defaultMarkerFillHover = '#ff5050';
        if (isset($content->marker_fill) && is_object($content->marker_fill)) {
            $marker_fill_normal = (!empty($content->marker_fill->normal) ? $content->marker_fill->normal : $defaultMarkerFillNormal);
            $marker_fill_hover = (!empty($content->marker_fill->hover) ? $content->marker_fill->hover : $defaultMarkerFillHover);
        }
        else if (isset($content->marker_fill) && is_string($content->marker_fill) && !empty($content->marker_fill)) {
            $marker_fill_normal = $content->marker_fill;
            $marker_fill_hover = $defaultMarkerFillHover;
        }
        else {
            $marker_fill_normal = $defaultMarkerFillNormal;
            $marker_fill_hover = $defaultMarkerFillHover;
        }

        $markers = [];
        $lines = [];

        if ($markerItems) {
            foreach ($markerItems as $mKey => $marker) {
                $marker_name = (isset($marker->name) && $marker->name ? $marker->name : '');
                $marker_coords = (isset($marker->coords) && $marker->coords ? $marker->coords : [0, 0]);
                $marker_coords = (is_string($marker_coords) ? explode(',', $marker_coords) : $marker_coords);
                $marker_lineto = (isset($marker->lineto) && $marker->lineto ? $marker->lineto : '');
                $marker_tooltip = (isset($marker->tooltip) && isset($marker->tooltip->{$this->lang}) && $marker->tooltip->{$this->lang} ? $marker->tooltip->{$this->lang} : (isset($marker->tooltip) ? array_values((array) $marker->tooltip)[0] ?? '' : ''));
                $markers[$mKey] = ['name' => $marker->name ?? '', 'coords' => $marker_coords];

                if ($marker_tooltip) {
                    $markers[$mKey]['tooltip'] = $marker_tooltip;
                }
                if ($marker_lineto && !empty($marker_name)) {
                    $lines[] = ['from' => $marker_name, 'to' => $marker_lineto];
                }
            }
        }

        $markersJson = json_encode($markers);
        $linesJson = ($show_lines && $lines ? 'lines: ' . json_encode($lines) . ',' : '');
        $curvature = ($show_lines && $lines && $curvature_lines ? 'curvature: ' . $line_curvature . ',' : '');
        $this->addAsset('jsvectormap');
        $style = '';
        $responsiveItems = [
            '#' . $widgetId . '-map' => [
            ['type' => 'height', 'unit' => 'px', 'value' => $content->map_height]
        ]
        ];
        $style .= self::parseResponsiveItems($responsiveItems, $widgetId);
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-vector-map-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content position-relative">';
        $output .= '<div class="fon-vector-map-container" id="' . $widgetId . '-map">';
        $output .= '</div>';
        $output .= '</div>';
        $output .= '</div>';
        $js = '<script defer src="' . $pageData['tadress'] . 'js/maps/' . $map_type . '.js"></script>' . PHP_EOL;
        $js .= '<script>' . "\n" . 'window.addEventListener("load", function() {' . "\n" . '     setTimeout(function() {' . "\n" . '        var markers' . $moduleId . ' = ' . $markersJson . ';' . "\n" . '        window.map' . $moduleId . ' = new jsVectorMap({' . "\n" . '            selector: document.querySelector("#' . $widgetId . '-map"),' . "\n" . '            map: "' . $map_type . '",' . "\n\t\t\t" . 'backgroundColor: "transparent",' . "\n" . '            showTooltip: ' . $show_tooltip . ',' . "\n\t\t\t" . 'zoomOnScroll: false,' . "\n" . '            zoomButtons: ' . $show_zooms . ',' . "\n\t\t\t" . 'onLoaded(map) {' . "\n" . '                document.querySelectorAll(".jvm-marker, .jvm-label").forEach(i => {' . "\n" . '                    i.classList.add("animated");' . "\n\t\t\t\t" . '});' . "\n" . '                window.addEventListener("resize", () => map.updateSize());' . "\n" . '                setTimeout(() => map.updateSize(), 700);' . "\n\t\t\t" . '},' . "\n\t\t\t" . 'regionStyle: {' . "\n\t\t\t\t" . 'initial: {' . "\n" . '                    fill: "' . $region_fill . '",' . "\n" . '                    stroke: "' . $region_stroke . '",' . "\n" . '                    strokeWidth: ' . $region_stroke_width . ',' . "\n\t\t\t\t\t" . 'fillOpacity: 1,' . "\n\t\t\t\t\t" . 'fillRule:"evenodd"' . "\n\t\t\t\t" . '},' . "\n\t\t\t" . '},' . "\n" . '            markers: markers' . $moduleId . ',' . "\n" . '            ' . $linesJson . "\n\t\t\t" . 'markerStyle: {' . "\n\t\t\t\t" . 'initial: {' . "\n" . '                    r: ' . $marker_radius . ',' . "\n" . '                    fill: "' . $marker_fill_normal . '",' . "\n" . '                    stroke: "' . $marker_stroke . '",' . "\n" . '                    strokeWidth: ' . $marker_stroke_width . ',' . "\n" . '                    strokeOpacity: 0.5' . "\n\t\t\t\t" . ' },' . "\n" . '                hover: {' . "\n" . '                    r: ' . $hover_marker_radius . ',' . "\n" . '                    fill: "' . $marker_fill_hover . '",' . "\n" . '                    strokeWidth: ' . $hover_marker_stroke_width . ',' . "\n" . '                }' . "\n\t\t\t" . '},' . "\n\t\t\t" . 'markerLabelStyle: {' . "\n\t\t\t\t" . 'initial: {' . "\n" . '                    fontSize: ' . $marker_label . ',' . "\n" . '                    fontWeight: 600,' . "\n" . '                    fill: "#35373e",' . "\n\t\t\t\t" . '},' . "\n\t\t\t" . '},' . "\n\t\t\t" . 'labels: {' . "\n" . '                markers: {' . "\n" . '                    render: function (marker) {' . "\n" . '                        return marker.name;' . "\n" . '                    },' . "\n" . '                },' . "\n" . '            },' . "\n" . '            lineStyle: {' . "\n" . '                strokeDasharray: "3 3 3",' . "\n" . '                animation: ' . $animate_lines . ',' . "\n" . '                stroke: "' . $line_stroke . '",' . "\n" . '                strokeWidth: ' . $line_stroke_width . ',' . "\n" . '                ' . $curvature . "\n\t\t\t" . '},' . "\n" . '            onMarkerTooltipShow(event, tooltip, index) {' . "\n" . '                let getMarker = markers' . $moduleId . '[index];' . "\n" . '                if(getMarker && getMarker.tooltip){' . "\n" . '                    let markerHTML = \'<h5 class="fs-15">\' + getMarker.name +\'</h5><p class="mb-0 small">\'+ getMarker.tooltip + \'</p>\';' . "\n" . '                    tooltip.text(markerHTML,true);' . "\n\t\t\t\t" . '}' . "\n" . '                tooltip.css({ ' . "\n" . '                    backgroundColor: "' . $tooltip_bg . '", ' . "\n" . '                    color: "' . $tooltip_color . '" ' . "\n" . '                });' . "\n" . '            },' . "\n" . '            onRegionTooltipShow(event, tooltip, index) {' . "\n" . '                tooltip.css({ ' . "\n" . '                    backgroundColor: "' . $tooltip_bg . '", ' . "\n" . '                    color: "' . $tooltip_color . '" ' . "\n" . '                });' . "\n" . '            }' . "\n" . '        });' . "\n" . '    }, 1500);' . "\n" . '});' . "\n" . '</script>';
        $this->addScript('footer', $pageData['page'], $js);
        return $output;
    }

    private function video_widget(object $content, string|int $moduleId, array $pageData, object $row, bool $isLCPCandidate = false): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $nameWidget = (isset($content->name_widget->{$this->lang}) && $content->name_widget->{$this->lang} ? $content->name_widget->{$this->lang} : array_values((array) $content->name_widget)[0] ?? '');
        $style = '';
        if (($content->name_widget_status == 'yes') && $nameWidget) {
            $style .= '#' . $widgetId . ' .fon-widget-title{';

            if ($content->title_color) {
                $style .= 'color: ' . $content->title_color . ';';
            }

            if ($content->title_margin->top) {
                $style .= 'margin-top: ' . $content->title_margin->top . 'px;';
            }

            if ($content->title_margin->bottom) {
                $style .= 'margin-bottom: ' . $content->title_margin->bottom . 'px;';
            }

            if ($content->title_font) {
                $style .= self::parseFontProperties($content->title_font);
            }

            $style .= '}';
        }
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }

        $output = '';
        $src = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-video-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        if (($content->name_widget_status == 'yes') && $nameWidget) {
            $output .= '<' . $content->heading_selector . ' class="fon-widget-title">';
            $output .= $nameWidget;
            $output .= '</' . $content->heading_selector . '>';
        }

        if ($content->video_source == '2') {
            if ($content->mp4_video) {
                $show_control = (isset($content->show_control) && $content->show_control == 'yes' ? 1 : 0);
                $video_loop = (isset($content->video_loop) && $content->video_loop == 'yes' ? 1 : 0);
                $autoplay_video = (isset($content->autoplay_video) && $content->autoplay_video == 'yes' ? 1 : 0);
                $video_mute = (isset($content->video_mute) && $content->video_mute == 'yes' ? 1 : 0);
                $video_poster = '';

                if (is_object($content->video_poster)) {
                    $video_poster = (isset($content->video_poster->{$this->lang}) && $content->video_poster->{$this->lang} ? $content->video_poster->{$this->lang} : array_values((array) $content->video_poster)[0] ?? '');
                }
                else if (is_string($content->video_poster)) {
                    $video_poster = $content->video_poster;
                }

                $video_poster = ($video_poster ? static::assetLinkDetermine($video_poster) : $lazyPlaceholder);
                $mp4_video = '';

                if (is_object($content->mp4_video)) {
                    $mp4_video = (isset($content->mp4_video->{$this->lang}) && $content->mp4_video->{$this->lang} ? $content->mp4_video->{$this->lang} : array_values((array) $content->mp4_video)[0] ?? '');
                }
                else if (is_string($content->mp4_video)) {
                    $mp4_video = $content->mp4_video;
                }

                $mp4_video = static::assetLinkDetermine($mp4_video);
                $output .= '<div class="fon-widget-video-local-video-wrap">';
                $output .= '<video class="fon-widget-video-local-source"' . ($video_loop != 0 ? ' loop' : '') . '' . ($autoplay_video != 0 ? ' autoplay' : '') . '' . ($show_control != 0 ? ' controls' : '') . '' . ($video_mute ? ' muted' : '') . ' ' . ($video_poster ? 'poster="' . $video_poster . '"' : '') . ' controlsList="nodownload" playsinline>';
                $output .= '<source src="' . $mp4_video . '" type="video/mp4">';
                $output .= '</video>';
                $output .= '</div>';
            }
        }
        else {
            if ($content->video_url) {
                $videoUrl = '';

                if (is_object($content->video_url)) {
                    $videoUrl = (isset($content->video_url->{$this->lang}) && $content->video_url->{$this->lang} ? $content->video_url->{$this->lang} : array_values((array) $content->video_url)[0] ?? '');
                }
                else if (is_string($content->video_url)) {
                    $videoUrl = $content->video_url;
                }

                $video = parse_url($videoUrl);
                $video_title = '';
                $aspect_ratio = '16by9';

                if ($content->video_source == '0') {
                    $no_cookie = (isset($content->no_cookie) && $content->no_cookie == 'yes' ? 1 : 0);
                    $show_rel_video = (isset($content->show_rel_video) && $content->show_rel_video == 'yes' ? '&rel=0' : '&rel=1');
                    $youtube_no_cookie = ($no_cookie ? '-nocookie' : '');
                    $youtube_shorts = (isset($content->youtube_shorts) && $content->youtube_shorts == 'yes' ? 1 : 0);
                    $aspect_ratio = (isset($content->aspect_ratio) && $content->aspect_ratio && $youtube_shorts ? $content->aspect_ratio : '16by9');

                    switch ($video['host']) {
                    case 'www.youtu.be':
                    case 'youtu.be':
                        $id = trim($video['path'], '/');
                        $src = '//www.youtube' . $youtube_no_cookie . '.com/embed/' . $id . '?iv_load_policy=3' . $show_rel_video;
                        $video_title = (isset($content->video_title->{$this->lang}) && $content->video_title->{$this->lang} ? $content->video_title->{$this->lang} : $this->language['widget_video_default_title']);
                        break;
                    case 'www.youtube.com':
                    case 'youtube.com':
                        parse_str($video['query'], $query);
                        $id = ($youtube_shorts ? trim($video['path'], '/shorts/') : $query['v']);
                        $src = '//www.youtube' . $youtube_no_cookie . '.com/embed/' . $id . '?iv_load_policy=3' . $show_rel_video;
                        $video_title = (isset($content->video_title->{$this->lang}) && $content->video_title->{$this->lang} ? $content->video_title->{$this->lang} : $this->language['widget_video_default_title']);
                        break;
                    }
                }
                else if ($content->video_source == '1') {
                    $id = trim($video['path'], '/');
                    $initialSrc = '//player.vimeo.com/video/' . $id;
                    $vimeo_show_author = (isset($content->vimeo_show_author) && $content->vimeo_show_author == 'yes' ? 'byline=1' : 'byline=0');
                    $vimeo_mute_video = (isset($content->vimeo_mute_video) && $content->vimeo_mute_video == 'yes' ? 'muted=1' : 'muted=0');
                    $vimeo_show_video_title = (isset($content->vimeo_show_video_title) && $content->vimeo_show_video_title == 'yes' ? 'title=1' : 'title=0');
                    $vimeo_show_author_profile = (isset($content->vimeo_show_author_profile) && $content->vimeo_show_author_profile == 'yes' ? 'portrait=1' : 'portrait=0');
                    $embeddedParameter = [$vimeo_mute_video, $vimeo_show_author, $vimeo_show_author_profile, $vimeo_show_video_title];
                    $embeddedString = '';
                    $separator = '&';

                    foreach ($embeddedParameter as $key => $value) {
                        $embeddedString .= (0 < $key ? $separator . $value : $value);
                    }

                    $src = $initialSrc . '?' . $embeddedString;
                }
            }

            $output .= '<div class="fon-video-block fon-embed-responsive fon-embed-responsive-' . $aspect_ratio . '">';
            $output .= '<iframe class="fon-embed-responsive-item" src="' . $src . '" ' . ($video_title ? 'title="' . $video_title . '"' : '') . ' allow="accelerometer" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>';
            $output .= '</div>';
        }

        $output .= '</div>';
        $output .= '</div>';
        return $output;
    }

    private function getWidgetProducts(object $content, string|int $moduleId, array $pageData, object $row, string $widgetName): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }
        if (($content->column->xl <= 3) && $content->use_carousel == 'yes') {
            $style .= '@media(min-width:1200px){';
            $style .= '#' . $widgetId . '-tabContent .tab-pane .fon-content-carousel{';
            $style .= 'max-width: 992px;';
            $style .= 'margin-left: auto;';
            $style .= 'margin-right: auto;';
            $style .= '}';
            $style .= '}';
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $carouselData = '';

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-row="no" data-rows="' . htmlspecialchars(Utility::jencode(['xl' => 1, 'lg' => 1, 'md' => 1, 'sm' => 1, 'xs' => 1]), ENT_QUOTES, 'UTF-8') . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '"';
        }

        $widgetStyle = 'default';
        $widgetThemeStyle = Config::get('theme/package_style');
        if (($widgetThemeStyle == '0') || !$widgetThemeStyle) {
            $widgetThemeStyle = 'default';
        }
        if ($content && isset($content->widget_style)) {
            $widgetStyle = $content->widget_style;
        }
        $widgetData = ['pageData' => $pageData, 'widget_name' => $widgetName, 'widget_content' => $content, 'carouselData' => $carouselData, 'currency_symbols' => self::getCurrencySymbols(), 'isWidget' => ($content ? true : false), 'widgetStyle' => $widgetStyle, 'widgetId' => $widgetId, 'row' => $row, 'showCoupon' => (isset($content->show_coupon) && $content->show_coupon == 'yes' ? true : false)];
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-' . $widgetName . '-widget ' . $content->fon_class . ' pricing-widget-style-' . $widgetStyle . '">';
        if (isset($pageData['items']) && $pageData['items'] && $widgetName == $content->page_type && $content->source == 'none') {
            $products = $this->getProductPackages(array_merge($widgetData, $pageData));
            $output .= $products;
        }
        else {
            $output .= '<div class="fon-widget-content">';
            $widgetItems = $this->getWidgetItems('products', $content->source, $widgetName, $content->limit);

            if ($widgetItems) {
                if ($widgetItems['type'] == 'cats') {
                    if (is_array($widgetItems['cats']) && 1 < count($widgetItems['cats'])) {
                        $output .= '<ul class="product-group-tabs nav nav-pills mb-5 justify-content-center" id="' . $widgetId . '-tab" role="tablist">';
                        $i = 0;

                        foreach ($widgetItems['cats'] as $catId => $cat) {
                            if (!empty($widgetItems['items'][$catId])) {
                                $output .= '<li class="nav-item"  role="presentation">';
                                $output .= '<a class="nav-link ' . ($i == 0 ? 'active' : '') . '" id="product-tab-' . $catId . '" data-bs-toggle="tab" href="#product-tab-content-' . $catId . '" role="tab" aria-controls="product-tab-content-' . $catId . '" aria-selected="' . ($i == 0 ? 'true' : 'false') . '">';
                                if (isset($cat['options']['icon']) && $cat['options']['icon']) {
                                    $output .= '<i class="' . $cat['options']['icon'] . '"></i> ';
                                }
                                else if (isset($cat['icon']) && $cat['icon']) {
                                    $img_path = 'resources' . DS . 'uploads' . DS . 'category-icon' . DS . $cat['icon'];

                                    if (file_exists($img_path)) {
                                        $output .= '<img class="d-inline me-2" src="' . static::assetLinkDetermine($img_path) . '" width="25" height="25" alt="' . $cat['title'] . '"> ';
                                    }
                                }

                                $output .= $cat['title'];
                                $output .= '</a>';
                                $output .= '</li>';
                                ++$i;
                            }
                        }

                        $output .= '</ul>';
                    }

                    $output .= '<div class="tab-content product-group-tabs-content" id="' . $widgetId . '-tabContent">';
                    $i = 0;

                    foreach ($widgetItems['items'] as $catId => $items) {
                        if (!empty($widgetItems['items'][$catId])) {
                            if (is_array($widgetItems['cats']) && 1 < count($widgetItems['cats'])) {
                                $output .= '<div class="tab-pane fade ' . ($i == 0 ? 'show active' : '') . '" id="product-tab-content-' . $catId . '" role="tabpanel" aria-labelledby="product-tab-' . $catId . '" tabindex="0">';
                            }

                            $products = $this->getPackagesList($widgetItems['items'][$catId], $widgetItems['cats'][$catId], $widgetData);
                            $output .= $products;
                            if (isset($content->show_all_link) && $content->show_all_link == 'yes') {
                                $output .= '<p class="text-center my-2">' . __('theme/all-products-link', ['{group_link}' => self::parseCanonicalUrl(Controllers::$init->CRLink('products', [$widgetItems['cats'][$catId]['route']])), '{group_title}' => $widgetItems['cats'][$catId]['title']]) . '</p>';
                            }
                            if (is_array($widgetItems['cats']) && 1 < count($widgetItems['cats'])) {
                                $output .= '</div>';
                            }

                            ++$i;
                        }
                    }

                    $output .= '</div>';
                }
                else {
                    foreach ($widgetItems['items'] as $item_key => $item) {
                        if ($item['type'] != 'sms') {
                            $category = $this->getCategory($item['category'], 'products', $item['type']);

                            if ($category) {
                                $widgetItems['items'][$item_key]['category'] = $category;
                            }
                        }
                    }

                    $products = $this->getPackagesList($widgetItems['items'], [], $widgetData);
                    $output .= $products;
                    if (isset($content->show_all_link) && $content->show_all_link == 'yes' && $widgetName != 'special') {
                        $output .= '<p class="text-center my-2">' . __('theme/all-products-link', ['{group_link}' => self::parseCanonicalUrl(Controllers::$init->CRLink('products', [$widgetName])), '{group_title}' => $widgetName]) . '</p>';
                    }
                }
            }

            $output .= '</div>';
        }

        $output .= '</div>';
        return $output;
    }

    private function getWidgetPages(object $content, string|int $moduleId, array $pageData, string $widgetName): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $style = '';
        if (isset($content->css_internal) && $content->css_internal) {
            $style .= str_replace('@widgetId', '#' . $widgetId, $content->css_internal);
        }

        if ($style) {
            $this->addStyle($pageData['page'], $style);
        }
        $isCarousel = (isset($content->use_carousel) && $content->use_carousel == 'yes' ? true : false);
        $carouselData = '';

        if ($isCarousel) {
            $this->addAsset('slick');
            $carouselData = 'data-pagination="' . $content->pagination . '" data-arrows="' . $content->arrows . '" data-autoplay="' . $content->autoplay . '" data-pause="' . $content->hoverpause . '" data-loop="' . $content->loop . '" data-columns="' . htmlspecialchars(Utility::jencode($content->column, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '" data-row="' . $content->use_row . '" data-rows="' . htmlspecialchars(Utility::jencode($content->row, JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8') . '"  id="carousel-' . $widgetId . '"';
        }

        $widgetData = ['name' => $widgetName, 'content' => $content, 'currency_symbols' => self::getCurrencySymbols(), 'carouselData' => $carouselData, 'isWidget' => ($content ? true : false), 'badress' => $pageData['badress']];
        $output = '';
        $output .= '<div id="' . $widgetId . '" class="fon-widget-container fon-' . $widgetName . '-widget ' . $content->fon_class . '">';
        $output .= '<div class="fon-widget-content">';
        $widgetItems = $this->getWidgetItems('pages', $content->sources, $widgetName, $content->limit);
        $oneCategoryForAllLink = [];

        if ($widgetItems) {
            if ($widgetItems['type'] == 'cats') {
                if (1 < count($widgetItems['cats'] ?? [])) {
                    $output .= '<ul class="product-group-tabs nav nav-pills mb-3 justify-content-center" id="' . $widgetId . '-tab" role="tablist">';
                    $i = 0;

                    foreach ($widgetItems['cats'] as $catId => $cat) {
                        $output .= '<li class="nav-item"  role="presentation">';
                        $output .= '<a class="nav-link ' . ($i == 0 ? 'active' : '') . '" id="product-tab-' . $catId . '" data-bs-toggle="tab" href="#product-tab-content-' . $catId . '" role="tab" aria-controls="product-tab-content-' . $catId . '" aria-selected="' . ($i == 0 ? 'true' : 'false') . '">';
                        if (isset($cat['options']['icon']) && $cat['options']['icon']) {
                            $output .= '<i class="' . $cat['options']['icon'] . '"></i> ';
                        }
                        else if (isset($cat['icon']) && $cat['icon']) {
                            $output .= '<img class="d-inline me-2" src="' . $cat['icon'] . '" width="25" height="25" alt="' . $cat['title'] . '"> ';
                        }

                        $output .= $cat['title'];
                        $output .= '</a>';
                        $output .= '</li>';
                        ++$i;
                    }

                    $output .= '</ul>';
                }

                $output .= '<div class="tab-content product-group-tabs-content" id="' . $widgetId . '-tabContent">';
                $i = 0;

                foreach ($widgetItems['items'] as $catId => $items) {
                    if (1 < count($widgetItems['cats'] ?? [])) {
                        $output .= '<div class="tab-pane fade ' . ($i == 0 ? 'show active' : '') . '" id="product-tab-content-' . $catId . '" role="tabpanel" aria-labelledby="product-tab-' . $catId . '" tabindex="0">';
                    }

                    $oneCategoryForAllLink = $widgetData['category'] = $widgetItems['cats'][$catId];
                    $pages = $this->getPageList($widgetItems['items'][$catId], $widgetData);
                    $output .= $pages;

                    if (1 < count($widgetItems['cats'] ?? [])) {
                        $output .= '</div>';
                    }

                    ++$i;
                }

                $output .= '</div>';
            }
            else {
                foreach ($widgetItems['items'] as $item_key => $item) {
                    if ($item['type'] != 'news') {
                        $oneCategoryForAllLink = $category = $this->getCategory($item['category'], $item['type']);

                        if ($category) {
                            $widgetItems['items'][$item_key]['category'] = $category;
                        }
                    }
                }

                $pages = $this->getPageList($widgetItems['items'], $widgetData);
                $output .= $pages;
            }
        }

        $output .= '</div>';
        if (isset($content->show_all_link) && $content->show_all_link == 'yes') {
            $CRLinkType = ($widgetName == 'software' ? 'softwares' : $widgetName);
            $allLink = Controllers::$init->CRLink($CRLinkType);
            if (($widgetItems['type'] == 'cats') && count($widgetItems['cats']) == 1) {
                $allLink = self::parseCanonicalUrl(Controllers::$init->CRLink($CRLinkType . '_category', [$oneCategoryForAllLink['route']]));
            }

            $output .= '<p class="text-center">' . __('theme/all-' . $widgetName . '-link', ['{page_link}' => $allLink]) . '</p>';
        }

        $output .= '</div>';
        return $output;
    }

    private function getWidgetItems(string $type, array|string $source, string $kind = '', int $limit = 10): array
    {
        $sourceItems = ($source != 'none' ? explode(': ', $source) : []);
        $sourceType = ($sourceItems ? $sourceItems[0] : '');
        $sourceIds = (($source != 'none') && $sourceItems ? explode(',', $sourceItems[1]) : $source);
        $result = ['type' => $sourceType];

        if ($sourceType == 'cats') {
            foreach ($sourceIds as $sourceId) {
                if ($sourceId == 'none') {
                    $result['cats'][$sourceId] = [];
                    $result['items'][$sourceId] = ($type == 'products' ? $this->getProducts($kind, $sourceId, $limit, true) : $this->getPages($kind, $sourceId, $limit, true));
                }
                else {
                    $category = ($type == 'products' ? $this->getCategory($sourceId, $type) : $this->getCategory($sourceId, $kind));

                    if ($category) {
                        $result['cats'][$category['id']] = $category;
                        $result['items'][$category['id']] = ($type == 'products' ? $this->getProducts($kind, $category['id'], $limit, true) : $this->getPages($kind, $category['id'], $limit, true));
                    }
                }
            }
        }
        else {
            $result['items'] = ($type == 'products' ? $this->getProducts($kind, $sourceIds, $limit, true) : $this->getPages($kind, $sourceIds, $limit, true));
        }

        return $result;
    }

    private function getPageList(array $list, array $data): string
    {
        $lazyPlaceholder = static::getLazyPlaceholder();
        $enableLazyLoading = Config::get('theme/enable_lazy_loading');
        $output = '';

        if ($list) {
            if ($data['carouselData']) {
                $containerClass = 'fon-content-carousel ' . $data['name'] . '-carousel';
            }
            else {
                $containerClass = 'row row-cols-' . $data['content']->column->xs . ' row-cols-sm-' . $data['content']->column->sm . ' row-cols-md-' . $data['content']->column->md . ' row-cols-lg-' . $data['content']->column->lg . ' row-cols-xl-' . $data['content']->column->xl;
            }

            $output .= '<div class="' . $containerClass . ' ' . $data['name'] . '-style-' . $data['content']->widget_style . ' ' . $data['name'] . '-items-container" ' . $data['carouselData'] . '>';

            foreach ($list as $item) {
                if (isset($data['category']) && is_int($item['category'])) {
                    $item['category'] = $data['category'];
                }

                $item['route'] = self::getItemLink($item['type'], $item['route'], false);

                if ($item['cover_image']) {
                    if ($item['type'] == 'software') {
                        $image_path = 'resources' . DS . 'uploads' . DS . $item['type'] . DS . $item['cover_image'];
                    }
                    else {
                        $image_path = 'resources' . DS . 'uploads' . DS . $item['type'] . DS . 'thumb' . DS . $item['cover_image'];
                    }
                }
                else if ($item['type'] == 'software') {
                    $image_path = 'resources' . DS . 'uploads' . DS . $item['type'] . DS . 'list-image-default.jpg';
                }
                else {
                    $image_path = 'resources' . DS . 'uploads' . DS . $item['type'] . DS . 'default.jpg';
                }

                $imageDimensions = NULL;

                if (file_exists($image_path)) {
                    $item['cover_image'] = $item['image'] = static::assetLinkDetermine($image_path);
                    $imageDimensions = static::getImageDimensions($image_path, $data['badress']);
                }

                $item['short_title'] = Utility::short_text(Filter::html_clear($item['title']), 0, 50, true);
                $item['short_content'] = Utility::short_text(Filter::html_clear($item['content']), 0, $data['content']->intro_text_limit ?? 100, true);
                $item['ctime'] = ($data['isWidget'] ? DateManager::format(Config::get('options/date-format'), $item['ctime']) : $item['ctime']);

                if ($item['type'] != 'news') {
                    $item['category_name'] = (isset($item['category']['title']) && $item['category']['title'] ? $item['category']['title'] : '');
                    $item['category_route'] = (isset($item['category']['route']) && $item['category']['route'] ? self::getItemLink($item['type'], $item['category']['route'], true) : '');
                }

                if ($item['type'] == 'software') {
                    if (isset($item['prices']) && $item['prices']) {
                        $item['price'] = self::calculatePrices($item['prices'], $data['currency_symbols'], $item['override_usrcurrency'], $item['type']);
                    }

                    $item['popular'] = false;
                    if (isset($item['options']['popular']) && $item['options']['popular']) {
                        $item['popular'] = true;
                    }

                    $item['buy_link'] = Controllers::$init->CRLink('order-steps', ['software', $item['id']]);
                    if (isset($item['options']['external_link']) && $item['options']['external_link'] != '') {
                        $item['buy_link'] = $item['options']['external_link'];
                    }
                    else if (isset($item['optionsl']['external_link']) && $item['optionsl']['external_link'] != '') {
                        $item['buy_link'] = $item['optionsl']['external_link'];
                    }
                }
                else if (($item['type'] == 'references') || $item['type'] == 'reference') {
                    $options = (isset($item['options']) && $item['options'] ? Utility::jdecode($item['options'], true) : []);
                    $item['category_name'] = (isset($item['category']['title']) && $item['category']['title'] ? $item['category']['title'] : '');
                    $item['category_route'] = (isset($item['category']['route']) && $item['category']['route'] ? self::getItemLink($item['type'], $item['category']['route'], true) : '');
                    $item['website'] = (isset($options['website']) ? $options['website'] : false);
                    $item['image'] = $item['cover_image'];
                }
                $output .= '<div class="col ' . $item['type'] . ' style-' . $data['content']->widget_style . ' ' . (isset($item['popular']) && $item['popular'] ? 'popular' : '') . '">';

                if ($data['carouselData']) {
                    $output .= '<div class="fon-content-carousel-item">';
                }

                include __DIR__ . DS . 'builder' . DS . 'page-styles' . DS . $item['type'] . DS . 'style_' . $data['content']->widget_style . '.php';

                if ($data['carouselData']) {
                    $output .= '</div>';
                }

                $output .= '</div>';
            }

            $output .= '</div>';
        }

        return $output;
    }

    public function getProductPackages(array $pageData, bool $isGsd = false, bool $forSelection = false): mixed
    {
        $output = '';
        $selectedCategory = [];
        $category = $pageData['items']['category'];
        $category2 = $pageData['items']['category2'];
        $showCategory = $pageData['items']['showCategory'];
        if (isset($pageData['items']) && $pageData['items']) {
            if (isset($pageData['widget_content']->show_cat_info) && $pageData['widget_content']->show_cat_info == 'yes') {
                $pageTitle = '';
                $pageDescription = '';

                if (isset($pageData['page'])) {
                    switch ($pageData['page']) {
                    case 'hosting':
                        $pageTitle = ___('constants/category-hosting/title');
                        $pageDescription = ___('constants/category-hosting/sub_title');
                        break;
                    case 'server':
                        $pageTitle = ___('constants/category-server/title');
                        $pageDescription = ___('constants/category-server/sub_title');
                        break;
                    case 'sms':
                        $pageTitle = ___('constants/category-sms/title');
                        $pageDescription = ___('constants/category-sms/sub_title');
                        break;
                    case 'software':
                        $pageTitle = ___('constants/category-software/title');
                        $pageDescription = ___('constants/category-software/sub_title');
                        break;
                    case 'special':
                        $pageTitle = ___('constants/category-software/title');
                        $pageDescription = ___('constants/category-software/sub_title');
                        break;
                    }
                }

                if (0 < $pageData['items']['showCategory']['id']) {
                    $pageTitle = $pageData['items']['showCategory']['title'];
                    $pageDescription = $pageData['items']['showCategory']['sub_title'];
                }

                $output .= '<div class="fon-section-title text-center">';
                $output .= '<h2 class="fon-section-title-heading">' . $pageTitle . '</h2>';
                $output .= '<p class="fon-section-title-subheading">' . $pageDescription . '</p>';
                $output .= '</div>';
            }
        }

        if (!$category2) {
            $list = $pageData['functions']['get_list']($showCategory['id'], $showCategory['kind']);
            $gsd = ['list' => $list, 'cat' => $showCategory['id']];
            $output .= $this->getPackagesList($list, $showCategory, $pageData);
        }

        $categories = $pageData['functions']['get_categories']($category['id'], $category['kind']);

        if ($categories) {
            $catSize = count($categories);
            $category_products = [];
            $categories_list = [];
            $selection = ($category2 ? $showCategory : false);
            $showCategoryList = true;
            if ($pageData['isWidget'] && isset($pageData['widget_content']->show_other_cats)) {
                if ($pageData['widget_content']->show_other_cats == 'no') {
                    $showCategoryList = false;
                }
            }
            $output .= '<ul class="product-group-tabs nav nav-pills mb-4 justify-content-center ' . (($catSize == 1) || !$showCategoryList ? 'd-none' : '') . '" role="tablist">';

            foreach ($categories as $k => $cat) {
                $list = $pageData['functions']['get_list']($cat['id'], $cat['kind']);
                $subs = $pageData['functions']['get_categories']($cat['id'], $cat['kind']);
                $category_products[$cat['id']] = $list;
                $categories_list[$cat['id']] = $subs;
                if (!$list && !$subs) {
                    continue;
                }

                $selected = false;

                if ($list) {
                    $cat['route'] = $pageData['functions']['category_tab_route']($cat['route']);
                }
                else {
                    $cat['route'] = Controllers::$init->CRLink('products', [$cat['route']]);
                }

                if ($category['id']) {
                    if (!$selection && $k == 0) {
                        $selection = $cat;
                    }
                    if ($selection && $cat['id'] == $selection['id']) {
                        $selected = true;
                    }
                }
                else if ($category2 && $category2['id'] == $cat['id']) {
                    $selected = true;
                    $selection = $cat;
                }
                else if (!$selection && $category_products[$cat['id']] && $k == 0) {
                    $selected = true;
                    $selection = $cat;
                }
                else if (!$selection && $k == 0) {
                    $category = $cat;
                    $selected = true;
                    $selection = $cat;
                }

                $categoryTarget = $cat['route'];
                if (isset($pageData['row']->row_section_id) && $pageData['row']->row_section_id) {
                    $categoryTarget .= '#' . $pageData['row']->row_section_id;
                }
                else if (isset($pageData['row']->text_class_id) && $pageData['row']->text_class_id) {
                    $categoryTarget .= '#' . $pageData['row']->text_class_id;
                }

                $output .= '<li class="nav-item"  role="presentation"><a href="' . $categoryTarget . '" class="nav-link ' . ($selected ? 'active' : '') . '">';
                if (isset($cat['options']['icon']) && $cat['options']['icon']) {
                    $output .= '<i class="' . $cat['options']['icon'] . '"></i> ';
                }
                else if (isset($cat['icon']) && $cat['icon']) {
                    $output .= '<img class="d-inline me-2" src="' . $cat['icon'] . '" width="25" height="25" alt="' . $cat['title'] . '"> ';
                }

                $output .= $cat['title'];
                $output .= '</a></li>';
            }

            $output .= '</ul>';
        }
        if (isset($selection) && $selection) {
            if (isset($category_products[$selection['id']])) {
                $list = $category_products[$selection['id']];
                $selectedCategory = ['category' => $selection, 'products' => $list];
                $gsd = ['list' => $list, 'cat' => $selection['id']];
                $output .= $this->getPackagesList($list, $selection, $pageData);

                if ($category['id']) {
                    $categories = (isset($categories_list[$selection['id']]) ? $categories_list[$selection['id']] : false);

                    if ($categories) {
                        if ($pageData['page'] != 'hosting') {
                            $subCatSize = count($categories);
                        }

                        if (isset($subCatSize)) {
                            $output .= '<div class="fon-accordion-widget style-4">';
                            $output .= '<div class="accordion" id="subCatAccordion">';
                        }

                        foreach ($categories as $cK => $cat) {
                            $list = $pageData['functions']['get_list']($cat['id'], $cat['kind']);
                            $catIcon = ($cat['icon'] || isset($cat['options']['icon']) && $cat['options']['icon'] ? true : false);

                            if ($list) {
                                $gsd = ['list' => $list, 'cat' => $cat['id']];

                                if (isset($subCatSize)) {
                                    $output .= '<div class="accordion-item ' . ($catIcon ? 'with-icon' : 'no-icon') . '">';
                                    $output .= '<h5 class="accordion-header">';
                                    $output .= '<button class="accordion-button ' . ($cK == 0 ? '' : 'collapsed') . '" type="button" data-bs-toggle="collapse" data-bs-target="#subcat-' . $cat['kind'] . '-' . $cat['id'] . '" aria-expanded="' . ($cK == 0 ? 'true' : 'false') . '" aria-controls="subcat-' . $cat['kind'] . '-' . $cat['id'] . '">';

                                    if ($catIcon) {
                                        $output .= '<span class="accordion-icon me-1">';

                                        if ($cat['icon']) {
                                            $output .= '<img class="d-inline" src="' . $cat['icon'] . '" width="25" height="25" alt="' . $cat['title'] . '"> ';
                                        }
                                        else if (isset($cat['options']['icon']) && $cat['options']['icon']) {
                                            $output .= '<i class="' . $cat['options']['icon'] . '"></i> ';
                                        }

                                        $output .= '</span>';
                                    }
                                    else {
                                        $output .= '<span class="accordion-icon me-1"><i class="fa-solid fa-server"></i></span>';
                                    }

                                    $output .= $cat['title'];
                                    $output .= '</button>';
                                    $output .= '</h5>';
                                    $output .= '<div id="subcat-' . $cat['kind'] . '-' . $cat['id'] . '" class="accordion-collapse collapse ' . ($cK == 0 ? 'show' : '') . '" data-bs-parent="#subCatAccordion">';
                                    $output .= '<div class="accordion-body">';
                                }

                                $output .= $this->getPackagesList($list, $cat, $pageData);

                                if (isset($subCatSize)) {
                                    $output .= '</div>';
                                    $output .= '</div>';
                                    $output .= '</div>';
                                }
                            }
                        }

                        if (isset($subCatSize)) {
                            $output .= '</div>';
                            $output .= '</div>';
                        }
                    }
                }
            }
        }

        if ($isGsd) {
            return $gsd ?? [];
        }
        else if ($forSelection) {
            return $selectedCategory;
        }
        else {
            return $output;
        }
    }

    public function getPackagesList(array $list, array $cat, array $widgetData = []): string
    {
        Helper::Load('Image');
        $widgetData['currency_symbols'] = self::getCurrencySymbols();
        if (!isset($widgetData['currency_map']) || !is_array($widgetData['currency_map']) || !$widgetData['currency_map']) {
            $widgetData['currency_map'] = [];

            foreach (Money::getCurrencies() as $cr) {
                $widgetData['currency_map'][$cr['id']] = $cr['code'];
            }
        }
        if (!isset($widgetData['percent_formatter']) || !($widgetData['percent_formatter'] instanceof NumberFormatter)) {
            $localeLangCode = (Language::selected() == 'tr' ? 'tr_TR' : 'en_US');
            $widgetData['percent_formatter'] = new NumberFormatter($localeLangCode, NumberFormatter::PERCENT);
        }

        $output = '';
        $showDetailLink = (isset($widgetData['widget_content']->show_detail_link) && $widgetData['widget_content']->show_detail_link == 'yes' ? true : false);
        $detailLinkType = (isset($widgetData['widget_content']->detail_link_type) ? $widgetData['widget_content']->detail_link_type : 'category');

        if (isset($widgetData['widget_content']->detail_link)) {
            $detailLinkUrl = (isset($widgetData['widget_content']->detail_link->{$this->lang}) ? $widgetData['widget_content']->detail_link->{$this->lang} : array_values((array) $widgetData['widget_content']->detail_link)[0] ?? '');
        }
        else {
            $detailLinkUrl = '';
        }

        if (isset($widgetData['widget_content']->detail_link_text)) {
            $detailLinkText = (isset($widgetData['widget_content']->detail_link_text->{$this->lang}) ? $widgetData['widget_content']->detail_link_text->{$this->lang} : array_values((array) $widgetData['widget_content']->detail_link_text)[0] ?? '');
        }
        else {
            $detailLinkText = '';
        }
        $detailLinkTarget = (isset($widgetData['widget_content']->detail_link_target) && $widgetData['widget_content']->detail_link_target ? $widgetData['widget_content']->detail_link_target : '_self');
        $widgetStyle = $widgetData['widgetStyle'] ?? (Config::get('theme/package_style') == '0' ? 'default' : Config::get('theme/package_style'));
        $showCoupon = $widgetData['showCoupon'] ?? false;
        $show_price_type = (isset($widgetData['widget_content']->show_price_type) && $widgetData['widget_content']->show_price_type ? $widgetData['widget_content']->show_price_type : 'default');

        if ($show_price_type == 'yes') {
            $show_price_type = 'month_year';
        }

        $price_calc = $widgetData['widget_content']->price_calc ?? 'default';
        $show_free_label = !isset($widgetData['widget_content']->show_free_label) || $widgetData['widget_content']->show_free_label == 'yes';
        $free_label_text = self::getFieldMultilingualText($widgetData['widget_content']->free_label_text ?? NULL, $this->lang, __('theme/is_free'));
        if ($show_free_label && empty($free_label_text)) {
            $free_label_text = __('theme/is_free');
        }
        $card_button_action_on_free = (isset($widgetData['widget_content']->card_button_action_on_free) && $widgetData['widget_content']->card_button_action_on_free ? $widgetData['widget_content']->card_button_action_on_free : 'default');
        $enable_custom_card_button_label = isset($widgetData['widget_content']->enable_custom_card_button_label) && $widgetData['widget_content']->enable_custom_card_button_label == 'yes';
        $custom_card_button_label = self::getFieldMultilingualText($widgetData['widget_content']->custom_card_button_label ?? NULL, $this->lang, __('website/index/add-basket-button'));
        $productType = (isset($widgetData['widget_name']) ? $widgetData['widget_name'] : $widgetData['page'] ?? 'default');
        $containerId = ($widgetData['widgetId'] ? $widgetData['widgetId'] . ($cat ? '-' . $cat['id'] : '') : 'product-package-container-' . ($cat ? '-' . $cat['id'] : ''));
        $widgetType = ($widgetData['isWidget'] && isset($widgetData['widget_content']->display) ? $widgetData['widget_content']->display : (isset($cat['options']['list_template']) && $cat['options']['list_template'] == 2 ? 'table' : 'box'));
        $showLocation = (isset($widgetData['widget_content']->show_location) && $widgetData['widget_content']->show_location == 'yes' ? true : false);
        $showFirstLocation = (isset($widgetData['widget_content']->first_location) && $widgetData['widget_content']->first_location == 'yes' ? true : false);
        $showFilters = (isset($widgetData['widget_content']->show_filters) && $widgetData['widget_content']->show_filters == 'yes' ? true : false);
        $enabledFilters = (isset($widgetData['widget_content']->enabled_filters) && $widgetData['widget_content']->enabled_filters ? $widgetData['widget_content']->enabled_filters : ['processor', 'ram', 'disk-space', 'location']);

        if ($showLocation) {
            $showFilters = true;
        }

        $locations = [];
        $periods = [];
        $serverOptions = [];
        if (($cat['kind'] == 'server') || $productType == 'server') {
            $this->addAsset('flags');
        }

        if ($list) {
            if ($widgetType == 'table') {
                if ($cat['kind'] == 'special') {
                    $columns = (isset($cat['options_lang']['columns']) ? $cat['options_lang']['columns'] : []);
                }

                $output .= '<div class="horizontal-pricing-table-container">';
                if ((($show_price_type != 'default') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) || $showFilters && $productType == 'server') {
                    $output .= '<div class="pricing-filter-container text-center mb-' . ($show_price_type == 'all_select' ? '5' : '3') . ' ' . $show_price_type . ' d-flex ' . ($showFilters && $productType == 'server' ? 'flex-column' : '') . ' align-items-center justify-content-center gap-3">';
                    if (($show_price_type == 'month_year') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) {
                        $output .= '<div class="pricing-period-swithcer mb-0" data-id="' . $containerId . '"><input id="monthly-package-price' . $containerId . '" class="monthly-package-price" type="radio" name="switch' . $containerId . '" checked="checked"><input id="yearly-package-price' . $containerId . '" class="yearly-package-price" type="radio" name="switch' . $containerId . '"><label class="monthly-package-price-label" for="monthly-package-price' . $containerId . '">' . ___('date/period-month') . '</label><label class="yearly-package-price-label" for="yearly-package-price' . $containerId . '">' . ___('date/period-year') . '</label><span class="package-prices-highlighter"></span></div>';
                    }
                    else if (($show_price_type == 'all_filter') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) {
                        foreach ($list as $sk => $sp) {
                            foreach ($sp['prices'] as $spkey => $spprice) {
                                $periods[$spkey] = $spprice['time'] . ' ' . ___('date/period-' . $spprice['period']);
                            }
                        }
                        if ($periods && 1 < count($periods)) {
                            $output .= '<div class="pricing-period-filter" data-id="#' . $containerId . '">';
                            $i = 0;

                            foreach ($periods as $spkey => $spperiod) {
                                $output .= '<input id="package-filter-price-' . $containerId . '-' . $spkey . '" class="package-filter-price-' . $spkey . '" type="radio" name="switch' . $containerId . '" ' . ($i == 0 ? 'checked="checked"' : '') . '>';
                                $output .= '<label class="package-filter-price-label-' . $spkey . '" for="package-filter-price-' . $containerId . '-' . $spkey . '">' . $spperiod . '</label>';
                                ++$i;
                            }

                            $output .= '</div>';
                        }
                    }
                    if ($showFilters && $productType == 'server') {
                        $this->addAsset('select2');
                        $output .= '<div class="server-filter-container row g-2 align-items-center justify-content-center">';

                        foreach ($list as $sk => $sp) {
                            if (isset($sp['options'])) {
                                $serverOptions[] = $sp['options'];
                            }
                        }
                        if ($serverOptions && 1 < count($serverOptions)) {
                            $serverProcessors = [];
                            $serverRams = [];
                            $serverDisks = [];
                            $serverBandwidths = [];
                            $serverRaids = [];

                            foreach ($serverOptions as $pkg) {
                                if (isset($pkg['processor'])) {
                                    $serverProcessors[] = $pkg['processor'];
                                }

                                if (isset($pkg['ram'])) {
                                    $serverRams[] = $pkg['ram'];
                                }

                                if (isset($pkg['disk-space'])) {
                                    $serverDisks[] = $pkg['disk-space'];
                                }

                                if (isset($pkg['bandwidth'])) {
                                    $serverBandwidths[] = $pkg['bandwidth'];
                                }

                                if (isset($pkg['raid'])) {
                                    $serverRaids[] = $pkg['raid'];
                                }
                            }

                            $serverProcessors = array_unique($serverProcessors);
                            $serverRams = array_unique($serverRams);
                            $serverDisks = array_unique($serverDisks);
                            $serverBandwidths = array_unique($serverBandwidths);
                            $serverRaids = array_unique($serverRaids);
                            sort($serverProcessors);
                            sort($serverRams);
                            sort($serverDisks);
                            sort($serverBandwidths);
                            sort($serverRaids);
                            $filtersCounts = 0;
                            if ($serverProcessors && 1 < count($serverProcessors) && in_array('processor', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-processor" class="form-select select-filter processor-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-cpu-label="' . __('website/products/server-list-processor') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-processor') . '</option>';

                                foreach ($serverProcessors as $serverProcessor) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverProcessor)) . '">' . htmlspecialchars($serverProcessor) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverRams && 1 < count($serverRams) && in_array('ram', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-ram" class="form-select select-filter ram-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-ram-label="' . __('website/products/server-list-ram') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-ram') . '</option>';

                                foreach ($serverRams as $serverRam) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverRam)) . '">' . htmlspecialchars($serverRam) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverDisks && 1 < count($serverDisks) && in_array('disk-space', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-disk" class="form-select select-filter disk-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-disk-label="' . __('website/products/server-list-disk') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-disk') . '</option>';

                                foreach ($serverDisks as $serverDisk) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverDisk)) . '">' . htmlspecialchars($serverDisk) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverBandwidths && 1 < count($serverBandwidths) && in_array('bandwidth', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-bandwidth" class="form-select select-filter bandwidth-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-bandwidth-label="' . __('website/products/server-list-bandwidth') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-bandwidth') . '</option>';

                                foreach ($serverBandwidths as $serverBandwidth) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverBandwidth)) . '">' . htmlspecialchars($serverBandwidth) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverRaids && 1 < count($serverRaids) && in_array('raid', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-raid" class="form-select select-filter raid-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-raid-label="' . __('website/products/server-list-raid') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-raid') . '</option>';

                                foreach ($serverRaids as $serverRaid) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverRaid)) . '">' . htmlspecialchars($serverRaid) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }

                            foreach ($list as $sk => $sp) {
                                if (isset($sp['options_lang']['location']) && !in_array($sp['options_lang']['location'], $locations)) {
                                    $locations[] = $sp['options_lang']['location'];
                                }
                            }
                            if ($locations && 1 < count($locations) && in_array('location', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-location" class="form-select location-filter select-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-location-label="' . __('theme/server_location') . '">';

                                if (!$showFirstLocation) {
                                    $output .= '<option value="">' . __('theme/server_location') . '</option>';
                                }

                                foreach ($locations as $location) {
                                    $country = $code = NULL;

                                    if (strpos($location, '-') !== false) {
                                        $parts = explode('-', $location);
                                        $country = $parts[0];
                                        $code = end($parts);
                                    }
                                    else {
                                        $country = $location;
                                        $code = NULL;
                                    }

                                    if (!empty($code)) {
                                        $code = mb_convert_encoding((string) $code, 'UTF-8', 'UTF-8');
                                    }

                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($location)) . '" data-flag="' . strtolower(htmlspecialchars($code)) . '">' . $country . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($filtersCounts && 2 <= $filtersCounts) {
                                $output .= '<div class="col btn-clear-filters" style="display: none;"><button type="button" class="btn btn-danger"><i class="fa-solid fa-times" title="' . __('theme/clear_filters') . '"></i></button></div>';
                            }
                        }

                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }

                $output .= '<div id="' . $containerId . '" class="fon-pricing-tables">';
                $productCards = [];

                foreach ($list as $k => $product) {
                    $product['order_image'] = Image::picture('product', $product['id'], 'order');
                    $opt = $product['options'];
                    $optl = $product['options_lang'];
                    $p_n = 0;
                    $prices = (!isset($product['prices']) ? [] : $product['prices']);
                    $productPrice = self::calculatePrices($prices, $widgetData['currency_symbols'], $product['override_usrcurrency'], $productType, $show_price_type, $price_calc);
                    $columnCount = (isset($columns) && $columns ? 3 + count($columns) : 8);

                    if (!isset($product['buy_link'])) {
                        if (isset($optl['external_link']) && $optl['external_link'] != '') {
                            $buy_link = $optl['external_link'];
                        }
                        else if (isset($product['optionsl']['external_link']) && $product['optionsl']['external_link'] != '') {
                            $buy_link = $product['optionsl']['external_link'];
                        }
                        else if (isset($product['options']['external_link']) && $product['options']['external_link'] != '') {
                            $buy_link = $product['options']['external_link'];
                        }
                        else {
                            $buy_link = Controllers::$init->CRLink('order-steps', [($cat ? $cat['kind'] : $product['type']), $product['id']]);
                        }
                    }
                    else if (isset($optl['external_link']) && $optl['external_link'] != '') {
                        $buy_link = $optl['external_link'];
                    }
                    else if (isset($product['optionsl']['external_link']) && $product['optionsl']['external_link'] != '') {
                        $buy_link = $product['optionsl']['external_link'];
                    }
                    else if (isset($product['options']['external_link']) && $product['options']['external_link'] != '') {
                        $buy_link = $product['options']['external_link'];
                    }
                    else {
                        $buy_link = $product['buy_link'];
                    }

                    $buy_button_name = __('website/index/add-basket-button');
                    if (isset($optl['buy_button_name']) && $optl['buy_button_name'] != '') {
                        $buy_button_name = $optl['buy_button_name'];
                    }
                    else if (isset($product['optionsl']['buy_button_name']) && $product['optionsl']['buy_button_name'] != '') {
                        $buy_button_name = $product['optionsl']['buy_button_name'];
                    }
                    else if (isset($product['options']['buy_button_name']) && $product['options']['buy_button_name'] != '') {
                        $buy_button_name = $product['options']['buy_button_name'];
                    }
                    else if ($enable_custom_card_button_label && !empty($custom_card_button_label)) {
                        $buy_button_name = $custom_card_button_label;
                    }

                    $columnWidth = 100 / $columnCount;

                    if (!empty($cat)) {
                        $catTitle = $cat['title'];
                        $pattern = '/^(http:\\/\\/|https:\\/\\/)/';

                        if (preg_match($pattern, $cat['route'])) {
                            $catRoute = $cat['route'];
                        }
                        else {
                            $catRoute = Controllers::$init->CRLink('products', [$cat['route']]);
                        }
                    }
                    else if (is_array($product['category']) && $product['category']) {
                        $catTitle = $product['category']['title'];
                        $pattern = '/^(http:\\/\\/|https:\\/\\/)/';

                        if (preg_match($pattern, $product['category']['route'])) {
                            $catRoute = $product['category']['route'];
                        }
                        else {
                            $catRoute = Controllers::$init->CRLink('products', [$product['category']['route']]);
                        }
                    }
                    else {
                        $catRoute = '';
                        $catTitle = '';
                    }
                    if (isset($widgetData['items']) && $widgetData['items'] && 0 < (int) $widgetData['items']['showCategory']['id']) {
                        $catRoute = '';
                    }
                    if (isset($product['features']) && $product['features']) {
                        $productFeatures = (self::isJSON($product['features']) ? Utility::jdecode($product['features'], true) : $product['features']);
                    }

                    ob_start();
                    include __DIR__ . DS . 'builder' . DS . 'product-styles' . DS . 'table.php';
                    $productCards[] = ob_get_clean();
                }

                if ($productCards) {
                    $output .= implode('', $productCards);
                }

                unset($productCards);
                $output .= '</div>';
                $output .= '</div>';
            }
            else {
                $verticalAlign = (isset($widgetData['widget_content']->vertical_align) && $widgetData['widget_content']->vertical_align ? 'align-items-' . $widgetData['widget_content']->vertical_align : '');
                $containerClass = 'row row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-3 justify-content-center pricing-style-' . $widgetStyle . ' ' . $verticalAlign;

                if ($widgetData['isWidget']) {
                    if (isset($widgetData['carouselData']) && $widgetData['carouselData']) {
                        $containerClass = 'fon-content-carousel fon-products-carousel pricing-style-' . $widgetStyle . ' ' . $widgetData['widget_name'] . '-carousel ' . $verticalAlign;
                    }
                    else {
                        $containerClass = 'row row-cols-' . $widgetData['widget_content']->column->xs . ' row-cols-sm-' . $widgetData['widget_content']->column->sm . ' row-cols-md-' . $widgetData['widget_content']->column->md . ' row-cols-lg-' . $widgetData['widget_content']->column->lg . ' row-cols-xl-' . $widgetData['widget_content']->column->xl . ' justify-content-center pricing-style-' . $widgetStyle . ' ' . $verticalAlign;
                    }
                }

                $containerId = $widgetData['widgetId'] . ($cat ? '-' . $cat['id'] : '');
                if ((($show_price_type != 'default') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) || $showFilters && $productType == 'server') {
                    $output .= '<div class="pricing-filter-container text-center mb-' . ($show_price_type == 'all_select' ? '5' : '3') . ' ' . $show_price_type . ' d-flex ' . ($showFilters && $productType == 'server' ? 'flex-column' : '') . ' align-items-center justify-content-center gap-3">';
                    if (($show_price_type == 'month_year') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) {
                        $output .= '<div class="pricing-period-swithcer mb-0" data-id="' . $containerId . '"><input id="monthly-package-price' . $containerId . '" class="monthly-package-price" type="radio" name="switch' . $containerId . '" checked="checked"><input id="yearly-package-price' . $containerId . '" class="yearly-package-price" type="radio" name="switch' . $containerId . '"><label class="monthly-package-price-label" for="monthly-package-price' . $containerId . '">' . ___('date/period-month') . '</label><label class="yearly-package-price-label" for="yearly-package-price' . $containerId . '">' . ___('date/period-year') . '</label><span class="package-prices-highlighter"></span></div>';
                    }
                    else if (($show_price_type == 'all_filter') && in_array($productType, ['hosting' => true, 'server' => true, 'special' => true])) {
                        foreach ($list as $sk => $sp) {
                            foreach ($sp['prices'] as $spkey => $spprice) {
                                $periods[$spkey] = $spprice['time'] . ' ' . ___('date/period-' . $spprice['period']);
                            }
                        }
                        if ($periods && 1 < count($periods)) {
                            $output .= '<div class="pricing-period-filter" data-id="#' . $containerId . '">';
                            $i = 0;

                            foreach ($periods as $spkey => $spperiod) {
                                $output .= '<input id="package-filter-price-' . $containerId . '-' . $spkey . '" class="package-filter-price-' . $spkey . '" type="radio" name="switch' . $containerId . '" ' . ($i == 0 ? 'checked="checked"' : '') . '>';
                                $output .= '<label class="package-filter-price-label-' . $spkey . '" for="package-filter-price-' . $containerId . '-' . $spkey . '">' . $spperiod . '</label>';
                                ++$i;
                            }

                            $output .= '</div>';
                        }
                    }
                    if ($showFilters && $productType == 'server') {
                        $this->addAsset('select2');
                        $output .= '<div class="server-filter-container row g-2 align-items-center justify-content-center">';

                        foreach ($list as $sk => $sp) {
                            if (isset($sp['options'])) {
                                $serverOptions[] = $sp['options'];
                            }
                        }
                        if ($serverOptions && 1 < count($serverOptions)) {
                            $serverProcessors = [];
                            $serverRams = [];
                            $serverDisks = [];
                            $serverBandwidths = [];
                            $serverRaids = [];

                            foreach ($serverOptions as $pkg) {
                                if (isset($pkg['processor'])) {
                                    $serverProcessors[] = $pkg['processor'];
                                }

                                if (isset($pkg['ram'])) {
                                    $serverRams[] = $pkg['ram'];
                                }

                                if (isset($pkg['disk-space'])) {
                                    $serverDisks[] = $pkg['disk-space'];
                                }

                                if (isset($pkg['bandwidth'])) {
                                    $serverBandwidths[] = $pkg['bandwidth'];
                                }

                                if (isset($pkg['raid'])) {
                                    $serverRaids[] = $pkg['raid'];
                                }
                            }

                            $serverProcessors = array_unique($serverProcessors);
                            $serverRams = array_unique($serverRams);
                            $serverDisks = array_unique($serverDisks);
                            $serverBandwidths = array_unique($serverBandwidths);
                            $serverRaids = array_unique($serverRaids);
                            sort($serverProcessors);
                            sort($serverRams);
                            sort($serverDisks);
                            sort($serverBandwidths);
                            sort($serverRaids);
                            $filtersCounts = 0;
                            if ($serverProcessors && 1 < count($serverProcessors) && in_array('processor', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-processor" class="form-select select-filter processor-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-cpu-label="' . __('website/products/server-list-processor') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-processor') . '</option>';

                                foreach ($serverProcessors as $serverProcessor) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverProcessor)) . '">' . htmlspecialchars($serverProcessor) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverRams && 1 < count($serverRams) && in_array('ram', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-ram" class="form-select select-filter ram-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-ram-label="' . __('website/products/server-list-ram') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-ram') . '</option>';

                                foreach ($serverRams as $serverRam) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverRam)) . '">' . htmlspecialchars($serverRam) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverDisks && 1 < count($serverDisks) && in_array('disk-space', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-disk" class="form-select select-filter disk-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-disk-label="' . __('website/products/server-list-disk') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-disk') . '</option>';

                                foreach ($serverDisks as $serverDisk) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverDisk)) . '">' . htmlspecialchars($serverDisk) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverBandwidths && 1 < count($serverBandwidths) && in_array('bandwidth', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-bandwidth" class="form-select select-filter bandwidth-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-bandwidth-label="' . __('website/products/server-list-bandwidth') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-bandwidth') . '</option>';

                                foreach ($serverBandwidths as $serverBandwidth) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverBandwidth)) . '">' . htmlspecialchars($serverBandwidth) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($serverRaids && 1 < count($serverRaids) && in_array('raid', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-raid" class="form-select select-filter raid-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-raid-label="' . __('website/products/server-list-raid') . '">';
                                $output .= '<option value="">' . __('website/products/server-list-raid') . '</option>';

                                foreach ($serverRaids as $serverRaid) {
                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($serverRaid)) . '">' . htmlspecialchars($serverRaid) . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }

                            foreach ($list as $sk => $sp) {
                                if (isset($sp['options_lang']['location']) && !in_array($sp['options_lang']['location'], $locations)) {
                                    $locations[] = $sp['options_lang']['location'];
                                }
                            }
                            if ($locations && 1 < count($locations) && in_array('location', $enabledFilters)) {
                                ++$filtersCounts;
                                $output .= '<div class="col">';
                                $output .= '<select id="' . $containerId . '-server-location" class="form-select location-filter select-filter" data-id="' . $containerId . '" data-type="' . $widgetType . '" data-carousel="' . (isset($widgetData['carouselData']) && $widgetData['carouselData'] ? 1 : 0) . '" data-location-label="' . __('theme/server_location') . '">';

                                if (!$showFirstLocation) {
                                    $output .= '<option value="">' . __('theme/server_location') . '</option>';
                                }

                                foreach ($locations as $location) {
                                    $country = $code = NULL;

                                    if (strpos($location, '-') !== false) {
                                        $parts = explode('-', $location);
                                        $country = $parts[0];
                                        $code = end($parts);
                                    }
                                    else {
                                        $country = $location;
                                        $code = NULL;
                                    }

                                    if (!empty($code)) {
                                        $code = mb_convert_encoding((string) $code, 'UTF-8', 'UTF-8');
                                    }

                                    $output .= '<option value="' . Filter::permalink(htmlspecialchars($location)) . '" data-flag="' . strtolower(htmlspecialchars($code)) . '">' . $country . '</option>';
                                }

                                $output .= '</select>';
                                $output .= '</div>';
                            }
                            if ($filtersCounts && 2 <= $filtersCounts) {
                                $output .= '<div class="col btn-clear-filters" style="display: none;"><button type="button" class="btn btn-danger"><i class="fa-solid fa-times" title="' . __('theme/clear_filters') . '"></i></button></div>';
                            }
                        }

                        $output .= '</div>';
                    }

                    $output .= '</div>';
                }

                $output .= '<div class="' . $containerClass . ' fon-pricing-tables" ' . ($widgetData['carouselData'] ?? '') . ' id="' . $containerId . '">';
                $productCards = [];

                foreach ($list as $product) {
                    $product['order_image'] = Image::picture('product', $product['id'], 'order');
                    $popular = false;
                    $prices = (!isset($product['prices']) ? [] : $product['prices']);
                    $productPrice = self::calculatePrices($prices, $widgetData['currency_symbols'], $product['override_usrcurrency'], $productType, $show_price_type, $price_calc);
                    $categoryCoupon = [];
                    $productCoupon = [];

                    if ($cat) {
                        if ($cat['kind'] == 'special') {
                            $categortKind = $this->getCategory($cat['id'], 'products', 'special');
                            $categoryKindId = $categortKind['kind_id'] ?? ($categortKind['kind_id'] ?? 0);

                            if ($categoryKindId) {
                                $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$categoryKindId . '/' . $cat['id']]);
                            }
                            else {
                                $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$cat['id']]);
                            }

                            $productCoupon = $this->couponCheck('product', $product['type'], [$categoryKindId, $product['id']]);
                        }
                        else {
                            $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$cat['id']]);
                            $productCoupon = $this->couponCheck('product', $product['type'], [$cat['id'], $product['id']]);
                        }
                    }
                    else if (isset($product['category'])) {
                        $categoryId = (is_array($product['category']) ? $product['category']['id'] : $product['category']);

                        if ($cat['kind'] == 'special') {
                            $categortKind = $this->getCategory($categoryId, 'products', 'special');
                            $categoryKindId = $categortKind['kind_id'] ?? ($categortKind['kind_id'] ?? 0);

                            if ($categoryKindId) {
                                $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$categoryKindId . '/' . $cat['id']]);
                            }
                            else {
                                $categoryCoupon = $this->couponCheck('category', $cat['kind'], [$cat['id']]);
                            }

                            $productCoupon = $this->couponCheck('product', $product['type'], [$categoryKindId, $product['id']]);
                        }
                        else {
                            $categoryCoupon = $this->couponCheck('category', $product['type'], [$categoryId]);
                            $productCoupon = $this->couponCheck('product', $product['type'], [$categoryId, $product['id']]);
                        }
                    }
                    else {
                        $categoryCoupon = $this->couponCheck('category', $product['type'], [0, $product['id']]);
                        $productCoupon = $this->couponCheck('product', $product['type'], [0, $product['id']]);
                    }
                    if (isset($product['options']['popular']) && $product['options']['popular']) {
                        $popular = true;
                    }

                    $features_output = '';
                    $slogan = '';
                    $packageIcon = '';

                    if ($product['features']) {
                        $productFeatures = (self::isJSON($product['features']) ? Utility::jdecode($product['features'], true) : $product['features']);
                        if (is_array($productFeatures) && isset($productFeatures['slogan'])) {
                            $slogan = $productFeatures['slogan'];
                        }
                        if (is_array($productFeatures) && isset($productFeatures['icon'])) {
                            $packageIcon = $productFeatures['icon'];
                        }

                        if ($product['type'] == 'server') {
                            $serverFeatures = [];
                            $server['features'] = ['processor', 'ram', 'disk-space', 'bandwidth', 'raid'];

                            foreach ($server['features'] as $key) {
                                if (isset($product['options'][$key])) {

                                    $serverFeatures[] = ['name' => match ($key) {
                                        'processor' => __('website/products/server-list-processor'),
                                        'ram' => __('website/products/server-list-ram'),
                                        'disk-space' => __('website/products/server-list-disk'),
                                        'bandwidth' => __('website/products/server-list-bandwidth'),
                                        'raid' => __('website/products/server-list-raid')
                                    }, 'desc' => '', 'icon' => match ($key) {
                                        'processor' => 'fa-solid fa-microchip',
                                        'ram' => 'fa-solid fa-memory',
                                        'disk-space' => 'fa-solid fa-hard-drive',
                                        'bandwidth' => 'fa-solid fa-gauge-high',
                                        'raid' => 'fa-solid fa-server'
                                    }, 'type' => 'text', 'text' => $product['options'][$key], 'exist' => true];
                                }
                            }

                            if (isset($product['options_lang']['location'])) {
                                $country = '-';
                                $code = NULL;

                                if ($product['options_lang']['location'] != '') {
                                    if (strpos($product['options_lang']['location'], '-') !== false) {
                                        $parts = explode('-', $product['options_lang']['location']);
                                        $country = $parts[0];
                                        $code = end($parts);
                                    }
                                    else {
                                        $country = $product['options_lang']['location'];
                                        $code = NULL;
                                    }
                                }

                                $serverFeatures[] = ['name' => __('website/products/server-list-location'), 'desc' => '', 'icon' => 'fa-solid fa-location-dot', 'type' => 'text', 'text' => ($code ? '<i class="flag flag-xs rounded-1 flag-country-' . strtolower($code) . ' me-1"></i>' . $country : $country), 'exist' => true];
                            }
                            if ($serverFeatures && is_array($productFeatures) && isset($productFeatures['features'])) {
                                $productFeatures['features'] = array_merge($serverFeatures, $productFeatures['features']);
                            }
                        }
                    }
                    else if ($product['type'] == 'server') {
                        $product['features'] = ['processor', 'ram', 'disk-space', 'bandwidth', 'raid'];
                        $productFeatures = [
                            'count'    => 6,
                            'features' => []
                        ];
                        if (isset($product['options']) && is_array($product['options'])) {
                            foreach ($product['features'] as $key) {
                                if (isset($product['options'][$key])) {

                                    $productFeatures['features'][] = ['name' => match ($key) {
                                        processor => __('website/products/server-list-processor'),
                                        ram => __('website/products/server-list-ram'),
                                        disk-space => __('website/products/server-list-disk'),
                                        bandwidth => __('website/products/server-list-bandwidth'),
                                        raid => __('website/products/server-list-raid')
                                    }, 'desc' => '', 'icon' => match ($key) {
                                        processor => 'fa-solid fa-microchip',
                                        ram => 'fa-solid fa-memory',
                                        disk-space => 'fa-solid fa-hard-drive',
                                        bandwidth => 'fa-solid fa-gauge-high',
                                        raid => 'fa-solid fa-server'
                                    }, 'type' => 'text', 'text' => $product['options'][$key], 'exist' => true];
                                }
                            }
                        }

                        if (isset($product['options_lang']['location'])) {
                            $country = '-';
                            $code = NULL;

                            if ($product['options_lang']['location'] != '') {
                                if (strpos($product['options_lang']['location'], '-') !== false) {
                                    $parts = explode('-', $product['options_lang']['location']);
                                    $country = $parts[0];
                                    $code = end($parts);
                                }
                                else {
                                    $country = $product['options_lang']['location'];
                                    $code = NULL;
                                }
                            }

                            $productFeatures['features'][] = ['name' => __('website/products/server-list-location'), 'desc' => '', 'icon' => 'fa-solid fa-location-dot', 'type' => 'text', 'text' => ($code ? '<i class="flag flag-xs rounded-1 flag-country-' . strtolower($code) . ' me-1"></i>' . $country : $country), 'exist' => true];
                        }
                    }

                    $optl = $product['options_lang'];

                    if (!isset($product['buy_link'])) {
                        if (isset($product['options']['external_link']) && $product['options']['external_link'] != '') {
                            $buy_link = $product['options']['external_link'];
                        }
                        else if (isset($product['optionsl']['external_link']) && $product['optionsl']['external_link'] != '') {
                            $buy_link = $product['optionsl']['external_link'];
                        }
                        else if (isset($optl['external_link']) && $optl['external_link'] != '') {
                            $buy_link = $optl['external_link'];
                        }
                        else {
                            $buy_link = Controllers::$init->CRLink('order-steps', [($cat ? $cat['kind'] : $product['type']), $product['id']]);
                        }
                    }
                    else if (isset($optl['external_link']) && $optl['external_link'] != '') {
                        $buy_link = $optl['external_link'];
                    }
                    else if (isset($product['optionsl']['external_link']) && $product['optionsl']['external_link'] != '') {
                        $buy_link = $product['optionsl']['external_link'];
                    }
                    else if (isset($product['options']['external_link']) && $product['options']['external_link'] != '') {
                        $buy_link = $product['options']['external_link'];
                    }
                    else {
                        $buy_link = $product['buy_link'];
                    }

                    $buy_button_name = __('website/index/add-basket-button');
                    if (isset($optl['buy_button_name']) && $optl['buy_button_name'] != '') {
                        $buy_button_name = $optl['buy_button_name'];
                    }
                    else if (isset($product['optionsl']['buy_button_name']) && $product['optionsl']['buy_button_name'] != '') {
                        $buy_button_name = $product['optionsl']['buy_button_name'];
                    }
                    else if (isset($product['options']['buy_button_name']) && $product['options']['buy_button_name'] != '') {
                        $buy_button_name = $product['options']['buy_button_name'];
                    }
                    else if ($enable_custom_card_button_label && !empty($custom_card_button_label)) {
                        $buy_button_name = $custom_card_button_label;
                    }

                    if (!empty($cat)) {
                        $catTitle = $cat['title'];
                        $pattern = '/^(http:\\/\\/|https:\\/\\/)/';

                        if (preg_match($pattern, $cat['route'])) {
                            $catRoute = $cat['route'];
                        }
                        else if (isset($widgetData['items']) && $widgetData['items'] && 0 < (int) $widgetData['items']['showCategory']['id'] && $widgetData['items']['showCategory']['id'] == $cat['id']) {
                            $catRoute = '';
                        }
                        else {
                            $catRoute = Controllers::$init->CRLink('products', [$cat['route']]);
                        }
                    }
                    else if (is_array($product['category']) && $product['category']) {
                        $catTitle = $product['category']['title'];
                        $pattern = '/^(http:\\/\\/|https:\\/\\/)/';

                        if (preg_match($pattern, $product['category']['route'])) {
                            $catRoute = $product['category']['route'];
                        }
                        else {
                            $catRoute = Controllers::$init->CRLink('products', [$product['category']['route']]);
                        }
                    }
                    else if (isset($widgetData['items']) && $widgetData['items'] && 0 < (int) $widgetData['items']['showCategory']['id']) {
                        $catRoute = '';
                    }
                    else {
                        $catRoute = '';
                        $catTitle = '';
                    }

                    ob_start();
                    include __DIR__ . DS . 'builder' . DS . 'product-styles' . DS . 'grid_' . $widgetStyle . '.php';
                    $productCards[] = ob_get_clean();
                }

                if ($productCards) {
                    $output .= implode('', $productCards);
                }

                unset($productCards);
                $output .= '</div>';
            }
        }

        return $output;
    }

    public function getPageContent(string $pageType, array $sourcePage): array
    {
        $cacheActive = false;
        $themeCache = Config::get('theme/cache_pages');
        $globalCache = Config::get('general/cache');
        if ($themeCache && $globalCache) {
            $cacheActive = true;
        }

        if ($cacheActive) {
            $cache = Controllers::$cache;
            $cache->setCache('fonbuilderpages');
            $cache->eraseExpired();
        }

        if ($cacheActive) {
            if (!$cache->isCached('page_' . $pageType . '_' . $sourcePage['id'])) {
                $page = static::pageContentQuery($pageType, $sourcePage['id'] ?? 0);
                $cache->store('page_' . $pageType . '_' . $sourcePage['id'], $page, '86400');
            }
            else {
                $page = $cache->retrieve('page_' . $pageType . '_' . $sourcePage['id']);
            }
        }
        else {
            $page = static::pageContentQuery($pageType, $sourcePage['id'] ?? 0);
        }
        if (!$page && in_array($pageType, ['hosting' => true, 'server' => true, 'sms' => true, 'special' => true])) {
            if ($cacheActive) {
                if (!$cache->isCached('page_' . $pageType . '_' . $sourcePage['parent'])) {
                    $page = static::pageContentQuery($pageType, $sourcePage['parent'] ?? 0);
                    $cache->store('page_' . $pageType . '_' . $sourcePage['parent'], $page, '86400');
                }
                else {
                    $page = $cache->retrieve('page_' . $pageType . '_' . $sourcePage['parent']);
                }
            }
            else {
                $page = static::pageContentQuery($pageType, $sourcePage['parent'] ?? 0);
            }

            if (!$page) {
                if ($cacheActive) {
                    if (!$cache->isCached('page_' . $pageType . '_0')) {
                        $page = static::pageContentQuery($pageType, 0);
                        $cache->store('page_' . $pageType . '_0', $page, '86400');
                    }
                    else {
                        $page = $cache->retrieve('page_' . $pageType . '_0');
                    }
                }
                else {
                    $page = static::pageContentQuery($pageType, 0);
                }
            }
        }

        $this->addAsset('builder');
        if (isset($page['page_style']) && $page['page_style']) {
            $pageType = ($pageType != 'page' ? $pageType : 'page-detail-normal');
            $this->addStyle($pageType, $page['page_style']);
        }
        $page['page_content'] = (isset($page['page_content']) && $page['page_content'] ? Utility::jdecode(html_entity_decode($page['page_content'], ENT_QUOTES, 'UTF-8')) : []);
        $page['page_options'] = (isset($page['page_options']) && $page['page_options'] ? Utility::jdecode(html_entity_decode($page['page_options'], ENT_QUOTES, 'UTF-8'), true) : []);
        return $page;
    }

    private static function pageContentQuery(string $pageType, ?int $pageId = 0): array
    {
        if (is_null($pageId) || !$pageId) {
            $pageId = 0;
        }

        $page_query = Models::$init->db->select('*');
        $page_query->from('fonpagebuilder');

        if ($pageType == 'custom') {
            $page_query->where('id', '=', (string) $pageId, '&&');
        }
        else {
            $page_query->where('type_id', '=', (string) $pageId, '&&');
        }

        $page_query->where('status', '=', '1', '&&');
        $page_query->where('type', '=', (string) $pageType);
        $page = ($page_query->build() ? $page_query->getAssoc() : []);
        return $page;
    }

    private function getProducts(string $kind = '', array|string $id = [], int $limit = 10, bool $widget = false): array
    {
        $select = ['p.id', 'p.type', 'p.type_id', 'p.category', 'p.rank', 'p.override_usrcurrency', 'p.options', 'pl.options AS options_lang', 'pl.options AS optionsl', 'pl.title', 'pl.features', 'c.options AS c_options', 'cl.options AS cl_options', 'i.name AS cover_image', 'CASE' . "\n" . '                WHEN stock = "" THEN 1' . "\n" . '                WHEN stock IS NULL THEN 1' . "\n" . '                ELSE stock' . "\n" . '                END AS haveStock'];
        $query = Models::$init->db->select(implode(',', $select))->from('products AS p');
        $query->join('LEFT', 'products_lang AS pl', 'pl.owner_id=p.id AND pl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'categories_lang AS cl', 'cl.owner_id=p.category AND cl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'pictures AS i', 'i.owner=\'product\' AND i.owner_id=p.id AND i.reason=\'order\'');

        if ($kind != 'sms') {
            $query->join('LEFT', 'categories AS c', 'p.category=c.id');
            $query->join('LEFT', 'categories_lang AS cl', 'cl.owner_id=p.category AND cl.lang=\'' . $this->lang . '\'');

            if ($id != 'none') {
                $query->where('c.id', 'IS NOT NULL', '', '&&');
            }
        }

        $query->where('pl.id', 'IS NOT NULL', '', '&&');

        if ($widget) {
            if (is_array($id)) {
                $query->where('p.id', 'IN (' . implode(', ', $id) . ')', '', '&&');
            }
            else if ($id != 'none') {
                $query->where('(');
                $query->where('p.category', '=', $id, '||');
                $query->where('FIND_IN_SET(' . $id . ',p.categories)', '', '');
                $query->where(')', '', '', '&&');
            }
            else {
                $query->where('p.category', '=', 0, '&&');
            }
        }
        else {
            $query->where('(');
            $query->where('FIND_IN_SET(p.category,\'' . $id . '\')', '', '', '||');
            $query->where('FIND_IN_SET(p.categories,\'' . $id . '\')', '', '', '');
            $query->where(')', '', '', '&&');
        }

        if ($kind) {
            $query->where('p.type', '=', $kind, '&&');
        }

        $query->where('p.status', '=', 'active', '&&');
        $query->where('p.visibility', '=', 'visible');
        $query->order_by('p.rank ASC');

        if ($limit) {
            $query->limit($limit);
        }

        $results = ($query->build() ? $query->fetch_assoc() : []);

        if ($results) {
            foreach ($results as $key => $result) {
                $results[$key]['prices'] = self::getPrices('products', $result['id'], $kind);
                $results[$key]['options'] = ($results[$key]['options'] ? json_decode($results[$key]['options'], true) : []);
                $results[$key]['optionsl'] = ($results[$key]['optionsl'] ? json_decode($results[$key]['optionsl'], true) : []);
                $results[$key]['options_lang'] = ($results[$key]['options_lang'] ? json_decode($results[$key]['options_lang'], true) : []);
            }
        }

        return $results;
    }

    private function getPages(string $type = '', array|string $id = [], int $limit = 10): array
    {
        $select = ['p.id', 'p.type', 'p.category', 'p.ctime', 'pl.route', 'pl.title', 'pl.content', 'p.options', 'p.override_usrcurrency', 'pl.options AS optionsl', 'i.name AS cover_image'];
        $query = Models::$init->db->select(implode(',', $select))->from('pages AS p');
        $query->join('LEFT', 'pages_lang AS pl', 'pl.owner_id=p.id AND pl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'pictures AS i', 'i.owner=\'page_' . $type . '\' AND i.owner_id=p.id AND i.reason=\'cover\'');
        $query->where('pl.id', 'IS NOT NULL', '', '&&');

        if (is_array($id)) {
            $query->where('p.id', 'IN (' . implode(', ', $id) . ')', '', '&&');
        }
        else if ($id != 'none') {
            $query->where('(');
            $query->where('p.category', '=', $id, '||');
            $query->where('FIND_IN_SET(' . $id . ',p.categories)', '', '');
            $query->where(')', '', '', '&&');
        }

        $query->where('p.type', '=', $type, '&&');
        $query->where('p.status', '=', 'active', '&&');
        $query->where('p.visibility', '=', 'visible');

        if ($type == 'software') {
            if (!is_array($id) && $id != 'none') {
                $query->order_by('p.rank ASC');
            }
            else {
                $query->order_by('p.id DESC');
            }
        }
        else if ($type == 'references') {
            $query->order_by('p.rank ASC,p.id DESC');
        }
        else {
            $query->order_by('p.id DESC');
        }

        $query->limit($limit);
        $results = ($query->build() ? $query->fetch_assoc() : []);

        if ($results) {
            foreach ($results as $key => $result) {
                if ($type == 'software') {
                    $results[$key]['prices'] = self::getPrices('softwares', $result['id'], 'software');
                }

                $results[$key]['options'] = ($results[$key]['options'] ? json_decode($results[$key]['options'], true) : []);
                $results[$key]['optionsl'] = ($results[$key]['optionsl'] ? json_decode($results[$key]['optionsl'], true) : []);
            }
        }

        return $results;
    }

    private function getCategory(int $id, string $type = 'products', string $kind = ''): array
    {
        $select = ['c.id', 'c.parent', 'c.kind', 'c.kind_id', 'c.options', 'cl.title', 'cl.sub_title', 'cl.route', 'cl.options AS optionsl', 'cl.options AS options_lang', 'cl.faq AS faqs', 'i.name AS background_image', '(SELECT name FROM ' . $this->db_prefix . 'pictures WHERE owner=\'category\' AND owner_id=c.id AND reason=\'icon\') AS icon'];
        $query = Models::$init->db->select(implode(',', $select))->from('categories AS c');
        $query->join('LEFT', 'categories_lang AS cl', 'cl.owner_id=c.id AND cl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'pictures AS i', 'i.owner=\'category\' AND i.owner_id=c.id AND i.reason=\'background-image\'');
        $query->where('cl.id', 'IS NOT NULL', '', '&&');
        $query->where('c.type', '=', $type, '&&');

        if ($kind) {
            $query->where('c.kind', '=', $kind, '&&');
        }

        $query->where('c.status', '=', 'active', '&&');
        $query->where('c.visibility', '=', 'visible', '&&');
        $query->where('c.id', '=', $id);
        $result = ($query->build() ? $query->getAssoc() : []);

        if ($result) {
            $result['options'] = ($result['options'] ? json_decode($result['options'], true) : []);
            $result['optionsl'] = ($result['optionsl'] ? json_decode($result['optionsl'], true) : []);
            $result['options_lang'] = ($result['options_lang'] ? json_decode($result['options_lang'], true) : []);
        }

        return $result;
    }

    private function getCategories(int $parent = 0, string $type = 'products', string $kind = ''): array
    {
        $select = ['c.id', 'c.parent', 'c.kind', 'c.options', 'cl.title', 'cl.sub_title', 'cl.route', 'cl.options AS optionsl', 'cl.options AS options_lang', 'i.name AS background_image', '(SELECT name FROM ' . $this->db_prefix . 'pictures WHERE owner=\'category\' AND owner_id=c.id AND reason=\'cover\') AS icon'];
        $query = Models::$init->db->select(implode(',', $select))->from('categories AS c');
        $query->join('LEFT', 'categories_lang AS cl', 'cl.owner_id=c.id AND cl.lang=\'' . $this->lang . '\'');
        $query->join('LEFT', 'pictures AS i', 'i.owner=\'category\' AND i.owner_id=c.id AND i.reason=\'background-image\'');
        $query->where('cl.id', 'IS NOT NULL', '', '&&');
        $query->where('c.type', '=', $type, '&&');

        if ($kind) {
            $query->where('c.kind', '=', $kind, '&&');
        }

        $query->where('c.status', '=', 'active', '&&');
        $query->where('c.visibility', '=', 'visible', '&&');
        if (($kind === 'server') && 0 < $parent) {
            $query->where('(SELECT id FROM ' . $this->db_prefix . 'products WHERE (category=c.id OR FIND_IN_SET(c.id,categories) OR FIND_IN_SET(category,(SELECT GROUP_CONCAT(id) FROM categories WHERE parent=c.id))) AND status=\'active\' AND visibility=\'visible\' LIMIT 1)', '', '', '&&');
        }

        $query->where('c.parent', '=', $parent);
        $results = ($query->build() ? $query->fetch_assoc() : []);

        if ($results) {
            foreach ($results as $key => $result) {
                $results[$key]['options'] = ($result['options'] ? json_decode($result['options'], true) : []);
                $results[$key]['optionsl'] = ($result['optionsl'] ? json_decode($result['optionsl'], true) : []);
                $results[$key]['options_lang'] = ($result['options_lang'] ? json_decode($result['options_lang'], true) : []);
            }
        }

        return $results;
    }

    private static function getPrices(string $owner, int $owner_id, string $kind): array
    {
        $type = ($kind == 'sms' ? 'sale' : 'periodicals');
        $query = Models::$init->db->select('*')->from('prices');
        $query->where('type', '=', $type, '&&');
        $query->where('owner', '=', $owner, '&&');
        $query->where('owner_id', '=', $owner_id);
        $query->order_by('rank ASC');
        return ($query->build() ? $query->fetch_assoc() : []);
    }

    public function couponCheck(string $type = 'category', string $kind = 'hosting', array $ids = []): array
    {
        $sth = Models::$init->db->select('*')->from('coupons');

        if ($type == 'category') {
            $categoryId = $ids[0];
            $sth->where('(');
            $sth->where('pservices', 'LIKE', '%category/' . $kind . '/' . $categoryId . '%', '||');

            if ($kind == 'special') {
                if (strpos($categoryId, '/') !== false) {
                    $parts = explode('/', $categoryId);
                    $groupId = $parts[0];
                    $sth->where('pservices', 'LIKE', '%allOf/' . $kind . '/' . $groupId . '%');
                }
                else {
                    $sth->where('pservices', 'LIKE', '%allOf/' . $kind . '/' . $categoryId . '%');
                }
            }
            else {
                $sth->where('pservices', 'LIKE', '%allOf/' . $kind . '%');
            }

            $sth->where(')', '', '', '&&');
        }
        else {
            $product_id = implode('/', $ids);
            $sth->where('pservices', 'LIKE', '%product/' . $kind . '/' . $product_id . '%', '&&');
        }

        $sth->where('status', '=', 'active', '&&');
        $sth->where('duedate', '>=', DateManager::Now());
        $sth->limit('1');
        $result = ($sth->build() ? $sth->getAssoc() : []);
        $coupon = [];
        $periodTypes = ['hour' => $this->language['coupon_hour'], 'day' => $this->language['coupon_day'], 'week' => $this->language['coupon_week'], 'month' => $this->language['coupon_month'], 'year' => $this->language['coupon_year']];

        if ($result) {
            if ($result['type'] == 'percentage') {
                $coupon['discount'] = '%' . $result['rate'];
            }
            else {
                $coupon['discount'] = Money::formatter_symbol($result['amount'], $result['currency']);
            }

            $periodtext = '';
            if ($result['period_type'] && $result['period_type'] != 'none') {
                if (1 < $result['period_duration']) {
                    $periodtext .= $result['period_duration'];
                }

                $periodtext .= $periodTypes[$result['period_type']];
                $coupon['period'] = $periodtext;
            }

            $coupon['code'] = $result['code'];
            $coupon['merge'] = $result['use_merge'];
        }

        return $coupon;
    }

    private function getTestimonials(int $limit = 4): array
    {
        $lang = Language::selected();
        $query = Models::$init->db->select('t1.*,t2.message,t3.name AS image')->from('customer_feedbacks AS t1');
        $query->join('LEFT', 'customer_feedbacks_lang AS t2', 't2.owner_id=t1.id AND t2.lang=\'' . $lang . '\'');
        $query->join('LEFT', 'pictures AS t3', 't1.id=t3.owner_id AND t3.owner=\'customer_feedback\' AND t3.reason=\'image\'');
        $query->where('t2.id', 'IS NOT NULL', '', '&&');
        $query->where('status', '=', 'approved');
        $query->order_by('t1.rank ASC,id DESC');
        $query->limit($limit);
        return ($query->build() ? $query->fetch_assoc() : []);
    }

    private static function getTldPrices(int $tldId = 0, string $priceType = 'register', string $order = 'p.rank ASC', int $limit = 0): array
    {
        $query = Models::$init->db->select()->from('prices AS p');
        $query->where('p.owner', '=', 'tld', '&&');
        $query->where('p.type', '=', $priceType, '&&');

        if ($tldId) {
            $query->where('p.owner_id', '=', $tldId);
        }

        $query->order_by($order);

        if ($limit) {
            $query->limit($limit);
        }

        $price = ($query->build() ? $query->getAssoc() : []);
        return $price;
    }

    public static function getCurrencySymbols(string $code = ''): array
    {
        $currency_symbols = [];

        foreach (Money::getCurrencies() as $currency) {
            if ($code) {
                if ($code == 'format') {
                    $currency_symbols[$currency['code']] = $currency['format'];
                }
                else {
                    $currency_symbols[] = $currency['code'];
                }
            }
            else {
                $symbol = ($currency['prefix'] != '' ? trim($currency['prefix']) : trim($currency['suffix']));

                if (!$symbol) {
                    $symbol = $currency['code'];
                }

                $currency_symbols[] = $symbol;
            }
        }

        return $currency_symbols;
    }

    public static function currencySymbol(string $amount, array $currency_symbols): string
    {
        $symbol_position = '';
        $symbol = '';
        $split_amount = explode(' ', $amount);

        if (in_array(current($split_amount), $currency_symbols)) {
            $symbol_position = 'left';
            $symbol = current($split_amount);
            array_shift($split_amount);
            $amount = implode(' ', $split_amount);
        }
        else if (in_array(end($split_amount), $currency_symbols)) {
            $symbol_position = 'right';
            $symbol = end($split_amount);
            array_pop($split_amount);
            $amount = implode(' ', $split_amount);
        }

        if ($symbol_position == 'left') {
            $priceFormatted = '<sup class="currency-symbol ' . $symbol_position . '">' . $symbol . '</sup>' . $amount;
        }
        else {
            $priceFormatted = $amount . '<sup class="currency-symbol ' . $symbol_position . '">' . $symbol . '</sup>';
        }

        return $priceFormatted;
    }

    public static function calculatePrices(array $prices, array $currency_symbols, int|bool $override_usrcurrency = 0, string $type = 'default', string|bool $show_price_type = '', string $price_calc = 'default'): array
    {
        if ((($show_price_type == 'yes') || $show_price_type == 'month_year') && in_array($type, ['hosting' => true, 'server' => true, 'special' => true])) {
            $productPrices = self::getPriceInfo($prices, $price_calc);
            if ($productPrices && 0 < $productPrices['price']) {
                $cid = $productPrices['cid'];
                $amount = $productPrices['price'];
                $price = Money::formatter_symbol($amount, $cid, !$override_usrcurrency);
                $priceRaw = self::parsePrice($price);
                $price = self::currencySymbol($price, $currency_symbols);
                $amountYearly = $productPrices['yearly'];
                $priceYearly = Money::formatter_symbol($amountYearly, $cid, !$override_usrcurrency);
                $priceRawYearly = self::parsePrice($priceYearly);
                $priceYearly = self::currencySymbol($priceYearly, $currency_symbols);
                $special = false;
                $specialYearly = false;
                if ($productPrices['discount'] && 0 < (float) $productPrices['discount']) {
                    $specialAmount = (float) $amount / (1 - ((float) $productPrices['discount'] / 100));
                    $special = Money::formatter_symbol($specialAmount, $cid, !$override_usrcurrency);
                    $specialRaw = self::parsePrice($special);
                    $special = self::currencySymbol($special, $currency_symbols);
                    $specialAmountYearly = (float) $amountYearly / (1 - ((float) $productPrices['discount'] / 100));
                    $specialYearly = Money::formatter_symbol($specialAmountYearly, $cid, !$override_usrcurrency);
                    $specialRawYearly = self::parsePrice($specialYearly);
                    $specialYearly = self::currencySymbol($specialYearly, $currency_symbols);
                }
            }

            if ($productPrices) {
                $period = View::period(1, $productPrices['period']);
            }

            $productPrice = ['price' => $price ?? '', 'priceRaw' => $priceRaw ?? '', 'special' => $special ?? '', 'specialRaw' => $specialRaw ?? '', 'priceY' => $priceYearly ?? '', 'priceRawY' => $priceRawYearly ?? '', 'specialY' => $specialYearly ?? '', 'specialRawY' => $specialRawYearly ?? '', 'period' => $period ?? '', 'discount' => (float) $productPrices['discount'], 'prices' => $prices, 'prices_periodically' => $productPrices, 'show_monthly' => $show_price_type, 'monthly_calc' => $price_calc, 'show_price_type' => $show_price_type, 'time' => $productPrices['time']];
            return $productPrice;
        }
        else if ((($show_price_type == 'all_filter') || $show_price_type == 'all_select') && in_array($type, ['hosting' => true, 'server' => true, 'special' => true])) {
            $productPrices = ['price_list' => $prices, 'price_type' => $show_price_type];

            if ($prices) {
                foreach ($prices as $price) {
                    if (0 < $price['amount']) {
                        $cid = $price['cid'];
                        $amount = $price['amount'];
                        $productPrice = Money::formatter_symbol($amount, $cid, !$override_usrcurrency);
                        $productPriceRaw = self::parsePrice($productPrice);
                        $productPrice = self::currencySymbol($productPrice, $currency_symbols);
                        $productSpecial = false;
                        if ($price['discount'] && 0 < (float) $price['discount']) {
                            $productSpecialAmount = (float) $amount / (1 - ((float) $price['discount'] / 100));
                            $productSpecial = Money::formatter_symbol($productSpecialAmount, $cid, !$override_usrcurrency);
                            $productSpecialRaw = self::parsePrice($productSpecial);
                            $productSpecial = self::currencySymbol($productSpecial, $currency_symbols);
                        }
                    }

                    $period = View::period($price['time'], $price['period']);
                    $productPrices['filter_prices'][] = ['price' => $productPrice ?? '', 'priceRaw' => $productPriceRaw ?? '', 'special' => $productSpecial ?? '', 'specialRaw' => $productSpecialRaw ?? '', 'period' => $period ?? '', 'period_key' => $price['time'] . '_' . $price['period'], 'discount' => (float) $price['discount'], 'show_price_type' => $show_price_type, 'time' => $price['time']];
                }
            }

            return $productPrices;
        }
        if (isset($prices[0]) && 0 < $prices[0]['amount']) {
            $cid = $prices[0]['cid'];
            $amount = $prices[0]['amount'];
            $price = Money::formatter_symbol($amount, $cid, !$override_usrcurrency);
            $priceRaw = self::parsePrice($price);
            $price = self::currencySymbol($price, $currency_symbols);
            $special = false;
            if ($prices[0]['discount'] && 0 < (float) $prices[0]['discount']) {
                $specialAmount = (float) $amount / (1 - ((float) $prices[0]['discount'] / 100));
                $special = Money::formatter_symbol($specialAmount, $cid, !$override_usrcurrency);
                $specialRaw = self::parsePrice($special);
                $special = self::currencySymbol($special, $currency_symbols);
            }
        }

        if (isset($prices[0])) {
            $period = View::period($prices[0]['time'], $prices[0]['period']);
        }

        $productPrice = ['price' => $price ?? '', 'priceRaw' => $priceRaw ?? '', 'special' => $special ?? '', 'specialRaw' => $specialRaw ?? '', 'period' => $period ?? '', 'discount' => (float) $prices[0]['discount'], 'show_monthly' => 0, 'monthly_calc' => 'default', 'show_price_type' => $show_price_type, 'time' => $prices[0]['time']];
        return $productPrice;
    }

    private static function getPriceInfo(array $prices, string $price_calc = 'default'): array
    {
        $nonePrices = [];
        $monthlyPrices = [];
        $yearlyPrices = [];
        $otherPrices = [];

        foreach ($prices as $price) {
            switch ($price['period']) {
            case 'none':
                $nonePrices[] = $price;
                break;
            case 'month':
                $monthlyPrices[] = $price;
                break;
            case 'year':
                $yearlyPrices[] = $price;
                break;
            default:
                $otherPrices[] = $price;
                break;
            }
        }

        $priceInfo = ['price' => '', 'monthly' => '', 'yearly' => '', 'period' => (isset($prices[0]['period']) ? $prices[0]['period'] : ''), 'cid' => (isset($prices[0]['cid']) ? $prices[0]['cid'] : ''), 'discount' => (isset($prices[0]['discount']) ? $prices[0]['discount'] : ''), 'time' => (isset($prices[0]['time']) ? $prices[0]['time'] : '')];

        if (!empty($nonePrices)) {
            $priceInfo['price'] = $nonePrices[0]['amount'];
            $priceInfo['monthly'] = $nonePrices[0]['amount'];
            $priceInfo['yearly'] = $nonePrices[0]['amount'];
            $priceInfo['period'] = $nonePrices[0]['period'];
            $priceInfo['cid'] = $nonePrices[0]['cid'];
            $priceInfo['discount'] = $nonePrices[0]['discount'];
            $priceInfo['time'] = $nonePrices[0]['time'];
            return $priceInfo;
        }
        if (empty($monthlyPrices) && empty($yearlyPrices)) {
            $firstPrice = $prices[0];
            $priceInfo['price'] = $firstPrice['amount'];
            $priceInfo['monthly'] = $firstPrice['amount'];
            $priceInfo['yearly'] = $firstPrice['amount'];
            $priceInfo['period'] = $nonePrices[0]['period'];
            $priceInfo['cid'] = $firstPrice['cid'];
            $priceInfo['discount'] = $firstPrice['discount'];
            $priceInfo['time'] = $firstPrice['time'];
            return $priceInfo;
        }

        if (!empty($monthlyPrices)) {
            $monthlyPrice = array_filter($monthlyPrices, function($p) {
                return $p['time'] == 1;
            });

            if (!empty($monthlyPrice)) {
                $monthlyPrice = reset($monthlyPrice);
                $priceInfo['monthly'] = $monthlyPrice['amount'];
                $priceInfo['period'] = 'month';
                $priceInfo['cid'] = $monthlyPrice['cid'];
                $priceInfo['discount'] = $monthlyPrice['discount'];
                $priceInfo['time'] = $monthlyPrice['time'];
            }
            else {
                usort($monthlyPrices, function($a, $b) {
                    return $a['time'] <=> $b['time'];
                });
                $monthlyPrice = $monthlyPrices[0];
                $priceInfo['monthly'] = number_format($monthlyPrice['amount'] / $monthlyPrice['time'], 5, '.', '');
                $priceInfo['period'] = 'month';
                $priceInfo['cid'] = $monthlyPrice['cid'];
                $priceInfo['discount'] = $monthlyPrice['discount'];
                $priceInfo['time'] = $monthlyPrice['time'];
            }
        }

        if (!empty($yearlyPrices)) {
            if ($price_calc === 'heighest_year') {
                usort($yearlyPrices, function($a, $b) {
                    return $b['time'] <=> $a['time'];
                });
            }
            else {
                usort($yearlyPrices, function($a, $b) {
                    return $a['time'] <=> $b['time'];
                });
            }

            $yearlyPrice = $yearlyPrices[0];
            $yearlyPrice = $yearlyPrices[0];
            $priceInfo['yearly'] = number_format($yearlyPrice['amount'] / $yearlyPrice['time'], 5, '.', '');
            $priceInfo['cid'] = $yearlyPrice['cid'];
            $priceInfo['discount'] = $yearlyPrice['discount'];
            $priceInfo['time'] = $yearlyPrice['time'];
        }
        if (empty($priceInfo['monthly']) && !empty($priceInfo['yearly'])) {
            if ($price_calc === 'heighest_year') {
                usort($yearlyPrices, function($a, $b) {
                    return $b['time'] <=> $a['time'];
                });
            }
            else {
                usort($yearlyPrices, function($a, $b) {
                    return $a['time'] <=> $b['time'];
                });
            }

            $yearlyPrice = $yearlyPrices[0];
            $priceInfo['monthly'] = number_format($yearlyPrice['amount'] / ($yearlyPrice['time'] * 12), 5, '.', '');
            $priceInfo['period'] = 'month';
            $priceInfo['time'] = $yearlyPrice['time'];
        }
        if (empty($priceInfo['yearly']) && !empty($priceInfo['monthly'])) {
            $priceInfo['yearly'] = number_format($priceInfo['monthly'] * 12, 5, '.', '');
            $priceInfo['period'] = 'month';
            $priceInfo['time'] = 1;
        }

        $priceInfo['price'] = $priceInfo['monthly'] ?: $priceInfo['yearly'];
        return $priceInfo;
    }

    public static function parsePrice(string $price): string
    {
        $priceKey = $parsedPrice = $price;
        $priceCode = '';
        $prefix = '';
        $suffix = '';

        foreach (Money::getCurrencies() as $currency) {
            $price = str_ireplace([$currency['prefix'], $currency['suffix'], $currency['code']], '', $price);
            if (($currency['prefix'] && strpos($priceKey, $currency['prefix']) !== false) || $currency['suffix'] && strpos($priceKey, $currency['suffix']) !== false || $currency['code'] && strpos($priceKey, $currency['code']) !== false) {
                $priceCode = $currency['code'];
                $prefix = $currency['prefix'];
                $suffix = $currency['suffix'];
            }

            $search = [$currency['prefix'], $currency['suffix'], $currency['code']];
            $price = str_replace($search, '', $price);
            $price = trim($price);
            $parsedPrice = Money::parseDecimal($price);
        }

        $returnPrice = '';

        if ($prefix) {
            $returnPrice .= '<sup class="currency-symbol">' . trim($prefix) . '</sup>';
        }

        if (is_array($parsedPrice)) {
            $returnPrice .= $parsedPrice['amount'];

            if (0 < (int) $parsedPrice['decimal']) {
                $returnPrice .= '<sup class="currency-decimal">.' . $parsedPrice['decimal'] . '</sup>';
            }
        }
        else {
            $returnPrice .= $parsedPrice;
        }

        if ($suffix) {
            $returnPrice .= '<sup class="currency-symbol">' . trim($suffix) . '</sup>';
        }
        if (!$prefix && !$suffix) {
            $returnPrice .= '<sup class="currency-symbol"> ' . $priceCode . '</sup>';
        }

        return $returnPrice;
    }

    public static function isJSON(mixed $value): bool
    {
        if (!is_string($value) || trim($value) === '') {
            return false;
        }

        json_decode($value);
        return json_last_error() === JSON_ERROR_NONE;
    }

    public static function unicodeFix(string $string): string
    {
        return preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function(array $matches): string {
            return mb_chr(hexdec($matches[1]), 'UTF-8');
        }, $string);
    }

    private function getItemLink(string $type, string $route, bool $cat = false): string
    {
        $link = '';

        switch ($type) {
        case 'articles':
            $link = ($cat ? Controllers::$init->CRLink('articles_category', [$route]) : Controllers::$init->CRLink('articles_detail', [$route]));
            break;
        case 'references':
            $link = ($cat ? Controllers::$init->CRLink('references_category', [$route]) : Controllers::$init->CRLink('references_detail', [$route]));
            break;
        case 'software':
            $link = ($cat ? Controllers::$init->CRLink('softwares_cat', [$route]) : Controllers::$init->CRLink('software_detail', [$route]));
            break;
        case 'news':
            $link = ($cat ? '' : Controllers::$init->CRLink('news_detail', [$route]));
            break;
        }

        return $link;
    }

    private function checkLink(string $input_link, bool $checkInternal = false): string|bool
    {
        $isInternal = false;

        if (preg_match('/^(http:\\/\\/|https:\\/\\/)/', $input_link)) {
            $fixed_link = $input_link;
        }
        else if (preg_match('/^(www\\.)?[\\w\\-]+\\.[a-z]{2,6}(\\/[\\w\\-\\/]*)?$/i', $input_link)) {
            $fixed_link = 'https://' . $input_link;
        }
        else {
            $isInternal = true;
            $fixed_link = APP_URI . '/' . ltrim($input_link, '/');
        }

        return ($checkInternal ? $isInternal : $fixed_link);
    }

    public function getAssets(): array
    {
        return $this->assets;
    }

    public function getStyles(string $page): array|string
    {
        return $this->styles[$page] ?? '';
    }

    public function getScripts(string $page, string $position = 'footer'): string
    {
        $scripts = '';
        if (isset($this->scripts[$position]) && isset($this->scripts[$position][$page])) {
            $scripts .= $this->scripts[$position][$page];
        }

        return $scripts;
    }

    public function getHeaderCodes(string $page): string
    {
        if (isset($this->headerCodes[$page])) {
            return $this->headerCodes[$page];
        }

        return '';
    }

    public function registerWidgetAsset(mixed $asset): void
    {
        $this->addAsset($asset);
    }

    public function registerWidgetStyle(string $page, string $style): void
    {
        if (($page == '') || $style == '') {
            return;
        }

        $this->addStyle($page, $style);
    }

    public function registerWidgetScript(string $position, string $page, string $script): void
    {
        if (($position == '') || $page == '' || $script == '') {
            return;
        }

        $this->addScript($position, $page, $script);
    }

    private function addAsset(mixed $asset): void
    {
        if (is_array($asset)) {
            foreach ($asset as $item) {
                if (!in_array($item, $this->assets)) {
                    $this->assets[] = $item;
                }
            }
        }
        else if (!in_array($asset, $this->assets)) {
            $this->assets[] = $asset;
        }
    }

    private function addScript(string $position, string $page, string $script): void
    {
        if (isset($this->scripts[$position][$page])) {
            $this->scripts[$position][$page] .= $script;
        }
        else {
            $this->scripts[$position][$page] = $script;
        }
    }

    private function addStyle(string $page, string $style): void
    {
        if (isset($this->styles[$page])) {
            $this->styles[$page] .= $style;
        }
        else {
            $this->styles[$page] = $style;
        }
    }

    private function addHeaderCode(string $page, string $code): void
    {
        if (isset($this->headerCodes[$page])) {
            $this->headerCodes[$page] .= $code;
        }
        else {
            $this->headerCodes[$page] = $code;
        }
    }

    private function parseButtons(array $items, string|int $moduleId, array $pageData, object|string|null $align = NULL): string
    {
        $widgetId = 'fon-widget-' . $moduleId;
        $buttonCount = count($items);
        $style = '';

        if (!is_object($align)) {
            $rawAlign = (is_string($align) ? trim($align) : '');

            $textAlign = match ($rawAlign) {
                left => 'start',
                center => 'center',
                right => 'end',
                default => 'center'
            };
            $align = new stdClass();
            $align->xs = $align->sm = $align->md = $align->lg = $align->xl = $textAlign;
        }

        $hasBlockButton = false;

        foreach ($items as $item) {
            if (isset($item->block_button) && $item->block_button === 'yes') {
                $hasBlockButton = true;
            }
            else {
            }
        }

        $alignClass = ($align ? 'text-' . $align->xs . ' text-sm-' . $align->sm . ' text-md-' . $align->md . ' text-lg-' . $align->lg . ' text-xl-' . $align->xl : 'text-center');
        $groupClass = (1 < $buttonCount ? 'fon-widget-button-group' : 'fon-button-wrapper');
        $gridClass = ($hasBlockButton ? ' d-grid' : '');
        $output = '';
        $output .= '<div class="' . $alignClass . ' ' . $groupClass . $gridClass . '">';

        foreach ($items as $key => $item) {
            $button_style = ($item->button_style ?? '') ?: 'default';
            $button_custom_style = ($item->button_custom_style ?? '') ?: 'default';
            $button_type = ($item->button_type ?? '') ?: 'default';
            $button_shape = ($item->button_shape ?? '') ?: 'round';
            $button_size = (isset($item->button_size) && $item->button_size !== 'default' ? $item->button_size : '');
            $button_rel = $item->button_rel ?? [];
            $scroll_button = isset($item->scroll_button) && $item->scroll_button === 'yes';
            $button_target = ($item->button_target ?? '') ?: '_self';
            $class = '';
            $class .= (($button_style === 'outline') && $button_type !== 'custom' ? '-' . $button_style : '');
            $class .= ($button_type ? '-' . $button_type : '');
            $class .= (($button_style === 'gradient') && $button_type !== 'custom' ? ' btn-style-' . $button_style : '');
            $class .= ($button_size ? ' btn-' . $button_size : '');
            $class .= ($button_shape !== 'round' ? ' btn-' . $button_shape : '');
            $rawLink = $item->button_link ?? '';
            $link = (isset($rawLink->{$this->lang}) && $rawLink->{$this->lang} ? $rawLink->{$this->lang} : array_values((array) $rawLink)[0] ?? '');
            $isInternal = false;

            if ($link) {
                $isInternal = self::checkLink($link, true);
            }

            $attribs = 'id="btn-' . ($moduleId . $key) . '"';
            if (!empty($button_rel) && !$scroll_button) {
                $attribs .= ' rel="' . implode(' ', (array) $button_rel) . '"';
            }

            $attribs .= ' target="' . $button_target . '"';
            if ($scroll_button && $isInternal) {
                $class .= ' fon-scroll-button';
            }

            $rawText = $item->button_text ?? '';
            $text = (isset($rawText->{$this->lang}) && $rawText->{$this->lang} ? $rawText->{$this->lang} : array_values((array) $rawText)[0] ?? '');
            $show_icon = isset($item->show_button_icon) && $item->show_button_icon === 'yes';
            $icon = $item->button_icon ?? '';
            $icon_position = $item->button_icon_position ?? 'left';
            if ($show_icon && $icon) {
                $iconTag = '<i class="' . $icon . '" aria-hidden="true"></i>';
                $text = ($icon_position === 'left' ? $iconTag . ' ' . $text : $text . ' ' . $iconTag);
            }

            $hrefTag = (!empty($link) ? 'href="' . $link . '"' : '');
            $output .= '<a ' . $hrefTag . ' ' . $attribs . ' class="btn btn' . $class . '">' . $text . '</a>';
            $fontProperties = (isset($item->button_font) ? self::parseFontProperties($item->button_font) : '');
            if (($button_type === 'custom') || $button_type === 'link' || $button_size === 'custom' || $fontProperties) {
                $style .= '#btn-' . ($moduleId . $key) . '{';
                $style .= $fontProperties;
                if (($button_type === 'custom') || $button_type === 'link') {
                    $style .= (isset($item->button_color_normal) && $item->button_color_normal ? '--bs-btn-color:' . $item->button_color_normal . ';' : '');
                    $style .= (isset($item->button_color_hover) && $item->button_color_hover ? '--bs-btn-hover-color:' . $item->button_color_hover . ';' : '');
                }

                if ($button_type === 'custom') {
                    if ($button_custom_style === 'default') {
                        if (isset($item->button_background_normal) && $item->button_background_normal) {
                            $style .= '--bs-btn-bg:' . $item->button_background_normal . ';';
                        }
                        if (isset($item->button_background_hover) && $item->button_background_hover) {
                            $style .= '--bs-btn-hover-bg:' . $item->button_background_hover . ';';
                        }
                        if (isset($item->button_border_normal) && $item->button_border_normal) {
                            $style .= '--bs-btn-border-color:' . $item->button_border_normal . ';';
                        }
                        else if (isset($item->button_background_normal)) {
                            $style .= '--bs-btn-border-color:' . $item->button_background_normal . ';';
                        }
                        if (isset($item->button_border_hover) && $item->button_border_hover) {
                            $style .= '--bs-btn-hover-border-color:' . $item->button_border_hover . ';';
                        }
                        else if (isset($item->button_background_hover)) {
                            $style .= '--bs-btn-hover-border-color:' . $item->button_background_hover . ';';
                        }
                    }
                    else if ($button_custom_style === 'gradient') {
                        $style .= '--bs-btn-border-width:0;';
                        $style .= (isset($item->button_gradient_normal) && $item->button_gradient_normal ? self::parseGradient($item->button_gradient_normal, 'normal') : '');
                        $style .= (isset($item->button_gradient_hover) && $item->button_gradient_hover ? self::parseGradient($item->button_gradient_hover, 'hover') : '');
                        $style .= 'background-image: var(--bs-normal-gradient);';
                    }
                }

                $style .= '}';
                if (($button_type === 'custom') && $button_custom_style === 'gradient') {
                    $style .= '#btn-' . ($moduleId . $key) . ':hover{';
                    if (isset($item->button_gradient_hover) && $item->button_gradient_hover) {
                        $style .= 'background-image: var(--bs-hover-gradient);';
                    }

                    $style .= '}';
                }
                if (($button_size === 'custom') && isset($item->button_padding)) {
                    $responsiveItems = [];
                    $responsiveItems['#btn-' . $moduleId . $key][] = ['type' => 'padding', 'value' => $item->button_padding];
                    $style .= self::parseResponsiveItems($responsiveItems);
                }
            }
        }

        $output .= '</div>';

        if ($style) {
            $pageName = $pageData['page'] ?? 'index';
            $this->addStyle($pageName, $style);
        }

        return $output;
    }

    private function parseButton(object $item, string|int $moduleId, array $pageData, array $btnProperties = []): string
    {
        $style = '';
        $buttonId = $btnProperties['id'] ?? ('fon-btn-' . $moduleId . '-' . bin2hex(random_bytes(3)));
        $attribs = ' id="' . $buttonId . '"';
        $button_style = ($item->button_style ?? '') ?: 'default';
        $button_custom_style = ($item->button_custom_style ?? '') ?: 'default';
        $button_type = ($item->button_type ?? '') ?: 'default';
        $button_shape = ($item->button_shape ?? '') ?: 'rounded';
        $button_size = (isset($item->button_size) && $item->button_size !== 'default' ? $item->button_size : '');
        $link = $item->button_link ?? '';

        if (is_object($link)) {
            $link = (isset($link->{$this->lang}) && $link->{$this->lang} ? $link->{$this->lang} : array_values((array) $link)[0] ?? '');
        }

        $rawText = $item->button_text ?? '';
        $text = (isset($rawText->{$this->lang}) && $rawText->{$this->lang} ? $rawText->{$this->lang} : array_values((array) $rawText)[0] ?? '');
        $show_icon = isset($item->show_button_icon) && $item->show_button_icon === 'yes';
        $icon = $item->button_icon ?? '';
        $icon_position = $item->button_icon_position ?? 'left';
        $scrollButton = isset($item->scroll_button) && $item->scroll_button === 'yes';
        $button_rel = (array) ($item->button_rel ?? []);
        $button_target = ($item->button_target ?? '') ?: '_self';
        $class = '';
        $class .= (($button_style === 'outline') && $button_type !== 'custom' ? '-' . $button_style : '');
        $class .= ($button_type ? '-' . $button_type : '');
        $class .= (($button_style === 'gradient') && $button_type !== 'custom' ? ' btn-style-' . $button_style : '');
        $class .= ($button_size && $button_size !== 'custom' ? ' btn-' . $button_size : '');
        $class .= ($button_shape !== 'round' ? ' btn-' . $button_shape : '');
        $class .= (isset($item->block_button) && $item->block_button === 'yes' ? ' btn-block' : '');

        if (!empty($btnProperties)) {
            if (!empty($btnProperties['class'])) {
                $class .= ' ' . $btnProperties['class'];
            }
            if (isset($btnProperties['disabled']) && $btnProperties['disabled'] === 'true') {
                $class .= ' disabled';
            }

            if (!empty($btnProperties['attributes'])) {
                $attribs .= ' ' . $btnProperties['attributes'];
            }
        }

        $isInternal = false;
        if ($link && is_string($link)) {
            $isInternal = self::checkLink($link, true);
        }
        if ($scrollButton && $isInternal) {
            $class .= '  fon-scroll-button';
        }

        if (!empty($button_rel)) {
            $attribs .= ' rel="' . implode(' ', $button_rel) . '"';
        }

        if ($button_target) {
            $attribs .= ' target="' . $button_target . '"';
        }
        if ($show_icon && $icon) {
            $iconTag = '<i class="' . $icon . '" aria-hidden="true"></i>';
            $text = ($icon_position === 'left' ? $iconTag . ' ' . $text : $text . ' ' . $iconTag);
        }
        if (!empty($btnProperties['data']) && is_array($btnProperties['data'])) {
            foreach ($btnProperties['data'] as $bdk => $btnData) {
                $formattedData = (is_array($btnData) ? htmlspecialchars(json_encode($btnData, JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8') : htmlspecialchars((string) $btnData, ENT_QUOTES, 'UTF-8'));
                $attribs .= ' data-' . $bdk . '=\'' . $formattedData . '\'';
            }
        }

        $output = '';

        if (!empty($btnProperties['is_btn'])) {
            $output .= '<button class="btn btn' . $class . '" ' . $attribs;

            if (!empty($btnProperties['type'])) {
                $output .= ' type="' . $btnProperties['type'] . '"';
            }
            if (isset($btnProperties['disabled']) && $btnProperties['disabled']) {
                $output .= ' aria-disabled="' . $btnProperties['disabled'] . '"';
            }

            $output .= '>' . $text . '</button>';
        }
        else {
            $hrefTag = (!empty($link) ? 'href="' . $link . '"' : '');
            $output .= '<a ' . $hrefTag . ' ' . $attribs . ' class="btn btn' . $class . '">' . $text . '</a>';
        }
        $fontProperties = (isset($item->button_font) && $item->button_font ? self::parseFontProperties($item->button_font) : '');
        if (($button_type === 'custom') || $button_type === 'link' || $button_size === 'custom' || $fontProperties) {
            $style .= '#' . $buttonId . '{';
            $style .= $fontProperties;
            if (($button_type === 'custom') || $button_type === 'link') {
                $style .= (isset($item->button_color_normal) && $item->button_color_normal ? '--bs-btn-color:' . $item->button_color_normal . ';' : '');
                $style .= (isset($item->button_color_hover) && $item->button_color_hover ? '--bs-btn-hover-color:' . $item->button_color_hover . ';' : '');
            }

            if ($button_type === 'custom') {
                if ($button_custom_style === 'default') {
                    if (isset($item->button_background_normal) && $item->button_background_normal) {
                        $style .= '--bs-btn-bg:' . $item->button_background_normal . ';';
                    }
                    if (isset($item->button_background_hover) && $item->button_background_hover) {
                        $style .= '--bs-btn-hover-bg:' . $item->button_background_hover . ';';
                    }
                    if (isset($item->button_border_normal) && $item->button_border_normal) {
                        $style .= '--bs-btn-border-color:' . $item->button_border_normal . ';';
                    }
                    else if (isset($item->button_background_normal)) {
                        $style .= '--bs-btn-border-color:' . $item->button_background_normal . ';';
                    }
                    if (isset($item->button_border_hover) && $item->button_border_hover) {
                        $style .= '--bs-btn-hover-border-color:' . $item->button_border_hover . ';';
                    }
                    else if (isset($item->button_background_hover)) {
                        $style .= '--bs-btn-hover-border-color:' . $item->button_background_hover . ';';
                    }
                }
                else if ($button_custom_style === 'gradient') {
                    $style .= '--bs-btn-border-width:0;';
                    $style .= (isset($item->button_gradient_normal) && $item->button_gradient_normal ? self::parseGradient($item->button_gradient_normal, 'normal') : '');
                    $style .= (isset($item->button_gradient_hover) && $item->button_gradient_hover ? self::parseGradient($item->button_gradient_hover, 'hover') : '');
                    $style .= 'background-image: var(--bs-normal-gradient);';
                }
            }

            $style .= '}';
            if (($button_type === 'custom') && $button_custom_style === 'gradient') {
                $style .= '#' . $buttonId . ':hover{';
                if (isset($item->button_gradient_hover) && $item->button_gradient_hover) {
                    $style .= 'background-image: var(--bs-hover-gradient);';
                }

                $style .= '}';
            }
            if (($button_size === 'custom') && isset($item->button_padding)) {
                $responsiveItems = [];
                $responsiveItems['#' . $buttonId][] = ['type' => 'padding', 'value' => $item->button_padding];
                $style .= self::parseResponsiveItems($responsiveItems);
            }
        }

        if ($style) {
            $pageName = $pageData['page'] ?? 'index';
            $this->addStyle($pageName, $style);
        }

        return $output;
    }

    public static function parseFontProperties(object $properties, bool $align = true): string
    {
        $style = [];

        if ($properties) {
            foreach ($properties as $key => $property) {
                if (is_object($property)) {
                    if ($key == 'font-style') {
                        if (isset($property->underline) && $property->underline) {
                            $style[] = 'text-decoration:underline!important';
                        }
                        if (isset($property->italic) && $property->italic) {
                            $style[] = 'font-style:italic!important';
                        }
                        if (isset($property->uppercase) && $property->uppercase) {
                            $style[] = 'text-transform:uppercase!important';
                        }
                    }
                    else if ($key == 'text-align') {
                        if ($align) {
                            if (isset($property->left) && $property->left) {
                                $style[] = $key . ':left!important';
                            }
                            else if (isset($property->center) && $property->center) {
                                $style[] = $key . ':center!important';
                            }
                            else if (isset($property->right) && $property->right) {
                                $style[] = $key . ':right!important';
                            }
                        }
                    }
                    else if (isset($property->value) && $property->value) {
                        $style[] = $key . ':' . $property->value . $property->unit . '!important';
                    }
                }
                else if ($property) {
                    $style[] = $key . ':' . $property . '!important';
                }
            }
        }

        if ($style) {
            return implode(';', $style) . ';';
        }

        return '';
    }

    public static function parseResponsiveItems(array $responsiveItems = [], string $widgetId = ''): string
    {
        $style = '';
        $breakpoints = [];
        $mediaQueries = ['xxl' => '1400px', 'xl' => '1200px', 'lg' => '1199.98px', 'md' => '991.98px', 'sm' => '767.98px', 'xs' => '575.98px'];

        if ($responsiveItems) {
            foreach ($responsiveItems as $selector => $items) {
                foreach ($items as $item) {
                    $itemBreakPoints = $item['value'] ?? (object) [];

                    if ($itemBreakPoints) {
                        foreach ($itemBreakPoints as $itemBreakPoint => $breakPointvalue) {
                            if (($breakPointvalue !== '') && $breakPointvalue !== null) {
                                $breakpoints[$itemBreakPoint][$selector][] = ['type' => $item['type'], 'unit' => $item['unit'] ?? '', 'value' => $breakPointvalue];
                            }
                        }
                    }
                }
            }
        }

        if ($breakpoints) {
            $largestKey = NULL;

            if (isset($breakpoints['xxl'])) {
                $largestKey = 'xxl';
            }
            else if (isset($breakpoints['xl'])) {
                $largestKey = 'xl';
            }
            if ($largestKey && isset($breakpoints[$largestKey])) {
                foreach ($breakpoints[$largestKey] as $selector => $breakpointItem) {
                    if ($widgetId) {
                        $style .= '#' . $widgetId . ' ';
                    }

                    $style .= $selector . '{';

                    foreach ($breakpointItem as $item) {
                        $style .= $item['type'] . ': ' . $item['value'] . $item['unit'] . ';';
                    }

                    $style .= '}';
                }
            }

            $orderedBreakpoints = array_keys($mediaQueries);

            foreach ($orderedBreakpoints as $breakpoint) {
                if ($breakpoint == $largestKey) {
                    continue;
                }

                if (isset($breakpoints[$breakpoint])) {
                    $style .= '@media(max-width:' . $mediaQueries[$breakpoint] . '){';

                    foreach ($breakpoints[$breakpoint] as $selector => $breakpointItem) {
                        if ($widgetId) {
                            $style .= '#' . $widgetId . ' ';
                        }

                        $style .= $selector . '{';

                        foreach ($breakpointItem as $item) {
                            $style .= $item['type'] . ': ' . $item['value'] . $item['unit'] . ';';
                        }

                        $style .= '}';
                    }

                    $style .= '}';
                }
            }
        }

        return $style;
    }

    private static function parseGradient(object $gradient, string $bs_gradient = ''): string
    {
        $style = '';
        if (!empty($gradient->sc) && !empty($gradient->ec)) {
            $gradientType = $gradient->gt ?? 'linear';
            $startColorPos = $gradient->scp ?? 0;
            $endColorPos = $gradient->ecp ?? 100;
            $style .= ($bs_gradient !== '' ? '--bs-' . $bs_gradient . '-gradient: ' : 'background-image: ');

            $gradientDetails = match ($gradientType) {
                linear => ($gradient->lga ?? 180) . 'deg',
                radial => 'at ' . str_replace('_', ' ', $gradient->rga ?? 'center'),
                default => '180deg'
            };
            $style .= $gradientType . '-gradient(' . $gradientDetails . ', ' . $gradient->sc . ' ' . $startColorPos . '%, ' . $gradient->ec . ' ' . $endColorPos . '%);';
        }

        return $style;
    }

    public static function validateAndNormalizeColor(string $colorInput): array
    {
        if (preg_match('/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6,8})$/', $colorInput)) {
            if ((strlen($colorInput) === 4) || strlen($colorInput) === 5) {
                $hexColor = '#' . str_repeat($colorInput[1], 2) . str_repeat($colorInput[2], 2) . str_repeat($colorInput[3], 2);

                if (strlen($colorInput) === 5) {
                    $hexColor .= str_repeat($colorInput[4], 2);
                }
            }
            else {
                $hexColor = strtolower($colorInput);
            }

            if (strlen($hexColor) === 9) {
                $alpha = substr($hexColor, -2);
                $hexColor = substr($hexColor, 0, 7);
            }
            else {
                $alpha = 'FF';
            }

            return ['color' => self::hexToRgb($hexColor), 'alpha' => round(hexdec($alpha) / 255, 2)];
        }

        if (preg_match('/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*([\\d.]+))?\\)/i', $colorInput, $matches)) {
            $red = (int) $matches[1];
            $green = (int) $matches[2];
            $blue = (int) $matches[3];
            $alpha = (isset($matches[4]) ? (float) $matches[4] : 1);
            return ['color' => $red . ',' . $green . ',' . $blue, 'alpha' => strval($alpha)];
        }

        if (preg_match('/hsla?\\((\\d+),\\s*(\\d+)%?,\\s*(\\d+)%?(?:,\\s*([\\d.]+))?\\)/i', $colorInput, $matches)) {
            $hue = (int) $matches[1];
            $saturation = (int) $matches[2];
            $lightness = (int) $matches[3];
            $alpha = (isset($matches[4]) ? (float) $matches[4] : 1);
            $rgb = self::hslToRgb([$hue, $saturation, $lightness]);
            return ['color' => $rgb, 'alpha' => $alpha];
        }

        return ['color' => $colorInput, 'alpha' => 1];
    }

    public static function hexToRgb(string $hexColor): string
    {
        $hexColor = ltrim($hexColor, '#');
        $r = hexdec(substr($hexColor, 0, 2));
        $g = hexdec(substr($hexColor, 2, 2));
        $b = hexdec(substr($hexColor, 4, 2));
        return $r . ',' . $g . ',' . $b;
    }

    public static function rgbToHex(array $rgbArray): string
    {
        list($r, $g, $b) = $rgbArray;
        return sprintf('#%02X%02X%02X', $r, $g, $b);
    }

    public static function rgbToHsl(array $rgbArray): string
    {
        list($r, $g, $b) = $rgbArray;
        $r /= 255;
        $g /= 255;
        $b /= 255;
        $max = max($r, $g, $b);
        $min = min($r, $g, $b);
        $h = $s = $l = ($max + $min) / 2;

        if ($max === $min) {
            $h = $s = 0;
        }
        else {
            $d = $max - $min;
            $s = (0.5 < $l ? $d / (2 - $max - $min) : $d / ($max + $min));

            switch ($max) {
            case $r:
                $h = (($g - $b) / $d) + ($g < $b ? 6 : 0);
                break;
            case $g:
                $h = (($b - $r) / $d) + 2;
                break;
            default:
                $h = (($r - $g) / $d) + 4;
                break;
            }

            $h /= 6;
        }

        $h = round($h * 360, 2);
        $s = round($s * 100, 2);
        $l = round($l * 100, 2);
        return $h . ' ' . $s . '%';
    }

    public static function hslToRgb(array $hslArray): string
    {
        list($h, $s, $l) = $hslArray;
        $h /= 360;
        $s /= 100;
        $l /= 100;

        if ($s == 0) {
            $r = $g = $b = $l;
        }
        else {
            $func = function($p, $q, $t) {
                if ($t < 0) {
                    $t += 1;
                }

                if (1 < $t) {
                    $t -= 1;
                }

                if ($t < 0.16666666666666666) {
                    return $p + ($t * (($q - $p) * 6));
                }

                if ($t < 0.5) {
                    return $q;
                }

                if ($t < 0.6666666666666666) {
                    return $p + (($q - $p) * (0.6666666666666666 - $t) * 6);
                }

                return $p;
            };
            $q = ($l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($l * $s));
            $p = ($l * 2) - $q;
            $r = $func($p, $q, $h + 0.3333333333333333);
            $g = $func($p, $q, $h);
            $b = $func($p, $q, $h - 0.3333333333333333);
        }

        $r = (int) round($r * 255);
        $g = (int) round($g * 255);
        $b = (int) round($b * 255);
        return $r . ',' . $g . ',' . $b;
    }

    public static function hexToHsl(string $hexColor): string
    {
        $rgbArray = self::hexToRgb($hexColor);
        $rgbArray = explode(',', $rgbArray);
        return self::rgbToHsl($rgbArray);
    }

    public static function hslToHex(array $hslArray): string
    {
        $rgbArray = self::hslToRgb($hslArray);
        $rgbArray = explode(',', $rgbArray);
        return self::rgbToHex($rgbArray);
    }

    public static function assetLinkDetermine(string $src, bool $isImage = true): string
    {
        if (strpos($src, 'http://') !== false || strpos($src, 'https://') !== false) {
            if (defined('APP_URI') && strpos($src, APP_URI) === false) {
                return $src;
            }
        }

        $path = parse_url($src, PHP_URL_PATH);

        if ($path) {
            $src = $path;
        }

        $cleanSrc = ltrim($src, '/');

        if (empty($cleanSrc)) {
            return '';
        }

        $asset_src = '';

        if ($isImage) {
            $info = pathinfo($cleanSrc);
            $directory = $info['dirname'];

            if ($directory === '.') {
                $directory = '';
            }

            if ($directory) {
                $directory = trim($directory, '/') . '/';
            }
            else {
                $directory = '/';
            }

            $asset_src = Utility::image_link_determiner($info['basename'], $directory);
        }
        else {
            $asset_src = '/' . $cleanSrc;
        }

        return $asset_src;
    }

    public function get_css_url(): string
    {
        return Controllers::$init->CRLink('templates/website/' . $this->name . '/css/fononline.min.css', false, 'none') . '?version=' . License::get_version();
    }

    public static function getHeaderMenu(array $list = [], bool $children = false, array $opt = [], int $childCount = 0): string
    {
        $menuFontSize = Config::get('theme/fonts/menu/size');
        $menuFontWeight = Config::get('theme/fonts/menu/weight');
        $mobile = isset($opt['mobile']) && $opt['mobile'];
        $output = '';

        if ($children) {
            $output .= '<ul class="' . (0 < $childCount ? 'child-' . $childCount : '') . ' ' . ($mobile ? 'inner' : '') . '">';
        }

        $i = $childCount;

        foreach ($list as $menu) {
            $mega = false;
            $tag = false;

            if (isset($menu['extra']['mega']['header_' . $opt['header_type']])) {
                $mega = $menu['extra']['mega']['header_' . $opt['header_type']];
            }

            if (isset($menu['extra']['tag'])) {
                $tag = $menu['extra']['tag'];
            }

            $menuClass = '';
            $menuWidth = '';

            if (!$children) {
                if ($mega) {
                    $menuClass = 'megamenuli';

                    if ($menu['icon']) {
                        if (!str_contains($menu['icon'], 'fa-')) {
                            if ($menu['icon'] == 'full') {
                                $menuClass .= ' full-width';
                            }
                            else {
                                $menuClass .= ' position-relative';
                                $menuWidth = $menu['icon'] . 'px';
                            }
                        }
                    }
                }
                else if ($menu['children']) {
                    $menuClass = 'flatmenuli';
                }
            }
            if ($menu['children'] || $mega) {
                $menu['link'] = 'javascript:void 0;';
            }
            $output .= '<li class="nav-item ' . $menuClass . ' ' . ($menu['children'] || $mega ? 'has-child' : '') . '">';
            $output .= '<a href="' . $menu['link'] . '" ' . ($menu['target'] ? ' target="_blank"' : '') . ' class="nav-link ' . ($mobile && $menu['children'] || $mega ? 'toggle' : '') . '" style="font-size:' . $menuFontSize . 'px;font-weight:' . $menuFontWeight . ';">';

            if ($tag) {
                $output .= '<span class="menu_tag" ' . ($tag['color'] != '' ? 'style="--menu-tag-background:' . $tag['color'] . ';"' : '') . '>' . self::getPriceHolders($tag['name']) . '</span>';
            }

            $output .= (isset($opt['span']) ? '<span class="menu-title">' : '');
            $output .= ($menu['icon'] && !$menuWidth ? '<i class="' . $menu['icon'] . '" aria-hidden="true"></i> ' : '');
            $output .= $menu['title'];
            $output .= (isset($opt['span']) ? '</span>' : '');
            $output .= ($menu['children'] || $mega ? ' <i class="fa-solid fa-angle-down"></i>' : '');
            $output .= '</a>';
            if (!$children && $mega) {
                $output .= '<div class="megamenu-container ' . ($mobile ? 'inner' : '') . ' ' . ($menuWidth ? 'has-width' : '') . '" ' . ($menuWidth ? 'style="width:' . $menuWidth . '; left:50%; transform:translateX(-' . ($menu['icon'] / 2) . 'px)"' : '') . '>';
                $output .= '<div class="container">';
                $output .= '<ul class="megamenu p-0">';
                $mega = self::getPriceHolders($mega);
                $output .= Utility::text_replace($mega, ['{SITE_URL}' => APP_URI . '/', '{TEMPLATE_URL}' => $opt['template_address']]);
                $output .= '</ul>';
                $output .= '</div>';
                $output .= '</div>';
            }
            if ($menu['children'] && !$mega) {
                ++$i;
                $output .= static::getHeaderMenu($menu['children'], true, $opt, $i);
            }

            $output .= '</li>' . PHP_EOL;
        }

        $output .= ($children ? '</ul>' . PHP_EOL : '');
        return $output;
    }

    public static function getFooterMenu(array $list = [], bool $children = false, array $opt = []): string
    {
        $footerMenu = '';

        foreach ($list as $menu) {
            if (!$children) {
                $footerMenu .= '<div class="col footer-menu-links">';
                $footerMenu .= '<div class="dropdown">';
            }
            else {
                $footerMenu .= '<li>';
            }

            $footerMenu .= '<a';
            $footerMenu .= (!$children ? ' class="dropdown-toggle" role="button" data-bs-toggle="dropdown" ' : ' class="dropdown-item" ');

            if ($menu['link'] != '') {
                $footerMenu .= ' href="' . $menu['link'] . '"';
                $footerMenu .= ($menu['target'] ? ' target="_blank"' : '');
            }

            $footerMenu .= '>';
            $footerMenu .= (!$children ? '<h3 class="footer-menu-header">' : '');
            $footerMenu .= (!empty($menu['icon']) ? '<i class="' . $menu['icon'] . '" aria-hidden="true"></i>' : '');
            $footerMenu .= $menu['title'];
            $footerMenu .= (!$children ? '</h3>' : '');
            $footerMenu .= '</a>';

            if ($children) {
                $footerMenu .= '</li>';
            }

            if ($menu['children']) {
                $footerMenu .= '<ul class="dropdown-menu footer-menu-list mb-4 mb-lg-0">';
                $footerMenu .= static::getFooterMenu($menu['children'], true, $opt);
                $footerMenu .= '</ul>';
            }

            if (!$children) {
                $footerMenu .= '</div>';
                $footerMenu .= '</div>';
            }
        }

        return $footerMenu;
    }

    public static function getClientAreaMenu(array $list = [], bool $children = false, array $opt = []): string
    {
        $pname = $opt['pname'] ?? '';
        $gtype = $opt['gtype'] ?? '';
        $acheader_info = $opt['acheader_info'] ?? '';
        $menu_links = $opt['menu_links'] ?? '';
        $visibility_ticket = $opt['visibility_ticket'] ?? '';
        $visibility_invoice = $opt['visibility_invoice'] ?? '';
        $domain_total = $opt['domain_total'] ?? 0;
        $software_total = $opt['software_total'] ?? 0;
        $sms_total = $opt['sms_total'] ?? 0;
        $hosting_total = $opt['hosting_total'] ?? 0;
        $server_total = $opt['server_total'] ?? 0;
        $special_total = $opt['special_total'] ?? 0;
        $special_list = $opt['special_list'] ?? [];
        $category = $opt['category'] ?? [];
        $ul_active = (isset($opt['active']) ? $opt['active'] : false);
        $pagebuilder = $opt['pagebuilder'] ?? false;
        $output = '';

        if ($children) {
            $output .= '<ul';
            $output .= ' class="inner list-group list-group-flush ' . ($ul_active ? ' show' : '') . '"';

            if ($ul_active) {
                $output .= ' style="display:block;"';
            }

            $output .= '>';
        }

        foreach ($list as $menu) {
            if ($menu['id'] == 'FonPageBuilder') {
                continue;
            }
            if (($menu['page'] == 'ca-tickets') && !$visibility_ticket) {
                continue;
            }
            if (($menu['page'] == 'ca-invoices') && !$visibility_invoice) {
                continue;
            }
            if ($menu['onlyCa'] && !$acheader_info) {
                continue;
            }
            if (($menu['page'] == 'create-account') && $acheader_info) {
                continue;
            }
            if (($menu['page'] == 'login-account') && $acheader_info) {
                continue;
            }
            if (($menu['page'] == 'product-group/domain') && !Config::get('options/pg-activation/domain')) {
                continue;
            }
            if (($menu['page'] == 'product-group/hosting') && !Config::get('options/pg-activation/hosting')) {
                continue;
            }
            if (($menu['page'] == 'product-group/server') && !Config::get('options/pg-activation/server')) {
                continue;
            }
            if (($menu['page'] == 'product-group/software') && !Config::get('options/pg-activation/software')) {
                continue;
            }
            if (($menu['page'] == 'product-group/sms') && !Config::get('options/pg-activation/sms')) {
                continue;
            }
            if ((($menu['page'] == 'product-group/international-sms') || $menu['page'] == 'ca-intl-sms') && !Config::get('options/pg-activation/international-sms')) {
                continue;
            }
            if (($menu['page'] == 'ca-affiliate') && !Config::get('options/affiliate/status')) {
                continue;
            }
            if (($menu['page'] == 'ca-reseller') && !Config::get('options/dealership/status')) {
                continue;
            }
            if (($menu['page'] == 'ca-reseller') && !Config::get('options/dealership/view-without-membership') && isset($acheader_info['dealership']['status']) && $acheader_info['dealership']['status'] == 'inactive') {
                continue;
            }
            if (($menu['page'] == 'ca-domains') && !Config::get('options/pg-activation/domain') && $domain_total < 1) {
                continue;
            }
            if (($menu['page'] == 'ca-orders') && !$menu['children']) {
                if (0 < $hosting_total) {
                    $menu['children'][] = [
                        'id'       => 'hosting',
                        'parent'   => $menu['id'],
                        'icon'     => '',
                        'rank'     => 0,
                        'target'   => 0,
                        'status'   => 'active',
                        'page'     => 'ca-order-group',
                        'onlyCa'   => 1,
                        'link'     => $menu_links['menu-2-2'],
                        'title'    => __('website/account/sidebar-menu-2-sub-hosting'),
                        'children' => []
                    ];
                }

                if (0 < $server_total) {
                    $menu['children'][] = [
                        'id'       => 'server',
                        'parent'   => $menu['id'],
                        'icon'     => '',
                        'rank'     => 0,
                        'target'   => 0,
                        'status'   => 'active',
                        'page'     => 'ca-order-group',
                        'onlyCa'   => 1,
                        'link'     => $menu_links['menu-2-3'],
                        'title'    => __('website/account/sidebar-menu-2-sub-server'),
                        'children' => []
                    ];
                }

                if (0 < $software_total) {
                    $menu['children'][] = [
                        'id'       => 'software',
                        'parent'   => $menu['id'],
                        'icon'     => '',
                        'rank'     => 0,
                        'target'   => 0,
                        'status'   => 'active',
                        'page'     => 'ca-order-group',
                        'onlyCa'   => 1,
                        'link'     => $menu_links['menu-2-0'],
                        'title'    => __('website/account/sidebar-menu-2-sub-software'),
                        'children' => []
                    ];
                }

                if (0 < $sms_total) {
                    $menu['children'][] = [
                        'id'       => 'sms',
                        'parent'   => $menu['id'],
                        'icon'     => '',
                        'rank'     => 0,
                        'target'   => 0,
                        'status'   => 'active',
                        'page'     => 'ca-order-group',
                        'onlyCa'   => 1,
                        'link'     => $menu_links['menu-2-1'],
                        'title'    => __('website/account/sidebar-menu-2-sub-sms'),
                        'children' => []
                    ];
                }
                if ((0 < $special_total) && $special_list) {
                    foreach ($special_list as $group) {
                        if ($group['parent'] != 0) {
                            continue;
                        }

                        $menu['children'][] = [
                            'id'       => 'special-' . $group['id'],
                            'parent'   => $menu['id'],
                            'icon'     => '',
                            'rank'     => 0,
                            'target'   => 0,
                            'status'   => 'active',
                            'page'     => 'ca-order-group',
                            'onlyCa'   => 1,
                            'link'     => $menu_links['menu-2-4'] . '?category=' . $group['id'],
                            'title'    => $group['name'],
                            'children' => []
                        ];
                    }
                }
            }
            else if (($menu['page'] == 'ca-addons') && !$menu['children']) {
                $addons = Modules::Load('Addons', 'All', true, true);

                if ($addons) {
                    $addon_menus = [];

                    foreach ($addons as $k => $v) {
                        if (!isset($v['config']['show_on_clientArea']) || !$v['config']['show_on_clientArea']) {
                            continue;
                        }

                        $addon_menus[] = [
                            'id'       => $k,
                            'parent'   => 0,
                            'icon'     => $menu['icon'],
                            'rank'     => 0,
                            'target'   => 0,
                            'status'   => 'active',
                            'page'     => 'addon',
                            'onlyCa'   => 1,
                            'link'     => Utility::link_determiner('addon/' . $k . '/client'),
                            'title'    => $v['lang']['meta']['name'],
                            'children' => []
                        ];
                    }

                    if ($addon_menus) {
                        $output .= self::getClientAreaMenu($addon_menus, false, $opt);
                    }
                }

                continue;
            }

            $active = false;
            if ((($pname == 'account_dashboard') && $menu['page'] == 'ca-dashboard') || ($pname == 'account_tickets') && $menu['page'] == 'ca-tickets' || ($pname == 'account_products') && $gtype == 'domain' && $menu['page'] == 'ca-domains' || ($pname == 'account_products') && $gtype != 'domain' && $menu['page'] == 'ca-orders' || ($pname == 'account_sms') && $menu['page'] == 'ca-intl-sms' || ($pname == 'account_invoices') && $menu['page'] == 'ca-invoices' || ($pname == 'account_info') && $menu['page'] == 'ca-ac-information' || ($pname == 'account_messages') && $menu['page'] == 'ca-messages' || ($menu['page'] == 'ca-order-group') && $category && ('special-' . $category['id']) == $menu['id'] || ($menu['page'] == 'ca-order-group') && $gtype == $menu['id'] || ($menu['page'] == 'addon') && $pname == $menu['id'] || ($menu['page'] == 'ca-affiliate') && $pname == 'affiliate' || ($menu['page'] == 'ca-reseller') && $pname == 'reseller') {
                $active = true;
            }

            if ($menu['children']) {
                $menu['link'] = 'javascript:void 0;';
            }

            $output .= '<li  class="list-group-item ' . ($children ? 'py-0 px-3' : 'p-0');

            if (stristr($menu['icon'], 'shopping-cart')) {
                $output .= ' neworderbtn';
            }

            $output .= '">';
            $output .= '<a href="' . $menu['link'] . '"';

            if ($menu['target']) {
                $output .= ' target="_blank"';
            }

            $output .= ' class="toggle d-flex align-items-center justify-content-between py-2"';

            if ($active) {
                $output .= ' data-id="active"';
            }

            $output .= '>';
            $output .= '<span>';
            $output .= ($menu['icon'] ? '<i class="' . $menu['icon'] . ' rounded bg-theme-light p-2 fa-fw" aria-hidden="true" style="width: 30px;height:30px"></i> ' : '');
            $output .= (!$menu['icon'] && $children ? '<i class="fa fa-angle-right fa-fw" aria-hidden="true"></i> ' : '');
            $output .= $menu['title'];
            $output .= '</span>';

            if ($menu['children']) {
                $output .= '<i class="fa-solid fa-angle-down"></i>';
            }

            $output .= '</a>';

            if ($menu['children']) {
                $_opt = $opt;
                $_opt['active'] = $active;
                $output .= self::getClientAreaMenu($menu['children'], true, $_opt);
            }

            $output .= '</li>' . PHP_EOL;
        }

        $output .= ($children ? '</ul>' . PHP_EOL : '');
        return $output;
    }

    public static function getThemeCustomStyles(): string
    {
        $configFonts = Config::get('theme/fonts');
        $themeFonts = [];
        $themeColors = self::getThemeColors();
        $fontSelectors = ['body', 'menu', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'custom'];
        $output = '';
        $baseFontSize = $configFonts['body']['size'] ?? 16;

        if ($configFonts) {
            if ($configFonts['source'] == 'google') {
                $fontHost = $configFonts['host'] ?? 'cloud';

                foreach ($configFonts as $fontKey => $themeFont) {
                    if (in_array($fontKey, $fontSelectors)) {
                        if (($fontKey == 'custom') && !$themeFont['selectors']) {
                            continue;
                        }

                        $themeFonts[] = $themeFont['family'] . ':' . $themeFont['variants'];
                    }
                }

                if ($themeFonts) {
                    $themeFonts = array_unique($themeFonts);
                    $cssFilePath = self::downloadGoogleFont($themeFonts, $fontHost);

                    if ($cssFilePath) {
                        if ($fontHost == 'cloud') {
                            $output .= '<link rel="preconnect" href="https://fonts.googleapis.com">';
                            $output .= '<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>';
                            $output .= '<link rel="dns-prefetch" href="https://fonts.gstatic.com">';
                        }

                        $output .= '<link href="' . $cssFilePath . '" rel="stylesheet" media="print" onload="this.media=\'all\'">' . PHP_EOL;
                        $output .= '<noscript><link href="' . $cssFilePath . '" rel="stylesheet"></noscript>' . PHP_EOL;
                    }
                }
            }
            else if ($configFonts['local']) {
                $cssFiles = explode(',', $configFonts['local']);

                foreach ($cssFiles as $cssFile) {
                    $output .= '<link href="' . trim($cssFile) . '" rel="stylesheet" media="print" onload="this.media=\'all\'">' . PHP_EOL;
                    $output .= '<noscript><link href="' . trim($cssFile) . '" rel="stylesheet"></noscript>' . PHP_EOL;
                }
            }
        }

        $output .= '<style>';
        $output .= 'html {';
        $output .= 'font-size:' . $configFonts['body']['size'] . 'px;';
        $output .= '}';
        $output .= ':root {';
        $output .= '--theme-primary: #' . $themeColors['theme-primary']['color'] . ';';
        $output .= '--theme-primary-rgb : ' . $themeColors['theme-primary']['rgb'] . ';';
        $output .= '--theme-primary-hsl : ' . $themeColors['theme-primary']['hsl'] . ';';
        $output .= '--theme-secondary: #' . $themeColors['theme-secondary']['color'] . ';';
        $output .= '--theme-secondary-rgb : ' . $themeColors['theme-secondary']['rgb'] . ';';
        $output .= '--theme-secondary-hsl : ' . $themeColors['theme-secondary']['hsl'] . ';';
        $output .= '--text-color: #' . $themeColors['text-color']['color'] . ';';
        $output .= '--text-color-rgb: ' . $themeColors['text-color']['rgb'] . ';';
        $output .= '--text-color-hsl: ' . $themeColors['text-color']['hsl'] . ';';
        $output .= '--link-color: #' . $themeColors['link-color']['color'] . ';';
        $output .= '--link-color-rgb: ' . $themeColors['link-color']['rgb'] . ';';
        $output .= '--link-color-hsl: ' . $themeColors['link-color']['hsl'] . ';';
        $output .= '--link-color-hover: #' . $themeColors['link-color-hover']['color'] . ';';
        $output .= '--link-color-hover-rgb: ' . $themeColors['link-color-hover']['rgb'] . ';';
        $output .= '--link-color-hover-hsl: ' . $themeColors['link-color-hover']['hsl'] . ';';
        $output .= '--link-color-active: #' . $themeColors['link-color-active']['color'] . ';';
        $output .= '--link-color-active-rgb: ' . $themeColors['link-color-active']['rgb'] . ';';
        $output .= '--link-color-active-hsl: ' . $themeColors['link-color-active']['hsl'] . ';';

        if ($configFonts['source'] == 'google') {
            $output .= '--body-font-family:"' . $configFonts['body']['family'] . '", ' . $configFonts['body']['category'] . ';';
            $output .= '--body-font-weight:' . $configFonts['body']['weight'] . ';';
            $output .= '--menu-font-family:"' . $configFonts['menu']['family'] . '", ' . $configFonts['menu']['category'] . ';';
            $output .= '--menu-font-weight:' . $configFonts['menu']['weight'] . ';';
            $output .= '--h1-font-family:"' . $configFonts['h1']['family'] . '", ' . $configFonts['h1']['category'] . ';';
            $output .= '--h1-font-weight:' . $configFonts['h1']['weight'] . ';';
            $output .= '--h2-font-family:"' . $configFonts['h2']['family'] . '", ' . $configFonts['h2']['category'] . ';';
            $output .= '--h2-font-weight:' . $configFonts['h2']['weight'] . ';';
            $output .= '--h3-font-family:"' . $configFonts['h3']['family'] . '", ' . $configFonts['h3']['category'] . ';';
            $output .= '--h3-font-weight:' . $configFonts['h3']['weight'] . ';';
            $output .= '--h4-font-family:"' . $configFonts['h4']['family'] . '", ' . $configFonts['h4']['category'] . ';';
            $output .= '--h4-font-weight:' . $configFonts['h4']['weight'] . ';';
            $output .= '--h5-font-family:"' . $configFonts['h5']['family'] . '", ' . $configFonts['h5']['category'] . ';';
            $output .= '--h5-font-weight:' . $configFonts['h5']['weight'] . ';';
            $output .= '--h6-font-family:"' . $configFonts['h6']['family'] . '", ' . $configFonts['h6']['category'] . ';';
            $output .= '--h6-font-weight:' . $configFonts['h6']['weight'] . ';';
        }

        $output .= '--body-font-size:' . round($configFonts['body']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--menu-font-size:' . round($configFonts['menu']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h1-font-size:' . round($configFonts['h1']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h2-font-size:' . round($configFonts['h2']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h3-font-size:' . round($configFonts['h3']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h4-font-size:' . round($configFonts['h4']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h5-font-size:' . round($configFonts['h5']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '--h6-font-size:' . round($configFonts['h6']['size'] / $baseFontSize, 2) . 'rem;';
        $output .= '}';
        if (($configFonts['source'] == 'google') && isset($configFonts['custom']['selector']) && $configFonts['custom']['selector']) {
            $output .= $configFonts['custom']['selector'] . '{';

            if ($configFonts['custom']['family']) {
                $output .= 'font-family:"' . $configFonts['custom']['family'] . '", ' . $configFonts['custom']['category'] . ';';
                $output .= 'font-size:' . round($configFonts['custom']['size'] / $baseFontSize, 2) . 'rem;';
                $output .= 'font-weight:' . $configFonts['custom']['weight'] . ';';
            }

            $output .= '}';
        }

        $output .= '</style>';
        return $output;
    }

    private static function downloadGoogleFont(array $fonts, string $host = 'cloud'): string
    {
        $outputDir = View::$init->get_template_dir() . 'fonts/google-fonts';
        $outputLink = View::$init->get_template_url() . Config::get('theme/name') . '/fonts/google-fonts';

        if ($host != 'cloud') {
            if (!is_dir($outputDir)) {
                mkdir($outputDir, 511, true);
            }
        }

        $fontName = [];
        $fontUrl = [];

        foreach ($fonts as $font) {
            list($name, $variants) = explode(':', $font);
            $fontName[] = strtolower(str_replace(' ', '_', $name));
            $variants = str_replace(',', ';', $variants);
            $fontUrl[] = 'family=' . urlencode($name) . ':wght@' . $variants;
        }

        $sanitizedFontFamily = implode('_', $fontName);
        $fontUrl = implode('&', $fontUrl);
        $cssFilePath = $outputDir . '/' . $sanitizedFontFamily . '.css';
        $cssFileLink = $outputLink . '/' . $sanitizedFontFamily . '.css';

        if ($host != 'cloud') {
            if (file_exists($cssFilePath)) {
                return $cssFileLink;
            }
        }

        $fontUrl = 'https://fonts.googleapis.com/css2?' . $fontUrl . '&display=swap';

        if ($host == 'cloud') {
            return $fontUrl;
        }

        $cssContent = file_get_contents($fontUrl);

        if (!$cssContent) {
            Modules::save_log('Addons', 'FonPageBuilder', 'themeDownloadGoogleFont', $fontUrl, $cssContent, '');
            return '';
        }

        preg_match_all('/url\\((https:\\/\\/fonts\\.gstatic\\.com\\/s\\/[^)]+)\\)/', $cssContent, $matches);

        foreach ($matches[1] as $fontFileUrl) {
            $filePath = $outputDir . '/' . basename($fontFileUrl);

            if (!file_exists($filePath)) {
                file_put_contents($filePath, file_get_contents($fontFileUrl));
            }

            $cssContent = str_replace($fontFileUrl, basename($fontFileUrl), $cssContent);
        }

        file_put_contents($cssFilePath, $cssContent);
        return $cssFileLink;
    }

    private static function getThemeColors(): array
    {
        $themePrimary = Config::get('theme/color1');
        $themeSecondary = Config::get('theme/color2');
        $themeTextColor = Config::get('theme/text-color');
        $themeLinkColor = Config::get('theme/link_color');
        $themeLinkColorHover = Config::get('theme/link_color_hover');
        $themeLinkColorActive = Config::get('theme/link_color_active');
        $themeColors = [
            'theme-primary'     => ['color' => $themePrimary, 'rgb' => self::hexToRgb($themePrimary), 'hsl' => self::hexToHsl($themePrimary)],
            'theme-secondary'   => ['color' => $themeSecondary, 'rgb' => self::hexToRgb($themeSecondary), 'hsl' => self::hexToHsl($themeSecondary)],
            'text-color'        => ['color' => $themeTextColor, 'rgb' => self::hexToRgb($themeTextColor), 'hsl' => self::hexToHsl($themeTextColor)],
            'link-color'        => ['color' => $themeLinkColor, 'rgb' => self::hexToRgb($themeLinkColor), 'hsl' => self::hexToHsl($themeLinkColor)],
            'link-color-hover'  => ['color' => $themeLinkColorHover, 'rgb' => self::hexToRgb($themeLinkColorHover), 'hsl' => self::hexToHsl($themeLinkColorHover)],
            'link-color-active' => ['color' => $themeLinkColorActive, 'rgb' => self::hexToRgb($themeLinkColorActive), 'hsl' => self::hexToHsl($themeLinkColorActive)]
        ];
        return $themeColors;
    }

    public static function getRandomColors(): string
    {
        $colors = ['#FF5733', '#33FF57', '#3357FF', '#FF33A6', '#33FFF6', '#5733FF', '#FF8C33', '#33FF8C', '#FF3333', '#33A1FF', '#FF9933', '#33FF99', '#FF33FF', '#FF6633', '#CC33FF', '#FF33CC', '#FFB533', '#640D5F', '#D91656', '#EE66A6', '#FF6600', '#4379F2', '#117554', '#624E88', '#C96868', '#16423C', '#161D6F', '#C7253E', '#7A1CAC', '#4E31AA', '#921A40', '#FF8225', '#36C2CE', '#F4CE14', '#1679AB', '#C80036', '#AF47D2', '#C738BD', '#D8AE7E', 'var(--theme-primary)', 'var(--theme-secondary)', 'var(--text-color)', 'var(--link-color)', 'var(--link-color-hover)', 'var(--link-color-active)'];
        return $colors[array_rand($colors)];
    }

    public function addHeroStyle(array $pageData, array $hero, string $section_id): void
    {
        if ($hero && $section_id != '') {
            $heroStyle = '';
            $heroStyle .= $section_id . '{';
            if (isset($hero['background']) && $hero['background']) {
                if ($hero['background']['type'] == 'image') {
                    $heroStyle .= ($hero['background']['image'] ? 'background-image:url(' . self::assetLinkDetermine($hero['background']['image']) . ')!important;' : '');
                    $heroStyle .= ($hero['background']['position'] ? 'background-position:' . $hero['background']['position'] . '!important;' : '');
                    $heroStyle .= ($hero['background']['size'] ? 'background-size:' . $hero['background']['size'] . '!important;' : '');
                    $heroStyle .= ($hero['background']['repeat'] ? 'background-repeat:' . $hero['background']['repeat'] . '!important;' : '');
                    $heroStyle .= ($hero['background']['attachment'] ? 'background-attachment:' . $hero['background']['attachment'] . '!important;' : '');
                    $heroStyle .= ($hero['background']['color'] ? 'background-color:' . $hero['background']['color'] . '!important;' : '');
                }
                else if ($hero['background']['type'] == 'gradient') {
                    $heroStyle .= ($hero['background']['gradient']['final'] ? 'background-image:' . $hero['background']['gradient']['final'] . '!important;' : '');
                }
                else if ($hero['background']['type'] == 'color') {
                    $heroStyle .= ($hero['background']['color'] ? 'background-color:' . $hero['background']['color'] . '!important;' : '');
                }
            }

            $heroStyle .= ($hero['padding'] ? 'padding:' . $hero['padding'] . ';' : '');
            $heroStyle .= '}';
            $heroStyle .= $section_id . ' .fon-hero-content{';
            $heroStyle .= ($hero['text_color'] ? 'color:' . $hero['text_color'] . ';' : '');
            $heroStyle .= '}';
            if (isset($hero['heading_color']) && $hero['heading_color'] != '') {
                $heroStyle .= $section_id . ' .fon-hero-content h1 ,' . $section_id . ' .fon-hero-content h2,' . $section_id . ' .fon-hero-content h3,' . $section_id . ' h4,' . $section_id . ' .fon-hero-content h5,' . $section_id . ' .fon-hero-content h6{color:' . $hero['heading_color'] . '!important;}';
            }
            if (isset($hero['link_color']) && $hero['link_color'] != '') {
                $heroStyle .= $section_id . '.fon-hero-content a:not(.btn){color:' . $hero['link_color'] . '!important;}';
            }
            if (isset($hero['link_hover_color']) && $hero['link_hover_color'] != '') {
                $heroStyle .= $section_id . ' .fon-hero-content a:not(.btn):hover{color:' . $hero['link_hover_color'] . '!important;}';
            }
            if (isset($hero['overlay']) && $hero['overlay']) {
                if (($hero['overlay']['type'] == 'solid') && $hero['overlay']['color']) {
                    $heroStyle .= $section_id . ' .fon-background-overlay{background-color:' . $hero['overlay']['color'] . ';}';
                }
                else if (($hero['overlay']['type'] == 'gradient') && $hero['overlay']['gradient']['final']) {
                    $heroStyle .= $section_id . ' .fon-background-overlay{background-image:' . $hero['overlay']['gradient']['final'] . ';}';
                }
            }
        }

        if ($heroStyle) {
            $this->addStyle($pageData['page'], $heroStyle);
        }
    }

    public static function generateColumnDisplayClassess(object $col): string
    {
        $columnStyle = '';
        $hiddenClass = [];
        if (isset($col->xl_col_display) && $col->xl_col_display) {
            $hiddenClass[] = $col->xl_col_display;
        }
        if (isset($col->lg_col_display) && $col->lg_col_display) {
            $hiddenClass[] = $col->lg_col_display;
        }
        if (isset($col->md_col_display) && $col->md_col_display) {
            $hiddenClass[] = $col->md_col_display;
        }
        if (isset($col->sm_col_display) && $col->sm_col_display) {
            $hiddenClass[] = $col->sm_col_display;
        }
        if (isset($col->xs_col_display) && $col->xs_col_display) {
            $hiddenClass[] = $col->xs_col_display;
        }

        $orderClass = [];
        if (isset($col->xl_col_order) && $col->xl_col_order != '') {
            $orderClass[] = 'order-xl-' . $col->xl_col_order;
        }
        if (isset($col->lg_col_order) && $col->lg_col_order != '') {
            $orderClass[] = 'order-lg-' . $col->lg_col_order;
        }
        if (isset($col->md_col_order) && $col->md_col_order != '') {
            $orderClass[] = 'order-md-' . $col->md_col_order;
        }
        if (isset($col->sm_col_order) && $col->sm_col_order != '') {
            $orderClass[] = 'order-sm-' . $col->sm_col_order;
        }
        if (isset($col->xs_col_order) && $col->xs_col_order != '') {
            $orderClass[] = 'order-' . $col->xs_col_order;
        }

        $columnStyle = implode(' ', array_merge($hiddenClass, $orderClass));
        return $columnStyle;
    }

    public function getPreloader(string $logo, string $favicon, string $url): string
    {
        $sitePreloader = Config::get('theme/site_preloader');
        $sitePreloaderBg = Config::get('theme/site_preloader_bg');

        if ($sitePreloader == 'site-logo') {
            $preloader_image = $logo;
        }
        else if ($sitePreloader == 'site-favicon') {
            $preloader_image = $favicon;
        }
        else {
            $preloader_image = $url . 'images/svg-loaders/' . $sitePreloader . '.svg';
        }

        $preloader = '<div id="site-preloader" class="loader ' . $sitePreloader . '" style="--fon-preloader-bg:#' . $sitePreloaderBg . '"><div class="align-items-center d-flex flex-column justify-content-center"><img src="' . $preloader_image . '" alt="Preloader" class="' . ($sitePreloader === 'site-logo' ? 'animated pulse infinite' : '') . '"/><p class="mt-3">' . $this->language['preloader_text'] . '</p></div></div>';
        return $preloader;
    }

    public static function isRecaptcha(object $captcha): bool
    {
        if (isset($captcha->module->config) && $captcha->module->config && isset($captcha->module->config['site-key']) && $captcha->module->config['site-key']) {
            return true;
        }

        return false;
    }

    private static function getTldList(string $names = ''): array
    {
        $query = Models::$init->db->select()->from('tldlist AS t');

        if ($names) {
            $query->where('t.name', 'IN (\'' . $names . '\')', '', '&&');
        }

        $query->where('t.status', '=', 'active');
        $query->order_by('t.rank ASC');
        $tlds = ($query->build() ? $query->fetch_assoc() : []);

        if ($tlds) {
            foreach ($tlds as $key => $tld) {
                $tlds[$key]['reg_price'] = self::getTldPrices($tld['id'], 'register');
                $tlds[$key]['ren_price'] = self::getTldPrices($tld['id'], 'renewal');
                $tlds[$key]['tra_price'] = self::getTldPrices($tld['id'], 'transfer');
            }
        }

        return $tlds;
    }

    public static function isMobile(): bool
    {
        $useragent = $_SERVER['HTTP_USER_AGENT'];
        $isMobile = preg_match('/(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i', $useragent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-/i', substr($useragent, 0, 4));
        return $isMobile;
    }

    public static function getPriceHolders(string $text): string
    {
        $pattern = '/\\{\\{(domain|hosting|server|software|sms|special):([\\w.]+)(?::(register|transfer|renewal))?\\}\\}/';
        $codePrice = preg_replace_callback($pattern, function($matches) {
            $urunGrubu = $matches[1];
            $urunId = $matches[2];
            $priceType = $matches[3] ?? NULL;

            if ($urunGrubu === 'domain') {
                $domain_override_uscurrency = Config::get('options/domain-override-user-currency');
                $query = Models::$init->db->select('p.*, t.name, t.promo_status, t.promo_register_price, t.promo_transfer_price, t.promo_duedate')->from('prices AS p');
                $query->join('LEFT', 'tldlist AS t', 't.id=p.owner_id');
                $query->where('p.type', '=', $priceType, '&&');
                $query->where('p.owner', '=', 'tld', '&&');
                $query->where('t.name', '=', $urunId);
                $query->order_by('p.rank ASC');
                $price = ($query->build() ? $query->getAssoc() : false);

                if ($price) {
                    if ($priceType != 'renewal') {
                        if ($price['promo_status'] && (substr($price['promo_duedate'], 0, 4) == '1881') || DateManager::strtotime() < DateManager::strtotime($price['promo_duedate'] . ' 23:59:59') && 0 < $price['promo_' . $priceType . '_price']) {
                            $price['amount'] = $price['promo_' . $priceType . '_price'];
                        }
                    }

                    $rawPrice = self::calculatePrices([$price], self::getCurrencySymbols(), $domain_override_uscurrency, $urunGrubu);
                    $price = $rawPrice['price'];
                }
            }
            else if ($urunGrubu === 'software') {
                $query = Models::$init->db->select('p.*, s.override_usrcurrency')->from('prices AS p');
                $query->join('LEFT', 'pages AS s', 's.id=p.owner_id');
                $query->where('p.owner', '=', 'softwares', '&&');
                $query->where('p.owner_id', '=', $urunId);
                $query->order_by('p.rank ASC');
                $query->limit('1');
                $price = ($query->build() ? $query->getAssoc() : false);

                if ($price) {
                    $rawPrice = self::calculatePrices([$price], self::getCurrencySymbols(), $price['override_usrcurrency'], $urunGrubu);
                    $price = $rawPrice['price'];
                }
            }
            else {
                $query = Models::$init->db->select('p.*, pr.override_usrcurrency')->from('prices AS p');
                $query->join('LEFT', 'products AS pr', 'pr.id=p.owner_id');
                $query->where('pr.type', '=', $urunGrubu, '&&');
                $query->where('p.owner', '=', 'products', '&&');
                $query->where('p.owner_id', '=', $urunId);
                $query->order_by('p.rank ASC');
                $query->limit('1');
                $price = ($query->build() ? $query->getAssoc() : false);

                if ($price) {
                    $rawPrice = self::calculatePrices([$price], self::getCurrencySymbols(), $price['override_usrcurrency'], $urunGrubu);
                    $price = $rawPrice['price'];
                }
            }

            if ($price === false) {
                return $matches[0];
            }

            return strip_tags($price);
        }, $text);
        return $codePrice;
    }

    private function checkAndUpdateVersion(): void
    {
        $themeConfig = $this->config;
        $versionFile = TEMPLATE_DIR . 'website' . DS . $themeConfig['meta']['name'] . DS . 'VERSION';
        $updateFile = TEMPLATE_DIR . 'website' . DS . $themeConfig['meta']['name'] . DS . 'UPDATE';

        if (!file_exists($versionFile)) {
            return;
        }

        $versionFileContent = trim(file_get_contents($versionFile));

        if (!$versionFileContent) {
            return;
        }

        $currentVersion = $themeConfig['meta']['version'] ?? NULL;

        if (version_compare($versionFileContent, $currentVersion, '>')) {
            $themeConfig['meta']['version'] = $versionFileContent;

            if (file_exists($updateFile)) {
                FileManager::file_delete($updateFile);
            }

            $this->ensureKeyExists($themeConfig, [
                ['key' => 'wisecpverion', 'value' => '3.1.9.7', 'parent' => 'meta', 'overwrite' => true],
                ['key' => 'enable_lazy_loading', 'value' => true, 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'google_analytics_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'google_ads_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'google_conversion_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'facebook_pixel_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'google_tm_id', 'value' => '', 'parent' => 'settings', 'overwrite' => false],
                ['key' => 'fb_pixel_via_gtm', 'value' => false, 'parent' => 'settings', 'overwrite' => false]
            ]);
            $this->migratePreviewImagesToCDN($themeConfig);
            $configDir = TEMPLATE_DIR . 'website' . DS . $themeConfig['meta']['name'] . DS;
            $export = Utility::array_export($themeConfig, ['pwith' => true]);
            FileManager::file_write($configDir . 'theme-config.php', $export);
            $this->_clearFonBuilderCache();
        }
    }

    private function ensureKeyExists(array &$config, array $options = []): void
    {
        if (!empty($options)) {
            foreach ($options as $option) {
                $key = $option['key'] ?? '';
                $value = $option['value'] ?? NULL;
                $parent = $option['parent'] ?? '';
                $forceUpdate = isset($option['overwrite']) && $option['overwrite'] === true;

                if ($key === '') {
                    continue;
                }

                if ($parent !== '') {
                    if (!isset($config[$parent]) || !is_array($config[$parent])) {
                        $config[$parent] = [];
                    }
                    if (!array_key_exists($key, $config[$parent]) || $forceUpdate) {
                        $config[$parent][$key] = $value;
                    }
                }
                else if (!array_key_exists($key, $config) || $forceUpdate) {
                    $config[$key] = $value;
                }
            }
        }
    }

    private function migratePreviewImagesToCDN(array &$config): bool
    {
        $search = 'https://fonwise.com/documentation/images/';
        $replace = 'https://cdn.jsdelivr.net/gh/Fononline/documentation-assets/';
        $targetKeys = ['package_styles', 'accordion_styles', 'animated_number_styles', 'articles_styles', 'banner_styles', 'campaign_styles', 'contentbox_styles', 'domain_tlds_styles', 'featurebox_styles', 'news_styles', 'references_styles', 'software_styles', 'tabs_styles', 'team_styles', 'testimonial_styles', 'timeline_styles'];
        $hasChanges = false;

        foreach ($targetKeys as $section) {
            if (isset($config[$section]) && is_array($config[$section])) {
                foreach ($config[$section] as $key => $value) {
                    if (is_string($value) && strpos($value, $search) !== false) {
                        $config[$section][$key] = str_replace($search, $replace, $value);
                        $hasChanges = true;
                    }
                }
            }
        }

        return $hasChanges;
    }

    public static function getLazyPlaceholder(): string
    {
        $lazyPlaceholder = static::assetLinkDetermine('templates/website/Datawise/builder/image/lazy-placeholder.svg');
        return $lazyPlaceholder;
    }

    public static function getDueDateWarning(string $dueDate, array $language, string $status): string
    {
        if (!$dueDate || $dueDate == '1970') {
            return '';
        }

        $dueDateObj = new DateTime($dueDate);
        $today = new DateTime();
        $interval = $today->diff($dueDateObj);
        $daysLeft = (int) $interval->format('%r%a');
        if (($daysLeft <= 60) && $status == 'active') {
            return ' <i class="fa-solid fa-bell fa-shake text-danger" title="' . $language['duedate_warning'] . '"></i>';
        }

        return '';
    }

    public static function getBCPLocale(string $lang): string
    {
        $localeMap = ['af' => 'af-ZA', 'am' => 'am-ET', 'ar' => 'ar-SA', 'ay' => 'ay-BO', 'az' => 'az-AZ', 'be' => 'be-BY', 'bg' => 'bg-BG', 'bi' => 'bi-VU', 'bn' => 'bn-IN', 'bs' => 'bs-BA', 'ca' => 'ca-ES', 'ch' => 'ch-PW', 'cs' => 'cs-CZ', 'da' => 'da-DK', 'de' => 'de-DE', 'dv' => 'dv-MV', 'dz' => 'dz-BT', 'el' => 'el-GR', 'en' => 'en-US', 'es' => 'es-ES', 'et' => 'et-EE', 'fa' => 'fa-IR', 'fi' => 'fi-FI', 'fj' => 'fj-FJ', 'fo' => 'fo-FO', 'fr' => 'fr-FR', 'ga' => 'ga-IE', 'gn' => 'gn-PY', 'gv' => 'gv-GB', 'he' => 'he-IL', 'hi' => 'hi-IN', 'ho' => 'ho-PG', 'hr' => 'hr-HR', 'ht' => 'ht-HT', 'hu' => 'hu-HU', 'hy' => 'hy-AM', 'hz' => 'hz-NA', 'id' => 'id-ID', 'is' => 'is-IS', 'it' => 'it-IT', 'ja' => 'ja-JP', 'ka' => 'ka-GE', 'kg' => 'kg-CD', 'kk' => 'kk-KZ', 'kl' => 'kl-GL', 'km' => 'km-KH', 'ko' => 'ko-KR', 'ky' => 'ky-KG', 'la' => 'la-VAT', 'ln' => 'ln-CD', 'lo' => 'lo-LA', 'lt' => 'lt-LT', 'lu' => 'lu-CD', 'lv' => 'lv-LV', 'mg' => 'mg-MG', 'mh' => 'mh-MH', 'mi' => 'mi-NZ', 'mk' => 'mk-MK', 'mn' => 'mn-MN', 'ms' => 'ms-MY', 'mt' => 'mt-MT', 'my' => 'my-MM', 'na' => 'na-NR', 'nb' => 'nb-NO', 'nd' => 'nd-ZW', 'ne' => 'ne-NP', 'ng' => 'ng-NA', 'nl' => 'nl-NL', 'nn' => 'nn-NO', 'no' => 'no-NO', 'nr' => 'nr-ZA', 'ny' => 'ny-MW', 'pl' => 'pl-PL', 'ps' => 'ps-AF', 'pt' => 'pt-PT', 'qu' => 'qu-PE', 'rm' => 'rm-CH', 'rn' => 'rn-BI', 'ro' => 'ro-RO', 'ru' => 'ru-RU', 'rw' => 'rw-RW', 'sg' => 'sg-CF', 'si' => 'si-LK', 'sk' => 'sk-SK', 'sl' => 'sl-SI', 'sm' => 'sm-AS', 'sn' => 'sn-ZW', 'so' => 'so-SO', 'sq' => 'sq-AL', 'sr' => 'sr-RS', 'ss' => 'ss-ZA', 'st' => 'st-ZA', 'sv' => 'sv-SE', 'sw' => 'sw-KE', 'ta' => 'ta-IN', 'tg' => 'tg-TJ', 'th' => 'th-TH', 'ti' => 'ti-ER', 'tk' => 'tk-TM', 'tn' => 'tn-ZA', 'to' => 'to-TO', 'tr' => 'tr-TR', 'ts' => 'ts-ZA', 'uk' => 'uk-UA', 'ur' => 'ur-PK', 'uz' => 'uz-UZ', 've' => 've-ZA', 'vi' => 'vi-VN', 'xh' => 'xh-ZA', 'zh' => 'zh-CN', 'zu' => 'zu-ZA'];
        $lang = strtolower($lang);
        return $localeMap[$lang] ?? 'en-US';
    }

    public static function getStarRating(int $score, string $color = 'var(--theme-primary)', int $starSize = 20): string
    {
        $maxStars = 5;
        $fullStar = '<span class="d-inline-flex align-items-center justify-content-center rounded text-white" style="width: ' . ($starSize + 8) . 'px;height: ' . ($starSize + 8) . 'px;background-color:' . $color . '"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>';
        $halfStar = '<span class="d-inline-flex align-items-center justify-content-center rounded text-white" style="width: ' . ($starSize + 8) . 'px;height: ' . ($starSize + 8) . 'px;background-color:' . $color . '"><i class="fa-solid fa-star-half" style="font-size:' . $starSize . 'px" ></i></span>';
        $emptyStar = '<span class="d-inline-flex align-items-center justify-content-center rounded bg-theme-light-200 text-white" style="width: ' . ($starSize + 8) . 'px;height: ' . ($starSize + 8) . 'px;"><i class="fa-solid fa-star" style="font-size:' . $starSize . 'px"></i></span>';
        $starsHtml = '';
        $fullStars = floor($score);
        $decimalPart = $score - $fullStars;

        if (0.75 <= $decimalPart) {
            ++$fullStars;
            $halfStars = 0;
        }
        else if (0.25 <= $decimalPart) {
            $halfStars = 1;
        }
        else {
            $halfStars = 0;
        }

        $emptyStars = $maxStars - $fullStars - $halfStars;
        $starsHtml .= str_repeat($fullStar, $fullStars);
        $starsHtml .= str_repeat($halfStar, $halfStars);
        $starsHtml .= str_repeat($emptyStar, $emptyStars);
        return $starsHtml;
    }

    public static function parseCanonicalUrl(string $url, string $current_lang = '', bool $alternate = false): string
    {
        if (!$current_lang) {
            $current_lang = Language::selected();
        }

        $default_lang = Config::get('general/local');
        $page_param = '';

        if (strpos($url, '?') !== false) {
            $url_parts = explode('?', $url, 2);
            $url = $url_parts[0];
            $parsed_query = [];
            parse_str($url_parts[1], $parsed_query);
            if (isset($parsed_query['page']) && is_numeric($parsed_query['page'])) {
                $page_param = '?page=' . (int) $parsed_query['page'];
            }
        }

        $slug_suffix = '';

        if (preg_match('#/sayfa/([0-9]+)$#i', $url, $page_matches)) {
            $slug_suffix = '/sayfa/' . $page_matches[1];
            $url = preg_replace('#/sayfa/[0-9]+$#i', '', $url);
        }

        $parsed = parse_url($url);
        $protocol = (isset($parsed['scheme']) ? $parsed['scheme'] : (Utility::isSSL() ? 'https' : 'http'));
        $host = (isset($parsed['host']) ? $parsed['host'] : $_SERVER['HTTP_HOST']);

        if (View::$init->template_file == 'index.php') {
            $homeRoute = ___('website-routes/website-routes/home', false, $current_lang);
            $firstHomeRoute = trim($homeRoute[0], ' ' . "\t\n\r" . "\0" . '/');

            if ($firstHomeRoute !== '') {
                $url = str_replace($homeRoute[0], '', $url);
            }
            else {
                $url = str_replace($homeRoute[1], '', $url);
            }
        }

        if ($current_lang == $default_lang) {
            $url = preg_replace('#^' . preg_quote($protocol . '://' . $host, '#') . '/' . $default_lang . '(?=/|$)#', $protocol . '://' . $host, $url);
        }

        $categoryRoute = ___('website-routes/website-routes/products', false, $current_lang);
        $category_slug = preg_replace('/\\/\\(\\?\\).*/', '', $categoryRoute[0]);
        $pattern = '#/' . $category_slug . '/(.*)#';

        if (preg_match($pattern, $url, $matches)) {
            $category_path = $matches[1];
            $slugs = explode('/', trim($category_path, '/'));
            $lang_prefix = ($current_lang != $default_lang ? $current_lang . '/' : '');
            $last_slug = end($slugs);

            if ($last_slug == 'sms') {
                $canonical_path = $category_slug . '/sms';
                $url = $protocol . '://' . $host . '/' . $lang_prefix . $canonical_path;
            }
            else {
                $canonical_path = $category_slug . '/' . trim($last_slug, '/');
                $url = $protocol . '://' . $host . '/' . $lang_prefix . $canonical_path;
            }
        }

        $url = rtrim($url, '/');
        $url = $url . $slug_suffix . $page_param;
        return $url;
    }

    private static function parseShortcodesToHtml(string $content): string
    {
        $content = preg_replace_callback('/\\[iframe\\s+(.*?)\\]/i', function($matches) {
            $attrs = [];
            preg_match_all('/(\\w+)\\s*=\\s*"([^"]*)"/', $matches[1], $attrMatches, PREG_SET_ORDER);

            foreach ($attrMatches as $attr) {
                $attrs[] = $attr[1] . '="' . htmlspecialchars($attr[2], ENT_QUOTES) . '"';
            }

            return '<iframe ' . implode(' ', $attrs) . '></iframe>';
        }, $content);
        $content = preg_replace_callback('/\\[script\\](.*?)\\[\\/script\\]/is', function($matches) {
            return '<script>' . $matches[1] . '</script>';
        }, $content);
        return $content;
    }

    public function googleStructuredData(array $pageData = []): string
    {
        $settings = (isset($this->config['settings']) ? $this->config['settings'] : []);
        $gsdData = ['show' => (isset($settings['seo_gsd_show']) ? $settings['seo_gsd_show'] : false), 'site_name' => (isset($settings['seo_site_name']) ? $settings['seo_site_name'] : []), 'organisation_name' => (isset($settings['seo_organisation_name']) ? $settings['seo_organisation_name'] : []), 'organisation_address' => (isset($settings['seo_organisation_address']) ? $settings['seo_organisation_address'] : ''), 'organisation_city' => (isset($settings['seo_organisation_city']) ? $settings['seo_organisation_city'] : ''), 'organisation_region' => (isset($settings['seo_organisation_region']) ? $settings['seo_organisation_region'] : ''), 'organisation_postal_code' => (isset($settings['seo_organisation_postal_code']) ? $settings['seo_organisation_postal_code'] : ''), 'organisation_country' => (isset($settings['seo_organisation_country']) ? $settings['seo_organisation_country'] : ''), 'organisation_price_min' => (isset($settings['seo_organisation_price_min']) ? $settings['seo_organisation_price_min'] : 0), 'organisation_price_max' => (isset($settings['seo_organisation_price_max']) ? $settings['seo_organisation_price_max'] : 0), 'organisation_price_currency' => (isset($settings['seo_organisation_price_currency']) ? $settings['seo_organisation_price_currency'] : 147), 'organisation_rating_value' => (isset($settings['seo_organisation_rating_value']) ? $settings['seo_organisation_rating_value'] : ''), 'organisation_rating_count' => (isset($settings['seo_organisation_rating_count']) ? $settings['seo_organisation_rating_count'] : '')];
        $template = $pageData['hoptions']['page'] ?? 'index';
        $lang = Language::selected();
        $currencies = Money::getCurrencies();
        $phones = Config::get('contact/phone-numbers');
        $address = Config::get('contact/address');
        $emails = Config::get('contact/email-addresses');
        $socials = Config::get('contact/social-links');
        $maps = Config::get('contact/maps');
        $logo = static::assetLinkDetermine(Config::get('theme/header-logo'));
        $breadcrumb = $pageData['breadcrumb'] ?? [];

        if ($socials) {
            $socials = array_column($socials, 'url');
        }

        $output = [];
        if (!empty($gsdData) && isset($gsdData['show']) && $gsdData['show']) {
            if ($breadcrumb) {
                end($breadcrumb);
                $lastKey = key($breadcrumb);
                $breadcrumb[$lastKey]['link'] = $pageData['hoptions']['gsd_route'] ?? '';
                $breadcrumbItems = [];

                foreach ($breadcrumb as $item) {
                    if (isset($item['title']) && isset($item['link'])) {
                        $breadcrumbItems[] = ['@type' => 'ListItem', 'position' => count($breadcrumbItems) + 1, 'name' => $item['title'], 'item' => ($item['link'] != '' ? $item['link'] : (!preg_match('/^https?:\\/\\//', $_SERVER['REQUEST_URI']) ? Controllers::$init->CRLink(ltrim($_SERVER['REQUEST_URI'], '/'), false, 'none') : $_SERVER['REQUEST_URI']))];
                    }
                }

                $output['breadcrums'] = ['@context' => 'http://schema.org', '@type' => 'BreadcrumbList', 'itemListElement' => $breadcrumbItems];
            }

            $output['website'] = [
                '@context'    => 'http://schema.org',
                '@type'       => 'WebSite',
                '@id'         => $pageData['badress'] ?? Utility::AppAdress(),
                'name'        => $gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang),
                'description' => __('website/index/meta/description', false, $lang),
                'url'         => $pageData['badress'] ?? Utility::AppAdress(),
                'image'       => ['@type' => 'ImageObject', 'url' => $logo],
                'sameAs'      => $socials
            ];
            $output['webpage'] = [
                '@context'    => 'http://schema.org',
                '@type'       => 'WebPage',
                'name'        => (isset($pageData['header_title']) && $pageData['header_title'] ? $pageData['header_title'] : (isset($pageData['meta']['title']) && $pageData['meta']['title'] ? $pageData['meta']['title'] : __('website/index/meta/title', false, $lang))),
                'description' => (isset($pageData['header_description']) && $pageData['header_description'] ? $pageData['header_description'] : (isset($pageData['meta']['description']) && $pageData['meta']['description'] ? $pageData['meta']['description'] : __('website/index/meta/description', false, $lang))),
                'url'         => $_SERVER['REQUEST_URI'],
                'inLanguage'  => $lang,
                'isPartOf'    => ['@id' => $pageData['badress'] ?? Utility::AppAdress()]
            ];

            if ($template == 'index') {
                $output['index'] = [
                    '@context'    => 'http://schema.org',
                    '@type'       => 'Organization',
                    'name'        => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang)),
                    'description' => __('website/index/meta/description', false, $lang),
                    'url'         => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'        => $logo ?? false,
                    'image'       => $logo ?? false,
                    'email'       => $emails[0] ?? false,
                    'sameAs'      => $socials,
                    'telephone'   => str_replace(' ', '', $phones[0] ?? ''),
                    'address'     => ['@type' => 'PostalAddress', 'streetAddress' => $gsdData['organisation_address'] ?? ($address ?? false), 'addressLocality' => $gsdData['organisation_city'] ?? false, 'addressRegion' => $gsdData['organisation_region'] ?? false, 'postalCode' => $gsdData['organisation_postal_code'] ?? false, 'addressCountry' => $gsdData['organisation_country'] ?? false]
                ];
            }
            else if ($template == 'articles') {
                if (isset($pageData['hoptions']['gsd_list']) && is_array($pageData['hoptions']['gsd_list']) && 0 < count($pageData['hoptions']['gsd_list'])) {
                    $blogPosts = [];

                    foreach ($pageData['hoptions']['gsd_list'] as $index => $item) {
                        $mtime = $this->gsd_get_page_mtime($item['id']);
                        $blogPosts[] = [
                            '@type'         => 'BlogPosting',
                            'headline'      => $item['title'],
                            'url'           => $item['route'],
                            'image'         => $item['image'] ?? false,
                            'datePublished' => (isset($item['ctime']) && $item['ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $item['ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c')),
                            'dateModified'  => $mtime ?: (new DateTime())->format('c'),
                            'author'        => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()]
                        ];
                    }
                    $output['blog'] = ['@context' => 'https://schema.org', '@type' => 'Blog', 'name' => (isset($pageData['meta']['title']) && $pageData['meta']['title'] != '' ? $pageData['meta']['title'] : $pageData['header_title']), 'url' => Controllers::$init->CRLink('articles', false, $lang), 'blogPost' => $blogPosts];
                }
            }
            else if (($template == 'softwares') || $template == 'news' || $template == 'knowledgebase' || $template == 'references') {
                if (isset($pageData['hoptions']['gsd_list']) && is_array($pageData['hoptions']['gsd_list']) && 0 < count($pageData['hoptions']['gsd_list'])) {
                    $itemListElements = [];

                    foreach ($pageData['hoptions']['gsd_list'] as $index => $item) {
                        $itemListElements[$index] = ['@type' => 'ListItem', 'url' => $item['route'], 'name' => $item['title'], 'position' => $index + 1];
                    }
                    $output[$template] = ['@context' => 'https://schema.org', '@type' => 'ItemList', 'name' => (isset($pageData['meta']['title']) && $pageData['meta']['title'] != '' ? $pageData['meta']['title'] : $pageData['header_title']), 'itemListElement' => $itemListElements];
                }
            }
            else if (($template == 'hosting-products') || $template == 'server-products' || $template == 'sms-products' || $template == 'special-products') {
                if (isset($pageData['hoptions']['gsd_list']['list']) && $pageData['hoptions']['gsd_list']['list'] && 0 < count($pageData['hoptions']['gsd_list']['list'])) {
                    $old_serialize_precision = ini_get('serialize_precision');
                    ini_set('serialize_precision', -1);
                    $offers = [];

                    foreach ($pageData['hoptions']['gsd_list']['list'] as $item) {
                        $currency = (isset($item['prices'][0]['cid']) ? $currencies[array_search($item['prices'][0]['cid'], array_column($currencies, 'id'))]['code'] : 'TRY');
                        $sale_price = $item['prices'][0]['amount'];
                        $raw_price = 0;

                        if (0 < $item['prices'][0]['discount']) {
                            $raw_price = $item['prices'][0]['amount'] / (1 - ($item['prices'][0]['discount'] / 100));
                        }
                        $offers[$item['id']] = [
                            '@type'         => 'Offer',
                            'name'          => $item['title'],
                            'sku'           => (isset($pageData['hoptions']['gsd_list']['cat']) && $pageData['hoptions']['gsd_list']['cat'] ? $pageData['hoptions']['gsd_list']['cat'] . '-' . $item['id'] : $item['id']),
                            'availability'  => (isset($item['haveStock']) && $item['haveStock'] ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock'),
                            'itemCondition' => 'https://schema.org/NewCondition',
                            'seller'        => ['@type' => 'Organization', 'name' => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang))],
                            'url'           => self::parseCanonicalUrl($item['buy_link'], $lang)
                        ];
                        if ((0 < $raw_price) && $raw_price != $sale_price) {
                            $offers[$item['id']]['priceSpecification'] = [
                                ['@type' => 'UnitPriceSpecification', 'price' => (float) sprintf('%.2f', $sale_price), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false],
                                ['@type' => 'UnitPriceSpecification', 'priceType' => 'https://schema.org/StrikethroughPrice', 'price' => (float) sprintf('%.2f', $raw_price), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false]
                            ];
                        }
                        else {
                            $offers[$item['id']]['priceSpecification'] = ['@type' => 'UnitPriceSpecification', 'price' => (float) sprintf('%.2f', $sale_price), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false];
                        }
                    }
                    $output[$template] = [
                        '@context'    => 'https://schema.org',
                        '@type'       => 'Product',
                        'name'        => $pageData['header_title'],
                        'description' => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['header_description']) && $pageData['header_description'] != '' ? $pageData['header_description'] : false)),
                        'brand'       => ['@type' => 'Brand', 'name' => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang))],
                        'image'       => ['@type' => 'ImageObject', 'url' => (isset($pageData['header_background']) && $pageData['header_background'] ? $pageData['header_background'] : false)],
                        'offers'      => array_values($offers)
                    ];
                    ini_set('serialize_precision', $old_serialize_precision);
                }
                if (isset($pageData['hoptions']['gsd_faq']) && $pageData['hoptions']['gsd_faq'] && 0 < count($pageData['hoptions']['gsd_faq'])) {
                    $faqs = [];

                    foreach ($pageData['hoptions']['gsd_faq'] as $faq) {
                        $faqs[] = [
                            '@type'          => 'Question',
                            'name'           => $faq['title'],
                            'acceptedAnswer' => ['@type' => 'Answer', 'text' => $faq['description']]
                        ];
                    }

                    $output[$template . '_faqs'] = ['@context' => 'https://schema.org', '@type' => 'FAQPage', 'mainEntity' => $faqs];
                }
            }
            else if ($template == 'page-detail-software') {
                $old_serialize_precision = ini_get('serialize_precision');
                ini_set('serialize_precision', -1);
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['software-detail'] = [
                    '@context'            => 'https://schema.org',
                    '@type'               => 'SoftwareApplication',
                    'mainEntityOfPage'    => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'name'                => $pageData['header_title'],
                    'applicationCategory' => 'BusinessApplication',
                    'description'         => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'               => (isset($pageData['hoptions']['gsd_mockup']) && $pageData['hoptions']['gsd_mockup'] ? $pageData['hoptions']['gsd_mockup'] : (isset($pageData['hoptions']['gsd_cover']) && $pageData['hoptions']['gsd_cover'] ? $pageData['hoptions']['gsd_cover'] : $pageData['header_background'] ?? false)),
                    'datePublished'       => $ctime,
                    'dateModified'        => $mtime ?: $ctime,
                    'aggregateRating'     => ['@type' => 'AggregateRating', 'ratingValue' => (float) sprintf('%.1f', 4.7), 'ratingCount' => $pageData['hoptions']['gsd_ratingCount'] ?? 0],
                    'offers'              => ['@type' => 'Offer', 'price' => (float) sprintf('%.2f', $pageData['hoptions']['gsd_price']['amount']), 'priceCurrency' => $currencies[array_search($pageData['hoptions']['gsd_price']['cid'], array_column($currencies, 'id'))]['code']],
                    'operatingSystem'     => 'Web'
                ];
                ini_set('serialize_precision', $old_serialize_precision);
            }
            else if ($template == 'page-detail-articles') {
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['article-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'BlogPosting',
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'isPartOf'         => ['@type' => 'Blog', 'name' => __('website/articles/meta/title') . ' - ' . __('website/index/meta/title'), 'url' => Controllers::$init->CRLink('articles')],
                    'headline'         => $pageData['header_title'],
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => (isset($pageData['hoptions']['gsd_cover']) && $pageData['hoptions']['gsd_cover'] ? $pageData['hoptions']['gsd_cover'] : $pageData['header_background'] ?? false),
                    'datePublished'    => $ctime,
                    'dateModified'     => $mtime ?: $ctime,
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ]
                ];
            }
            else if ($template == 'page-detail-news') {
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['news-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'NewsArticle',
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'headline'         => $pageData['header_title'],
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => (isset($pageData['hoptions']['gsd_cover']) && $pageData['hoptions']['gsd_cover'] ? static::assetLinkDetermine('resources/uploads/news/' . $pageData['hoptions']['gsd_cover']) : $pageData['header_background'] ?? false),
                    'datePublished'    => $ctime,
                    'dateModified'     => $mtime ?: $ctime,
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ]
                ];
            }
            else if ($template == 'page-detail-references') {
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['reference-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'Article',
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'isPartOf'         => ['@type' => 'CollectionPage', 'name' => __('website/references/meta/title') . ' - ' . __('website/index/meta/title'), 'url' => Controllers::$init->CRLink('references')],
                    'headline'         => $pageData['header_title'],
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => (isset($pageData['hoptions']['gsd_mockup']) && $pageData['hoptions']['gsd_mockup'] ? $pageData['hoptions']['gsd_mockup'] : (isset($pageData['hoptions']['gsd_cover']) && $pageData['hoptions']['gsd_cover'] ? static::assetLinkDetermine('resources/uploads/references/' . $pageData['hoptions']['gsd_cover']) : $pageData['header_background'] ?? false)),
                    'datePublished'    => $ctime,
                    'dateModified'     => $mtime ?: $ctime,
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ]
                ];
            }
            else if ($template == 'page-detail-normal') {
                $ctime = (isset($pageData['hoptions']['gsd_ctime']) && $pageData['hoptions']['gsd_ctime'] ? ($dt = DateTime::createFromFormat(Config::get('options/date-format'), $pageData['hoptions']['gsd_ctime']) ? $dt->format('c') : (new DateTime())->format('c')) : (new DateTime())->format('c'));
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0);
                $output['normal-page-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'Article',
                    '@id'              => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link'],
                    'url'              => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link'],
                    'name'             => $pageData['header_title'],
                    'headline'         => $pageData['header_title'],
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => $pageData['header_background'] ?? false,
                    'inLanguage'       => $lang,
                    'datePublished'    => $ctime,
                    'dateModified'     => $mtime ?: $ctime,
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ],
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']]
                ];
            }
            else if ($template == 'knowledgebase-detail') {
                $ctime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0, 'ctime', 'knowledgebase');
                $mtime = $this->gsd_get_page_mtime($pageData['hoptions']['gsd_id'] ?? 0, 'mtime', 'knowledgebase');
                $output['knowledgebase-detail'] = [
                    '@context'         => 'https://schema.org',
                    '@type'            => 'TechArticle',
                    'mainEntityOfPage' => ['@type' => 'WebPage', '@id' => $pageData['hoptions']['gsd_route'] ?? $breadcrumb[count($breadcrumb) - 1]['link']],
                    'isPartOf'         => ['@type' => 'CollectionPage', 'name' => __('website/knowledgebase/meta/title') . ' - ' . __('website/index/meta/title'), 'url' => Controllers::$init->CRLink('knowledgebase')],
                    'headline'         => (isset($pageData['hoptions']['gsd_title']) && $pageData['hoptions']['gsd_title'] != '' ? $pageData['hoptions']['gsd_title'] : (isset($pageData['meta']['title']) && $pageData['meta']['title'] != '' ? $pageData['meta']['title'] : '')),
                    'description'      => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['gsd_description']) && $pageData['hoptions']['gsd_description'] != '' ? $this->_gsd_description_create($pageData['hoptions']['gsd_description']) : '')),
                    'image'            => (isset($pageData['header_background']) && $pageData['header_background'] ? $pageData['header_background'] : false),
                    'datePublished'    => $ctime ?: (new DateTime())->format('c'),
                    'dateModified'     => $mtime ?: (new DateTime())->format('c'),
                    'author'           => ['@type' => 'Organization', 'name' => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'), 'url' => $pageData['badress'] ?? Utility::AppAdress()],
                    'publisher'        => [
                    '@type' => 'Organization',
                    'name'  => $gsdData['site_name'][$lang] ?? __('website/index/meta/title'),
                    'url'   => $pageData['badress'] ?? Utility::AppAdress(),
                    'logo'  => ['@type' => 'ImageObject', 'url' => $logo ?? false]
                ]
                ];
            }
            else if ($template == 'contact') {
                $old_serialize_precision = ini_get('serialize_precision');
                ini_set('serialize_precision', -1);
                $output['contact'] = [
                    '@context'        => 'https://schema.org',
                    '@type'           => ['LocalBusiness'],
                    '@id'             => ($pageData['badress'] ? $pageData['badress'] . '#LocalBusiness' : Utility::AppAdress() . '#LocalBusiness'),
                    'image'           => $logo ?? false,
                    'name'            => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title')),
                    'telephone'       => str_replace(' ', '', $phones[0] ?? ''),
                    'email'           => $emails[0] ?? false,
                    'priceRange'      => str_replace(' ', '', Money::formatter_symbol($gsdData['organisation_price_min'], $gsdData['organisation_price_currency'])) . ' - ' . str_replace(' ', '', Money::formatter_symbol($gsdData['organisation_price_max'], $gsdData['organisation_price_currency'])),
                    'address'         => ['@type' => 'PostalAddress', 'streetAddress' => $gsdData['organisation_address'] ?? ($address ?? false), 'addressLocality' => $gsdData['organisation_city'] ?? false, 'addressRegion' => $gsdData['organisation_region'] ?? false, 'postalCode' => $gsdData['organisation_postal_code'] ?? false, 'addressCountry' => $gsdData['organisation_country'] ?? false],
                    'aggregateRating' => ['@type' => 'AggregateRating', 'ratingValue' => ($gsdData['organisation_rating_value'] ? (float) sprintf('%.1f', $gsdData['organisation_rating_value']) : 5), 'reviewCount' => $gsdData['organisation_rating_count'] ?? 100, 'worstRating' => 1, 'bestRating' => 5],
                    'geo'             => ['@type' => 'GeoCoordinates', 'latitude' => $maps['latitude'] ?? false, 'longitude' => $maps['longitude'] ?? false],
                    'url'             => $pageData['badress'] ?? Utility::AppAdress(),
                    'sameAs'          => $socials
                ];
                ini_set('serialize_precision', $old_serialize_precision);
            }
            else if ($template == 'domain') {
                if (isset($pageData['hoptions']['gsd_list']) && $pageData['hoptions']['gsd_list'] && 0 < count($pageData['hoptions']['gsd_list'])) {
                    $old_serialize_precision = ini_get('serialize_precision');
                    ini_set('serialize_precision', -1);
                    $offers = [];

                    foreach ($pageData['hoptions']['gsd_list'] as $item) {
                        $currency = (isset($item['currency']) ? $currencies[array_search($item['currency'], array_column($currencies, 'id'))]['code'] : 'TRY');
                        $offers[$item['id']] = [
                            '@type'         => 'Offer',
                            'name'          => '.' . $item['name'] . ' Domain',
                            'sku'           => 'domain-' . $item['name'],
                            'availability'  => 'https://schema.org/InStock',
                            'itemCondition' => 'https://schema.org/NewCondition',
                            'seller'        => ['@type' => 'Organization', 'name' => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang))],
                            'url'           => self::parseCanonicalUrl(Controllers::$init->CRLink('domain', false, $lang), $lang)
                        ];
                        if ($item['promo_status'] && 0 < $item['promo_register_price']) {
                            $offers[$item['id']]['priceValidUntil'] = $item['promo_duedate'];
                            $offers[$item['id']]['priceSpecification'] = [
                                ['@type' => 'UnitPriceSpecification', 'price' => (float) sprintf('%.2f', $item['promo_register_price']), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false],
                                ['@type' => 'UnitPriceSpecification', 'priceType' => 'https://schema.org/StrikethroughPrice', 'price' => (float) sprintf('%.2f', $item['reg_price']['amount']), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false]
                            ];
                        }
                        else {
                            $offers[$item['id']]['priceSpecification'] = ['@type' => 'UnitPriceSpecification', 'price' => (float) sprintf('%.2f', $item['reg_price']['amount']), 'priceCurrency' => $currency, 'valueAddedTaxIncluded' => false];
                        }
                    }
                    $output[$template] = [
                        '@context'    => 'https://schema.org',
                        '@type'       => 'Product',
                        'name'        => $pageData['header_title'],
                        'description' => (isset($pageData['meta']['description']) && $pageData['meta']['description'] != '' ? $pageData['meta']['description'] : (isset($pageData['hoptions']['header_description']) && $pageData['header_description'] != '' ? $pageData['header_description'] : false)),
                        'brand'       => ['@type' => 'Brand', 'name' => $gsdData['organisation_name'][$lang] ?? ($gsdData['site_name'][$lang] ?? __('website/index/meta/title', false, $lang))],
                        'image'       => ['@type' => 'ImageObject', 'url' => (isset($pageData['header_background']) && $pageData['header_background'] ? $pageData['header_background'] : false)],
                        'offers'      => array_values($offers)
                    ];
                    ini_set('serialize_precision', $old_serialize_precision);
                }
                if (isset($pageData['hoptions']['gsd_faq']) && $pageData['hoptions']['gsd_faq'] && 0 < count($pageData['hoptions']['gsd_faq'])) {
                    $faqs = [];

                    foreach ($pageData['hoptions']['gsd_faq'] as $faq) {
                        $faqs[] = [
                            '@type'          => 'Question',
                            'name'           => $faq['title'],
                            'acceptedAnswer' => ['@type' => 'Answer', 'text' => $faq['description']]
                        ];
                    }

                    $output['hosting-faqs'] = ['@context' => 'https://schema.org', '@type' => 'FAQPage', 'mainEntity' => $faqs];
                }
            }
        }

        $final_output = '<!-- Google Yapılandırılmış Veri - Start -->' . "\n";
        if ($output && is_array($output) && 0 < count($output)) {
            foreach ($output as $item) {
                $final_output .= '<script type="application/ld+json">';
                $final_output .= json_encode($item, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
                $final_output .= '</script>';
            }
        }

        $final_output .= '<!-- Google Yapılandırılmış Veri - End -->' . "\n";
        return $final_output;
    }

    public function parseOpenGraph(array $data = []): string
    {
        if (($data['type'] ?? '') == 'business.business') {
            $settings = (isset($this->config['settings']) ? $this->config['settings'] : []);
            $data['title'] = (isset($settings['seo_organisation_name'][$this->lang]) ? $settings['seo_organisation_name'][$this->lang] : __('website/meta/title', false, $this->lang));
            $data['image'] = static::assetLinkDetermine(Config::get('theme/header-logo'));
            $data['description'] = __('website/meta/description', false, $this->lang);
            $data['url'] = Controllers::$init->CRLink('contact');
            $address = (isset($settings['seo_organisation_address']) ? $settings['seo_organisation_address'] : Config::get('contact/address') ?? '');
            $city = (isset($settings['seo_organisation_city']) ? $settings['seo_organisation_city'] : '');
            $region = (isset($settings['seo_organisation_region']) ? $settings['seo_organisation_region'] : '');
            $zipcode = (isset($settings['seo_organisation_postal_code']) ? $settings['seo_organisation_postal_code'] : '');
            $country = (isset($settings['seo_organisation_country']) ? $settings['seo_organisation_country'] : Config::get('general/country') ?? '');
            $countryList = AddressManager::getCountryList();
            $countryName = '';

            if ($country) {
                foreach ($countryList as $c) {
                    if (strtoupper($country) == $c['code']) {
                        $countryName = $c['name'];
                    }
                }
            }
        }

        $ogLang = self::getBCPLocale($this->lang);
        $opengraph = '';
        $opengraph .= '<meta property="og:locale" content="' . $ogLang . '">' . PHP_EOL;
        $opengraph .= '<meta property="og:site_name" content="' . __('website/index/meta/title', false, $this->lang) . '">' . PHP_EOL;
        if (isset($data['title'][$this->lang]) && $data['title'][$this->lang] != '') {
            $opengraph .= '<meta property="og:title" content="' . $data['title'][$this->lang] . '">' . PHP_EOL;
        }

        $opengraph .= '<meta property="og:type" content="' . ($data['type'] ?? 'website') . '">' . PHP_EOL;
        $opengraph .= '<meta property="og:url" content="' . $data['url'] . '">' . PHP_EOL;
        if (isset($data['image']) && $data['image'] != '') {
            $opengraph .= '<meta property="og:image" content="' . static::assetLinkDetermine($data['image']) . '">' . PHP_EOL;

            if ($data['type'] != 'business.business') {
                $opengraph .= '<meta property="og:image:width" content="1200">' . PHP_EOL;
                $opengraph .= '<meta property="og:image:height" content="630">' . PHP_EOL;
            }
        }
        if (isset($data['description'][$this->lang]) && $data['description'][$this->lang] != '') {
            $opengraph .= '<meta property="og:description" content="' . $data['description'][$this->lang] . '">' . PHP_EOL;
        }
        if (isset($data['type']) && $data['type'] == 'article') {
            if (isset($data['author']) && $data['author'] != '') {
                $opengraph .= '<meta property="article:author" content="' . $data['author'] . '">' . PHP_EOL;
            }
            if (isset($data['published_time']) && $data['published_time'] != '') {
                $opengraph .= '<meta property="article:published_time" content="' . $data['published_time'] . '">' . PHP_EOL;
            }
            if (isset($data['modified_time']) && $data['modified_time'] != '') {
                $opengraph .= '<meta property="article:modified_time" content="' . $data['modified_time'] . '">' . PHP_EOL;
            }
            if (isset($data['section']) && $data['section'] != '') {
                $opengraph .= '<meta property="article:section" content="' . $data['section'] . '">' . PHP_EOL;
            }
        }
        if (isset($data['type']) && $data['type'] == 'business.business') {
            if (isset($address) && $address != '') {
                $opengraph .= '<meta property="business:contact_data:street_address" content="' . $address . '">' . PHP_EOL;
            }
            if (isset($region) && $region != '') {
                $opengraph .= '<meta property="business:contact_data:locality" content="' . $region . '">' . PHP_EOL;
            }
            if (isset($city) && $city != '') {
                $opengraph .= '<meta property="business:contact_data:region" content="' . $city . '">' . PHP_EOL;
            }
            if (isset($zipcode) && $zipcode != '') {
                $opengraph .= '<meta property="business:contact_data:postal_code" content="' . $zipcode . '">' . PHP_EOL;
            }
            if (isset($countryName) && $countryName != '') {
                $opengraph .= '<meta property="business:contact_data:country_name" content="' . $countryName . '">' . PHP_EOL;
            }
        }
        if (isset($data['type']) && $data['type'] != 'business.business') {
            $opengraph .= '<meta name="twitter:card" content="summary">' . PHP_EOL;
            $opengraph .= '<meta name="twitter:site" content="' . __('website/index/meta/title', false, $this->lang) . '">' . PHP_EOL;
            if (isset($data['description'][$this->lang]) && $data['description'][$this->lang] != '') {
                $opengraph .= '<meta property="twitter:description" content="' . $data['description'][$this->lang] . '">' . PHP_EOL;
            }
            if (isset($data['image']) && $data['image'] != '') {
                $opengraph .= '<meta name="twitter:image:src" content="' . static::assetLinkDetermine($data['image']) . '">' . PHP_EOL;
            }
        }

        return $opengraph;
    }

    private function _gsd_description_create(string $text, int $limit = 250): string
    {
        $text = strip_tags($text);

        if (mb_strlen($text) <= $limit) {
            return $text;
        }

        $short = mb_substr($text, 0, $limit);
        $lastSpace = mb_strrpos($short, ' ');
        return mb_substr($short, 0, $lastSpace) . '…';
    }

    public function gsd_get_page_mtime(string|int $id, string $column = 'mtime', string $type = 'pages'): string
    {
        $time = '';
        $pageTimeExist = WDB::query('SHOW COLUMNS FROM `' . $type . '` LIKE \'' . $column . '\'')->rowCount();

        if ($pageTimeExist) {
            $query = WDB::select('p.' . $column)->from($type . ' AS p')->where('p.id', '=', $id);
            $result = ($query->build() ? $query->getAssoc() : '');
            if ($result && isset($result[$column]) && $result[$column] != '0000-00-00 00:00:00') {
                $time = date(DATE_ATOM, strtotime($result[$column]));
            }
        }

        return $time;
    }

    public static function wordCount(string $unicode_string): int
    {
        $unicode_string = preg_replace('/[\\p{P}\\p{N}]/u', '', $unicode_string);
        $unicode_string = preg_replace('/\\s+/u', ' ', $unicode_string);
        $words_array = preg_split('/\\s+/u', trim($unicode_string), -1, PREG_SPLIT_NO_EMPTY);
        return count($words_array);
    }

    public static function getImageDimensions(string $image_path_or_url, ?string $base_url = NULL): ?string
    {
        if (empty($base_url)) {
            $protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http');
            $host = $_SERVER['HTTP_HOST'];
            $host = preg_replace('/^www\\./', '', $host);
            $base_url = $protocol . '://' . $host;
        }
        $is_remote = (strpos($image_path_or_url, 'http://') === 0) || strpos($image_path_or_url, 'https://') === 0;
        $full_path = NULL;

        if ($is_remote) {
            if (strpos($image_path_or_url, $base_url) === 0) {
                $relative_path = substr($image_path_or_url, strlen($base_url));
                $base_path = $_SERVER['DOCUMENT_ROOT'];
                $full_path = $base_path . '/' . ltrim($relative_path, '/');

                if (!file_exists($full_path)) {
                    return NULL;
                }
            }
            else {
                return NULL;
            }
        }
        else {
            $base_path = $_SERVER['DOCUMENT_ROOT'];
            $full_path = $base_path . '/' . ltrim($image_path_or_url, '/');

            if (!file_exists($full_path)) {
                return NULL;
            }
        }

        $size_info = @getimagesize($full_path);
        if ($size_info !== false && isset($size_info[0]) && isset($size_info[1]) && 0 < $size_info[0] && 0 < $size_info[1]) {
            return 'width="' . $size_info[0] . '" height="' . $size_info[1] . '"';
        }

        return NULL;
    }

    public static function getImageThumb(string $image, string $type = 'articles'): string
    {
        $defaultImage = 'resources/uploads/' . $type . '/default.jpg';

        if ($type == 'software') {
            $defaultImage = 'resources/uploads/' . $type . '/list-image-default.jpg';
        }

        $defaultImage = static::assetLinkDetermine($defaultImage);

        if ($image) {
            $image = trim($image);
            $parts = parse_url($image);
            $itemImagePath = (isset($parts['path']) ? $parts['path'] : '');
            $segments = explode('/', trim($itemImagePath, '/'));
            $itemImageFolder = $segments[count($segments) - 2] ?? '';
            $itemImageFile = end($segments) ?: '';

            if (strpos($itemImagePath, '/' . $type . '/thumb/') !== false) {
                $defaultImage = $image;
            }
            else {
                $thumbUrl = preg_replace('#/(' . preg_quote($type, '#') . ')/#', '/$1/thumb/', $image, 1);
                $thumbPath = RESOURCE_DIR . 'uploads' . DS . $type . DS . 'thumb' . DS . $itemImageFolder . DS . $itemImageFile;

                if (file_exists($thumbPath)) {
                    $defaultImage = $thumbUrl;
                }
                else {
                    $defaultImage = $image;
                }
            }
        }

        return $defaultImage;
    }

    private function sanitizeRelativePath(string $path): string
    {
        $safePath = str_replace('\\', '/', $path);
        $safePath = str_replace('..', '', $safePath);
        return ltrim($safePath, '/');
    }

    private function buildGalleryPrettyTitle(string $fileBaseName): string
    {
        $cleaned = preg_replace('/[^a-zA-Z0-9]+/', ' ', $fileBaseName) ?? '';
        $cleaned = trim($cleaned);

        if ($cleaned === '') {
            return 'Untitled';
        }

        return ucwords(strtolower($cleaned));
    }

    private function ensureThumbDirectory(string $path): void
    {
        if (!is_dir($path)) {
            mkdir($path, 509, true);
        }
    }

    private function buildGalleryThumbForImage(string $relativePath, string $baseDir, string $thumbDir, int $width, int $height): array
    {
        if (!class_exists('Upload')) {
            require_once ROOT_DIR . 'coremio' . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'libraries' . DIRECTORY_SEPARATOR . 'Uploads' . DIRECTORY_SEPARATOR . 'class.upload.php';
        }

        $safeRelativePath = $this->sanitizeRelativePath($relativePath);
        $sourcePath = realpath($baseDir . DIRECTORY_SEPARATOR . $safeRelativePath);
        $baseRealPath = realpath($baseDir);
        if ($sourcePath === false || $baseRealPath === false || strpos($sourcePath, $baseRealPath) !== 0) {
            return ['crop' => $safeRelativePath, 'fit' => $safeRelativePath];
        }

        $sourceDir = (string) pathinfo($safeRelativePath, PATHINFO_DIRNAME);
        $baseName = (string) pathinfo($safeRelativePath, PATHINFO_FILENAME);
        $safeBaseName = Filter::permalink($baseName);
        $sourceDir = ($sourceDir === '.' ? '' : $sourceDir);
        $targetDir = $thumbDir . ($sourceDir !== '' ? DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $sourceDir) : '');
        $this->ensureThumbDirectory($targetDir);
        $fileStem = $safeBaseName . '_' . $width . '_' . $height;
        $cropName = $fileStem . '_crop.jpg';
        $fitName = $fileStem . '_fit.jpg';
        $cropAbsolute = $targetDir . DIRECTORY_SEPARATOR . $cropName;
        $fitAbsolute = $targetDir . DIRECTORY_SEPARATOR . $fitName;

        if (!is_file($cropAbsolute)) {
            $upload = new Upload($sourcePath);
            $upload->image_resize = true;
            $upload->image_convert = 'jpg';
            $upload->image_x = $width;
            $upload->image_y = $height;
            $upload->image_ratio_crop = true;
            $upload->jpeg_quality = 85;
            $upload->file_safe_name = false;
            $upload->file_overwrite = true;
            $upload->file_new_name_body = $fileStem . '_crop';
            $upload->file_new_name_ext = 'jpg';
            $upload->process($targetDir);
        }

        if (!is_file($fitAbsolute)) {
            $upload = new Upload($sourcePath);
            $upload->image_resize = true;
            $upload->image_convert = 'jpg';
            $upload->image_x = $width;
            $upload->image_y = $height;
            $upload->image_ratio = true;
            $upload->jpeg_quality = 85;
            $upload->file_safe_name = false;
            $upload->file_overwrite = true;
            $upload->file_new_name_body = $fileStem . '_fit';
            $upload->file_new_name_ext = 'jpg';
            $upload->process($targetDir);
        }

        $thumbPrefix = 'fongallerythumb/' . ($sourceDir !== '' ? $sourceDir . '/' : '');
        return ['crop' => $thumbPrefix . $cropName, 'fit' => $thumbPrefix . $fitName];
    }

    private function _parseResponsiveBootstrapTextAligns(object|array $alignData): string
    {
        if (empty($alignData)) {
            return '';
        }

        $alignData = (array) $alignData;
        $directionMap = ['left' => 'start', 'right' => 'end', 'center' => 'center', 'justify' => 'justify'];
        $classes = [];

        foreach ($alignData as $breakpoint => $value) {
            if (!isset($directionMap[$value])) {
                continue;
            }

            $bsValue = $directionMap[$value];

            if ($breakpoint === 'xs') {
                $classes[] = 'text-' . $bsValue;
            }
            else {
                $classes[] = 'text-' . $breakpoint . '-' . $bsValue;
            }
        }

        return implode(' ', $classes);
    }

    private function _parseResponsiveBootstrapFlexAligns(object|array $alignData): string
    {
        if (empty($alignData)) {
            return '';
        }

        $alignData = (array) $alignData;
        $directionMap = ['left' => 'start', 'right' => 'end', 'center' => 'center', 'justify' => 'between'];
        $classes = [];

        foreach ($alignData as $breakpoint => $value) {
            if (!isset($directionMap[$value])) {
                continue;
            }

            $bsValue = $directionMap[$value];

            if ($breakpoint === 'xs') {
                $classes[] = 'justify-content-' . $bsValue;
            }
            else {
                $classes[] = 'justify-content-' . $breakpoint . '-' . $bsValue;
            }
        }

        return implode(' ', $classes);
    }

    public static function getFieldMultilingualText(mixed $field, string $currentLang = 'tr', array|string $default = ''): string
    {
        if (!isset($field) || empty($field)) {
            return $default;
        }
        if (is_object($field) || is_array($field)) {
            $fieldArray = (array) $field;
            if (isset($fieldArray[$currentLang]) && $fieldArray[$currentLang] !== '') {
                return $fieldArray[$currentLang];
            }

            $firstValue = array_values($fieldArray)[0] ?? '';
            return ($firstValue !== '' ? $firstValue : $default);
        }

        if (is_string($field)) {
            return ($field !== '' ? $field : $default);
        }

        return $default;
    }

    private function addPreloadLink(string $imageUrl, string $page = 'index', string $as = 'image'): void
    {
        $url = static::assetLinkDetermine($imageUrl);
        $preloadCode = '<link rel="preload" href="' . $url . '" as="' . $as . '" fetchpriority="high">';
        $encoded = htmlentities($preloadCode, ENT_QUOTES, 'UTF-8');
        $this->addHeaderCode($page, $encoded . PHP_EOL);
    }

    private function handlePatternImages(string $classes, string $pageKey, string $tadress, bool $isLcpCandidate = false): string
    {
        $themeUrl = $tadress . 'images/bg/';
        $patterns = [
            'bg-data-pattern-left'      => [
            'images' => ['data-pattern-left.png'],
            'pos'    => 'left center',
            'size'   => 'contain'
        ],
            'bg-data-pattern-right'     => [
            'images' => ['data-pattern-right.png'],
            'pos'    => 'right center',
            'size'   => 'contain'
        ],
            'bg-data-pattern-all'       => [
            'images' => ['data-pattern-left.png', 'data-pattern-right.png'],
            'pos'    => 'left center, right center',
            'size'   => '450px, 450px'
        ],
            'bg-data-pattern-all-white' => [
            'images' => ['data-pattern-left-white.png', 'data-pattern-right-white.png'],
            'pos'    => 'left center, right center',
            'size'   => '450px, 450px'
        ]
        ];
        $inlineStyle = '';
        $classArray = array_filter(explode(' ', $classes));

        foreach ($patterns as $classKey => $data) {
            if (in_array($classKey, $classArray)) {
                if ($isLcpCandidate && self::$lcpHandled === false) {
                    foreach ($data['images'] as $img) {
                        $fullUrl = $themeUrl . $img;
                        $this->addPreloadLink($fullUrl, $pageKey);
                    }
                }

                $bgUrls = [];

                foreach ($data['images'] as $img) {
                    $bgUrls[] = 'url(' . $themeUrl . $img . ')';
                }

                $inlineStyle = 'background-image: ' . implode(',', $bgUrls) . '!important; ';

                if (isset($data['pos'])) {
                    $inlineStyle .= 'background-position: ' . $data['pos'] . '!important; ';
                }

                if (isset($data['size'])) {
                    $inlineStyle .= 'background-size: ' . $data['size'] . '!important; ';
                }

                break;
            }
        }

        return $inlineStyle;
    }
}

?>

FonPageBuilder.php lisans mekanizma oldugu yeri paylaştım

PHP:
private function runLicenseCheck($activate = false)
    {
        if (!function_exists('curl_init') || !function_exists('curl_exec') || !function_exists('curl_setopt')) {
            self::$licenseStatus = false;
            $this->error = self::$licenseError = 'PHP Curl Library not found';
            return false;
        }

        $licenseFile = __DIR__ . DS . 'LICENSE';
        $license_data = self::getLicenseFileData();
        $config = include __DIR__ . DS . 'config.php';
        $createdAt = (isset($config['created_at']) ? (int) $config['created_at'] : 0);
        $cacheHash = (isset($config['settings']['cache_hash']) ? $config['settings']['cache_hash'] : '');
        $decodedHash = (!empty($cacheHash) ? Crypt::decode($cacheHash, Config::get('crypt/system')) : '');
        $isVerified = $decodedHash === $config['meta']['name'] . '_cache_secure_99';
        if (!$activate && !empty($license_data) && isset($license_data['next-check-time'])) {
            if (time() < strtotime($license_data['next-check-time'])) {
                self::$licenseStatus = true;
                return true;
            }
        }

        $retryCount = (isset($license_data['retry-count']) ? (int) $license_data['retry-count'] : 0);
        $documentRoot = realpath($_SERVER['DOCUMENT_ROOT']);
        $currentDir = realpath(__DIR__);

        if (strpos($currentDir, $documentRoot) !== 0) {
            return false;
        }

        $domain = Utility::getDomain();

        if (!$domain) {
            if (isset($_SERVER['HTTP_X_BALANCED_HOST'])) {
                $domain = str_replace('www.', '', $_SERVER['HTTP_X_BALANCED_HOST']);
            }
            else if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
                $domain = str_replace('www.', '', $_SERVER['HTTP_X_FORWARDED_HOST']);
            }
            else if (isset($_SERVER['HTTP_HOST'])) {
                $domain = str_replace('www.', '', $_SERVER['HTTP_HOST']);
            }
            else {
                $domain = str_replace('www.', '', $_SERVER['SERVER_NAME']);
            }
        }

        $directory = __DIR__;

        if (class_exists('UserManager')) {
            $ip = UserManager::GetIP();
        }
        else {
            $ip = static::getClientIP();
        }

        $server_ip = $_SERVER['SERVER_ADDR'];
        if (($server_ip == '127.0.0.1') && isset($_SERVER['HTTP_X_TARGET_IP'])) {
            $server_ip = $_SERVER['HTTP_X_TARGET_IP'];
        }

        $origin = (Utility::isSSL() ? 'https://' : 'http://');
        $entered_url = $origin . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        $entered_url = parse_url($entered_url);
        unset($entered_url['query']);
        $entered_url = $entered_url['scheme'] . '://' . $entered_url['host'] . rtrim($entered_url['path'], '/');
        $referer_url = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');

        if ($referer_url) {
            $referer_url = parse_url($referer_url);
            unset($referer_url['query']);
            $referer_url = $referer_url['scheme'] . '://' . $referer_url['host'] . rtrim($referer_url['path'], '/');
        }

        $parameters = ['domain' => $domain, 'server_ip' => $server_ip, 'user_ip' => $ip, 'entered_url' => $entered_url, 'referer_url' => $referer_url, 'directory' => $directory];
        $address = 'https://fononline.net/license/checking/d153d7b91000f4b1509484fb3b896d03/305?' . http_build_query($parameters);
        $resultErr = false;
        if (!file_exists($licenseFile) || empty($license_data)) {
            $isOldInstall = 86400 < (time() - $createdAt);
            $isFirstMigration = !isset($config['settings']['cache_hash']);
            if ($isOldInstall || $isVerified) {
                if (!$isFirstMigration) {
                    $result = self::useLicenseCurl($address, $resultErr, true);

                    if ($result['status'] !== 'success') {
                        self::$licenseStatus = false;
                        $this->error = self::$licenseError = 'Güvenlik doğrulaması yapılamadı. Lütfen internet bağlantınızı kontrol edin.';
                        return false;
                    }
                }
            }
        }

        if (!isset($result)) {
            $result = self::useLicenseCurl($address, $resultErr, true);
        }

        if ($result['status'] !== 'success') {
            Modules::save_log('Addons', __CLASS__, __FUNCTION__, $parameters, $address, $result);
            $isHardError = ($result['message'] === 'ERROR') || $result['status'] == 'license_error';

            if ($isHardError) {
                self::setConfigVerified(false);
                $report = self::useLicenseCurl('https://fononline.net/license/error?user_ip=' . $ip, $resultErr);
                $rawError = $report['message'] ?: ($this->lang['license_error_message'] ?? 'Geçerli bir lisansınız yok.');
                $errBody = static::getBodyFromCurlResponse($rawError);

                if (!$errBody) {
                    $errBody = $rawError;
                }

                $this->error = self::$licenseError = $errBody;
                $nextCheckTime = date('Y-m-d H:i:s', strtotime('+1 day'));
                $gracePeriodEnd = date('Y-m-d H:i:s');
                $retryCount = 0;
                self::$licenseStatus = false;
            }
            else {
                ++$retryCount;

                if ($retryCount <= 8) {
                    $nextCheckTime = date('Y-m-d H:i:s', strtotime('+3 hours'));
                    self::$licenseStatus = true;
                    $gracePeriodEnd = $nextCheckTime;
                    $rawError = $resultErr ?: ($this->lang['license_error_curl'] ?? 'Bağlantı sorunu, yeniden deneniyor.');
                }
                else {
                    $nextCheckTime = date('Y-m-d H:i:s', strtotime('+3 hours'));
                    $gracePeriodEnd = date('Y-m-d H:i:s');
                    self::$licenseStatus = false;
                    $rawError = $this->lang['license_error_timeout'] ?? 'Lisans sunucusuna ulaşılamadı. Lütfen sunucunuzun dış bağlantılarını kontrol edin.';
                }

                $errBody = static::getBodyFromCurlResponse($rawError);

                if (!$errBody) {
                    $errBody = $rawError;
                }

                $this->error = self::$licenseError = $errBody;
            }

            $checkFileData = self::cryptChip('encrypt', Utility::jencode(['last-check-time' => date('Y-m-d H:i:s'), 'next-check-time' => $nextCheckTime, 'license-status' => self::$licenseStatus, 'grace-period-end' => $gracePeriodEnd, 'license-error' => $this->error, 'retry-count' => $retryCount]), 'a2dNeVRxQlJxaGpTUVNUUTZiT2xFM0VyeUJLYVF5YWIvQWtXLytQNTFiK01NR0prL2ZVSmgwTyt3dGhZYkJOdw==');
            FileManager::file_write(__DIR__ . DS . 'LICENSE', $checkFileData);
            self::getLicenseFileData(true);
            return self::$licenseStatus;
        }
        if (isset($this) && $this instanceof self) {
            $set_config = $this->config;
            $rawValue = $set_config['meta']['name'] . '_cache_secure_99';
            $set_config['settings']['cache_hash'] = Crypt::encode($rawValue, Config::get('crypt/system'));
            $this->save_config($set_config);
            $this->config = $set_config;
        }
        else {
            self::setConfigVerified(true);
        }

        $checkFileData = self::cryptChip('encrypt', Utility::jencode(['last-check-time' => date('Y-m-d H:i:s'), 'next-check-time' => date('Y-m-d H:i:s', strtotime('+1 month')), 'license-status' => true, 'retry-count' => 0]), 'a2dNeVRxQlJxaGpTUVNUUTZiT2xFM0VyeUJLYVF5YWIvQWtXLytQNTFiK01NR0prL2ZVSmgwTyt3dGhZYkJOdw==');
        FileManager::file_write(__DIR__ . DS . 'LICENSE', $checkFileData);
        self::getLicenseFileData(true);
        self::$licenseStatus = true;
        self::$licenseError = '';
        return true;
    }

    private static function getLicenseFileData($reload = false)
    {
        if ($reload || !static::$licenseTempFile) {
            if (!file_exists(__DIR__ . DS . 'LICENSE')) {
                return false;
            }

            $checkingFileData = FileManager::file_read(__DIR__ . DS . 'LICENSE');

            if ($checkingFileData) {
                $checkingFileData = self::cryptChip('decrypt', $checkingFileData, 'a2dNeVRxQlJxaGpTUVNUUTZiT2xFM0VyeUJLYVF5YWIvQWtXLytQNTFiK01NR0prL2ZVSmgwTyt3dGhZYkJOdw==');

                if ($checkingFileData) {
                    static::$licenseTempFile = Utility::jdecode($checkingFileData, true);
                    return static::$licenseTempFile;
                }
            }
        }
        else {
            return static::$licenseTempFile;
        }

        return false;
    }

    private static function cryptChip($action, $string, $salt = '')
    {
        if ($salt != 'a2dNeVRxQlJxaGpTUVNUUTZiT2xFM0VyeUJLYVF5YWIvQWtXLytQNTFiK01NR0prL2ZVSmgwTyt3dGhZYkJOdw==') {
            return false;
        }

        $key = '0|.%J.MF4AMT$(.VU1J' . $salt . 'O1SbFd$|N83JG' . str_replace('www.', '', $_SERVER['SERVER_NAME']) . '.~&/-_f?fge&';
        $output = false;
        $encrypt_method = 'AES-256-CBC';

        if (is_null($key)) {
            $secret_key = 'NULL';
        }
        else {
            $secret_key = $key;
        }

        $secret_iv = 'JxaGpTUVNUUTZiT2';
        $key = hash('sha256', $secret_key);
        $iv = substr(hash('sha256', $secret_iv), 0, 16);

        if ($action === 'encrypt') {
            $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
            $output = base64_encode($output);
        }
        else if ($action === 'decrypt') {
            $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
        }

        return $output;
    }

    private static function getClientIP()
    {
        $ipKeys = ['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];

        foreach ($ipKeys as $key) {
            if (!empty($_SERVER[$key])) {
                $ipList = preg_split('/[\\s,]+/', $_SERVER[$key]);

                foreach ($ipList as $ip) {
                    if (filter_var($ip, FILTER_VALIDATE_IP)) {
                        return $ip;
                    }
                }
            }
        }

        return '0.0.0.0';
    }

    private static function useLicenseCurl($address, &$error_msg, $check = false)
    {
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => $address,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 3,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 20,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'GET',
            CURLOPT_HEADER => true,
            CURLOPT_NOBODY => false,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_USERAGENT => 'FonPageBuilder-License-Checker/2.0',
            CURLOPT_RESOLVE => ['fononline.net:443:18.102.222.10']
        ]);
        $response = curl_exec($curl);
        $errNo = curl_errno($curl);
        $error = curl_error($curl);

        if ($errNo) {
            $error_msg = 'Error Code: ' . $errNo . ' - ' . $error;
            curl_close($curl);
            return ['status' => 'timeout', 'code' => 'cURL', 'errno' => $errNo, 'message' => $error_msg];
        }

        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
        $body = trim(substr($response, $header_size));

        if (!mb_check_encoding($body, 'UTF-8')) {
            $body = mb_convert_encoding($body, 'UTF-8', 'ISO-8859-9');
        }

        curl_close($curl);

        if ($httpCode == 200) {
            if ($check) {
                if ($body === 'OK') {
                    return ['status' => 'success', 'code' => $httpCode, 'message' => $body];
                }
                else {
                    return ['status' => 'license_error', 'code' => $httpCode, 'message' => $body];
                }
            }

            return ['status' => 'error', 'code' => $httpCode, 'message' => $body];
        }
        else if (400 <= $httpCode) {
            return ['status' => 'server_error', 'code' => $httpCode, 'message' => $body];
        }

        return ['status' => 'error', 'code' => $httpCode, 'message' => 'Unknown License Control Response'];
    }

    private static function getBodyFromCurlResponse($html)
    {
        if (empty($html)) {
            return '';
        }

        $doc = new DOMDocument();
        libxml_use_internal_errors(true);
        $utf8_header = '<?xml encoding="utf-8" ?>';
        $doc->loadHTML($utf8_header . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOERROR | LIBXML_NOWARNING);
        libxml_clear_errors();
        $body = $doc->getElementsByTagName('body')->item(0);

        if (!$body) {
            $text = $doc->saveHTML();
        }
        else {
            $text = $doc->saveHTML($body);
        }

        $text = strip_tags($text);
        $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
        $text = preg_replace('/\\s+/', ' ', $text);
        return trim($text);
    }

    public function isLicenseValid(): bool
    {
        $licenseData = self::getLicenseFileData();
        if (isset($licenseData['grace-period-end']) && time() < strtotime($licenseData['grace-period-end'])) {
            return true;
        }

        return self::$licenseStatus === true;
    }

    private static function setConfigVerified($status = true)
    {
        $configPath = __DIR__ . DS . 'config.php';

        if (!file_exists($configPath)) {
            return false;
        }

        $config = include $configPath;
        $rawValue = $config['meta']['name'] . '_cache_secure_99';
        $hashValue = ($status ? Crypt::encode($rawValue, Config::get('crypt/system')) : '');
        if (isset($config['settings']['cache_hash']) && $hashValue === $config['settings']['cache_hash']) {
            return true;
        }

        $config['settings']['cache_hash'] = $hashValue;
        $export = Utility::array_export($config, ['pwith' => true]);
        return FileManager::file_write($configPath, $export);
    }

    public function create_error($error = '')
    {
        if ($error) {
            Helper::Load(['Events']);
            return Events::create([
                'type'     => 'info',
                'owner'    => 'system',
                'owner_id' => '0',
                'name'     => 'module-addon-error',
                'data'     => ['name' => __CLASS__, 'message' => $error]
            ]);
        }

        return false;
    }

    private function disableAddon()
    {
        $config = $this->config;
        $config['status'] = 0;
        FileManager::file_write(__DIR__ . DS . 'config.php', Utility::array_export($config, ['pwith' => true]));
        return true;
    }

    public function upgrade()
    {
        if (version_compare($this->version, $this->config['meta']['version'], '>')) {
            $set_config = $this->config;
            if (isset($set_config['created_at']) && $set_config['created_at'] == 1693916240) {
                $set_config['created_at'] = time();
            }

            $set_config['meta']['version'] = $this->version;
            $this->save_config($set_config);
            $this->config = $set_config;
            $dbPrefix = Config::get('database/prefix');
            $tables = [$dbPrefix . 'categories' => 'mtime', $dbPrefix . 'pages' => 'mtime', $dbPrefix . 'knowledgebase' => 'mtime', $dbPrefix . 'fonpagebuilder' => 'mtime'];

            foreach ($tables as $table => $column) {
                $checkColumn = WDB::query('SHOW COLUMNS FROM `' . $table . '` LIKE \'' . $column . '\'')->rowCount();

                if ($checkColumn == 0) {
                    WDB::query('ALTER TABLE `' . $table . '` ADD COLUMN `' . $column . '` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;');
                }
            }

            $tblSuggestions = $dbPrefix . 'fon_ai_domain_suggestions';

            if (!WDB::hasTable($tblSuggestions)) {
                $sql = 'CREATE TABLE IF NOT EXISTS `' . $tblSuggestions . '` (' . "\r\n" . '                    `id`          INT AUTO_INCREMENT PRIMARY KEY,' . "\r\n" . '                    `sorgu_hash`  CHAR(32)     NOT NULL,' . "\r\n" . '                    `user_query`  TEXT         NOT NULL,' . "\r\n" . '                    `engine`      VARCHAR(30)  NOT NULL DEFAULT \'\',' . "\r\n" . '                    `model`       VARCHAR(120) NOT NULL DEFAULT \'\',' . "\r\n" . '                    `lang`        CHAR(5)      NOT NULL DEFAULT \'\',' . "\r\n" . '                    `tlds`        VARCHAR(255) NOT NULL DEFAULT \'\',' . "\r\n" . '                    `ai_response` JSON         NOT NULL,' . "\r\n" . '                    `created_at`  TIMESTAMP    DEFAULT CURRENT_TIMESTAMP,' . "\r\n" . '                    FULLTEXT KEY `ft_query`   (`user_query`),' . "\r\n" . '                    INDEX        `idx_hash`   (`sorgu_hash`),' . "\r\n" . '                    INDEX        `idx_filter` (`engine`, `lang`)' . "\r\n" . '                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';

                if (!WDB::exec($sql)) {
                    $this->create_error = 'fon_ai_domain_suggestions veritabanı tablosu oluşturulamadı.';
                }
            }

            $tblStats = $dbPrefix . 'fon_ai_stats';

            if (!WDB::hasTable($tblStats)) {
                $sql = 'CREATE TABLE IF NOT EXISTS `' . $tblStats . '` (' . "\r\n" . '                    `id`                INT AUTO_INCREMENT PRIMARY KEY,' . "\r\n" . '                    `user_ip`           VARCHAR(45)   NOT NULL,' . "\r\n" . '                    `engine`            VARCHAR(30)   NOT NULL DEFAULT \'\',' . "\r\n" . '                    `model`             VARCHAR(120)  NOT NULL DEFAULT \'\',' . "\r\n" . '                    `prompt_tokens`     INT           NOT NULL DEFAULT 0,' . "\r\n" . '                    `completion_tokens` INT           NOT NULL DEFAULT 0,' . "\r\n" . '                    `total_tokens`      INT           NOT NULL DEFAULT 0,' . "\r\n" . '                    `estimated_cost`    DECIMAL(15,10) NOT NULL DEFAULT 0.0000000000,' . "\r\n" . '                    `cache_hit`         TINYINT(1)    NOT NULL DEFAULT 0,' . "\r\n" . '                    `similar_hit`       TINYINT(1)    NOT NULL DEFAULT 0,' . "\r\n" . '                    `created_at`        TIMESTAMP     DEFAULT CURRENT_TIMESTAMP,' . "\r\n" . '                    INDEX `idx_created` (`created_at`),' . "\r\n" . '                    INDEX `idx_engine`  (`engine`)' . "\r\n" . '                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';

                if (!WDB::exec($sql)) {
                    $this->create_error = 'fon_ai_stats veritabanı tablosu oluşturulamadı.';
                }
            }
        }

        return true;
    }

    private static function logLicense($message)
    {
        $logFile = __DIR__ . '/license_debug.log';
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = '[' . $timestamp . '] [IP: ' . $_SERVER['REMOTE_ADDR'] . '] [URL: ' . $_SERVER['REQUEST_URI'] . ('] ' . $message) . PHP_EOL;
        file_put_contents($logFile, $logEntry, FILE_APPEND);
    }

    private static function diffDay($start = '', $end = '')
    {
        $dStart = new DateTime($start);
        $dEnd = new DateTime($end);
        $dDiff = $dStart->diff($dEnd);
        return $dDiff->days;
    }

    private static function siteMapCategoryRoute($id, $lang)
    {
        $hierarchy = [];
        $query = WDB::select('c.id, c.parent, cl.route');
        $query->from('categories c');
        $query->join('INNER', 'categories_lang cl', 'cl.owner_id = c.id');
        $query->where('c.type', '=', 'products', '&&');
        $query->where('cl.lang', '=', $lang, '&&');
        $query->where('c.id', '=', $id);
        $category = ($query->build() ? $query->getAssoc() : false);

        while ($category) {
            array_unshift($hierarchy, $category['route']);

            if ($category['parent'] == 0) {
                break;
            }

            $query = WDB::select('c.id, c.parent, cl.route');
            $query->from('categories c');
            $query->join('INNER', 'categories_lang cl', 'cl.owner_id = c.id');
            $query->where('c.id', '=', $category['parent'], '&&');
            $query->where('cl.lang', '=', $lang);
            $category = $query->build(true)->getAssoc();
        }

        if (2 < count($hierarchy)) {
            $hierarchy = array_slice($hierarchy, -2, 2, true);
        }

        return $hierarchy;
    }

    public function save_fields($fields = [])
    {
        return $fields;
    }

    public function activate()
    {
        $set_config = $this->config;
        if (isset($set_config['created_at']) && $set_config['created_at'] == 1693916240) {
            $set_config['created_at'] = time();
            $this->save_config($set_config);
            $this->config = $set_config;
        }

        $licenced = $this->runLicenseCheck(true);

        if (!$licenced) {
            return false;
        }

        if (!file_exists($this->imageFolder)) {
            @mkdir($this->imageFolder, 511, true);
            @touch($this->imageFolder . DS . 'index.html');
        }

        $operation = WDB::exec('CREATE TABLE IF NOT EXISTS `fonpagebuilder` (' . "\r\n\t\t\t\t" . '  `id` int(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,' . "\r\n\t\t\t\t" . '  `name` varchar(255) NOT NULL,' . "\r\n\t\t\t\t" . '  `type` varchar(100) NOT NULL,' . "\r\n\t\t\t\t" . '  `type_id` int(11) NOT NULL DEFAULT 0,' . "\r\n\t\t\t\t" . '  `page_options` text,' . "\r\n\t\t\t\t" . '  `page_content` longtext,' . "\r\n\t\t\t\t" . '  `page_style` text DEFAULT NULL,' . "\r\n\t\t\t\t" . '  `status` tinyint(1) NOT NULL DEFAULT 1,' . "\r\n\t\t\t\t" . '  `ctime` datetime NOT NULL DEFAULT current_timestamp(),' . "\r\n\t\t\t\t" . '  `mtime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP' . "\r\n\t\t\t\t" . ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;' . "\r\n\t\t\t\t" . 'CREATE TABLE IF NOT EXISTS `fonpagebuilder_saved` (' . "\r\n\t\t\t\t" . '  `id` int(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,' . "\r\n\t\t\t\t" . '  `name` varchar(255) NOT NULL,' . "\r\n\t\t\t\t" . '  `type` varchar(100) NOT NULL,' . "\r\n\t\t\t\t" . '  `page_content` text DEFAULT NULL' . "\r\n\t\t\t\t" . ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;' . "\r\n\t\t\t");

        if (!$operation) {
            $this->error = $this->lang['database_not_created'] ?? 'Veritabanı oluşturulamadı: ';
            return false;
        }

        return true;
    }

    public function deactivate()
    {
        $set = ['status' => 0];
        $operation = Models::$init->db->update('fonpagebuilder');
        $operation->set($set);
        $operation->where('status', '=', '1');
        $save = $operation->save();
        return true;
    }
kırdım @richard :)