<?php // https://divibooster.com/replace-pagination-numbers-with-icons-in-divi-gallery-module/

namespace DiviBooster\GalleryBooster\GridNumberIcons;

// === Constants ===
const DIVI4_MODULE_SLUG = 'et_pb_gallery';
const DIVI5_MODULE_SLUG = 'divi/gallery';

// Divi 4 field slugs (snake_case)
const D4_DISPLAY_MODE = 'divibooster_pagination_number_display';
const D4_NUMBER_ICON  = 'divibooster_pagination_number_icon';

// Divi 5 attribute slugs (camelCase)
const D5_DISPLAY_MODE = 'diviboosterPaginationNumberDisplay';
const D5_NUMBER_ICON  = 'diviboosterPaginationNumberIcon';

// === Divi 4: Add Fields ===
add_filter('et_pb_all_fields_unprocessed_' . DIVI4_MODULE_SLUG, __NAMESPACE__ . '\d4_add_fields');
function d4_add_fields($fields) {
    if (!is_array($fields)) return $fields;

    $fields[D4_DISPLAY_MODE] = array(
        'label'           => esc_html__('Pagination Number Display', 'divi-booster'),
        'type'            => 'select',
        'options'         => array(
            'default'     => esc_html__('Default (Numbers)', 'divi-booster'),
            'icon'        => esc_html__('Icon', 'divi-booster'),
        ),
        'default'         => 'default',
        'option_category' => 'configuration',
        'tab_slug'        => 'general',
        'toggle_slug'     => 'elements',
        'description'     => esc_html__('Choose how to display the numeric pagination links for the gallery grid.', 'divi-booster'),
        'show_if'         => array(
            'fullwidth'       => 'off',
            'show_pagination' => 'on',
        ),
    );

    $fields[D4_NUMBER_ICON] = array(
        'label'           => esc_html__('Pagination Number Icon', 'divi-booster'),
        'type'            => 'select_icon',
        'class'           => array('et-pb-font-icon'),
        'option_category' => 'basic_option',
        'tab_slug'        => 'general',
        'toggle_slug'     => 'elements',
        'description'     => esc_html__('Choose an icon to display in place of the numeric pagination links.', 'divi-booster'),
        'show_if'         => array(
            'fullwidth'       => 'off',
            'show_pagination' => 'on',
            D4_DISPLAY_MODE   => array('icon'),
        ),
        'mobile_options'  => false,
        'hover'           => 'tabs',
        'sticky'          => true,
    );

    return $fields;
}

// === Divi 5: Attribute Registration (PHP) ===
add_filter('divi_module_library_register_module_attrs', __NAMESPACE__ . '\d5_register_attrs', 10, 2);
function d5_register_attrs($attrs, $args) {
    if (($args['name'] ?? '') !== DIVI5_MODULE_SLUG) return $attrs;
    $attrs[D5_DISPLAY_MODE] = get_d5_display_attr_definition();
    $attrs[D5_NUMBER_ICON]  = get_d5_icon_attr_definition();
    return $attrs;
}

// === Divi 5: VB Attribute Registration & Conversion Mapping (JS) ===
add_action('divi_visual_builder_assets_before_enqueue_scripts', __NAMESPACE__ . '\enqueue_d5_vb_script');
function enqueue_d5_vb_script() {
    if ((!function_exists('et_builder_d5_enabled') || !\et_builder_d5_enabled()) ||
        (!function_exists('et_core_is_fb_enabled') || !\et_core_is_fb_enabled())) {
        return;
    }
    $handle = sanitize_title('divibooster-d5-gallery-grid-number-icons');
    wp_register_script($handle, '', ['lodash', 'divi-vendor-wp-hooks'], null, true);
    wp_enqueue_script($handle);
    wp_add_inline_script($handle, get_d5_vb_inline_js());
}

// === Divi 5: PHP conversion outline registration ===
add_filter('divi.moduleLibrary.conversion.moduleConversionOutline', __NAMESPACE__ . '\d5_register_conversion_outline', 10, 2);
function d5_register_conversion_outline($conversion_outline, $module_name) {
    if ($module_name !== DIVI5_MODULE_SLUG) return $conversion_outline;

    if (!isset($conversion_outline['module']) || !is_array($conversion_outline['module'])) {
        $conversion_outline['module'] = array();
    }
    $conversion_outline['module'][D4_DISPLAY_MODE] = D5_DISPLAY_MODE . '.*';
    $conversion_outline['module'][D4_NUMBER_ICON]  = D5_NUMBER_ICON . '.innerContent.*';

    if (!isset($conversion_outline['valueExpansionFunctionMap']) || !is_array($conversion_outline['valueExpansionFunctionMap'])) {
        $conversion_outline['valueExpansionFunctionMap'] = array();
    }
    $conversion_outline['valueExpansionFunctionMap'][D4_NUMBER_ICON] = 'convertFontIcon';

    return $conversion_outline;
}

// === Divi 4 Output Filter ===
add_filter('et_module_shortcode_output', __NAMESPACE__ . '\d4_output_filter', 10, 3);
function d4_output_filter($output, $render_slug, $module) {
    if (!is_string($output) || $render_slug !== DIVI4_MODULE_SLUG || !isset($module->props) || !is_array($module->props)) {
        return $output;
    }
    $props = $module->props;
    if (!is_grid_pagination_enabled_d4($props)) return $output;

    $config = build_config_from_d4($props);
    if (!should_output_css($config)) return $output;

    $order_class = extract_order_class($output);
    if (!$order_class) return $output;

    $output = inject_config_into_pagination_number_container($output, $config);

    // Register wp_footer hook only if gallery is rendered
    if (!has_action('wp_footer', 'divibooster_gallery_booster_grid_number_icons_wp_footer')) {
        add_action('wp_footer', __NAMESPACE__ . '\\divibooster_gallery_booster_grid_number_icons_wp_footer');
    }

    $css = generate_icons_css($order_class, $config['mode'], $config['icon']);
    if ($css) {
        $output = $css . ensure_icon_font_loaded($config['icon']) . $output;
    }
    return $output;
}

// === Divi 5 Block Output Filter ===
add_filter('render_block_' . DIVI5_MODULE_SLUG, __NAMESPACE__ . '\d5_output_filter', 10, 3);
function d5_output_filter($block_content, $parsed_block, $block) {
    $attrs = $parsed_block['attrs'] ?? array();
    if (!is_grid_pagination_enabled_d5($attrs)) return $block_content;

    $config = build_config_from_d5($attrs);
    if (!should_output_css($config)) return $block_content;

    $order_class = '';
    if (is_string($block_content) && preg_match('/class="([^"]+)"/i', $block_content, $m)) {
        $classes = preg_split('/\s+/', $m[1], -1, PREG_SPLIT_NO_EMPTY);
        foreach ($classes as $cls) {
            if (strpos($cls, 'et_pb_gallery_') === 0) { $order_class = $cls; break; }
        }
    }
    if (!$order_class) return $block_content;

    $block_content = inject_config_into_pagination_number_container($block_content, $config);

    // Register wp_footer hook only if gallery is rendered
    if (!has_action('wp_footer', 'divibooster_gallery_booster_grid_number_icons_wp_footer')) {
        add_action('wp_footer', __NAMESPACE__ . '\\divibooster_gallery_booster_grid_number_icons_wp_footer');
    }

    $css = generate_icons_css($order_class, $config['mode'], $config['icon']);
    if ($css) {
        $block_content = $css . ensure_icon_font_loaded($config['icon']) . $block_content;
    }
    return $block_content;
}

// === Helpers & Generators (low-level) ===
function is_grid_pagination_enabled_d4($props) {
    $fullwidth = isset($props['fullwidth']) ? $props['fullwidth'] : 'off';
    $show_pagination = isset($props['show_pagination']) ? $props['show_pagination'] : 'on';
    return ($fullwidth === 'off') && ($show_pagination === 'on');
}
function is_grid_pagination_enabled_d5($attrs) {
    $fullwidth = $attrs['module']['advanced']['fullwidth']['desktop']['value'] ?? 'off';
    $show_pagination = $attrs['pagination']['advanced']['showPagination']['desktop']['value'] ?? 'on';
    return ($fullwidth === 'off') && ($show_pagination === 'on');
}
function extract_order_class($html) {
    if (!is_string($html)) return '';
    if (preg_match('/class="([^"]+)"/i', $html, $m)) {
        foreach (preg_split('/\s+/', $m[1], -1, PREG_SPLIT_NO_EMPTY) as $cls) {
            if (strpos($cls, 'et_pb_gallery_') === 0) return $cls;
        }
    }
    return '';
}
function normalize_icon_from_d4($value) {
    if (!is_string($value) || $value === '') return false;
    $parts = explode('||', $value);
    $entity = trim($parts[0]);
    if (!$entity) return false;
    // Normalize to lower-case entity if provided as &#x....;
    if (preg_match('/&#x([0-9a-fA-F]+);/', $entity, $m)) {
        $entity = '&#x' . strtolower($m[1]) . ';';
    }
    return [ 'unicode' => $entity, 'fontFamily' => 'ETmodules' ];
}
function normalize_icon_from_d5($attrs_value) {
    if (!is_array($attrs_value)) return false;
    $unicode = $attrs_value['innerContent']['desktop']['value']['unicode'] ?? '';
    if (!$unicode) return false;
    if (preg_match('/&#x([0-9a-fA-F]+);/', $unicode, $m)) {
        $unicode = '&#x' . strtolower($m[1]) . ';';
    }
    return [ 'unicode' => $unicode, 'fontFamily' => 'ETmodules' ];
}
function entity_to_css_unicode($entity) {
    if (!is_string($entity) || $entity === '') return '';
    if (preg_match('/&#x([0-9a-fA-F]+);/', $entity, $m)) {
        $hex = strtolower($m[1]);
        $hex = str_pad($hex, 4, '0', STR_PAD_LEFT);
        return '\\' . $hex;
    }
    if (preg_match('/\\([0-9a-fA-F]{3,6})/', $entity, $m)) {
        return '\\' . strtolower($m[1]);
    }
    return '';
}
function build_config_from_d4($props) {
    $mode = isset($props[D4_DISPLAY_MODE]) ? trim((string)$props[D4_DISPLAY_MODE]) : 'default';
    $icon = isset($props[D4_NUMBER_ICON]) ? normalize_icon_from_d4($props[D4_NUMBER_ICON]) : false;
    $mode = in_array($mode, ['default','icon'], true) ? $mode : 'default';
    return [ 'mode' => $mode, 'icon' => $icon ];
}
function build_config_from_d5($attrs) {
    $mode = $attrs[D5_DISPLAY_MODE]['desktop']['value'] ?? ($attrs[D5_DISPLAY_MODE]['value'] ?? 'default');
    $icon = normalize_icon_from_d5($attrs[D5_NUMBER_ICON] ?? []);
    $mode = in_array($mode, ['default','icon'], true) ? $mode : 'default';
    return [ 'mode' => $mode, 'icon' => $icon ];
}
function should_output_css($config) {
    if (!is_array($config)) return false;
    $mode = $config['mode'] ?? 'default';
    $icon = $config['icon'] ?? false;
    if ($mode === 'default') return false;
    if ($mode === 'icon' && !$icon) return false; // no icon selected -> fallback to numbers
    return true;
}
function ensure_icon_font_loaded($icon) {
    if (!$icon || empty($icon['unicode'])) return '';
    $entity = $icon['unicode'];
    if (function_exists('et_pb_process_font_icon')) {
        $icon_code = et_pb_process_font_icon($entity);
        // Hidden element to trigger the ETmodules font enqueue
        return '<i class="et-pb-icon" style="position:absolute;left:-9999px;visibility:hidden;height:0;overflow:hidden;">' . et_core_esc_previously($icon_code) . '</i>';
    }
    return '';
}
function generate_icons_css($order_class, $mode, $icon) {
    if (!$order_class || !$icon || empty($icon['unicode'])) return '';
    $css_unicode = entity_to_css_unicode($icon['unicode']);
    if (!$css_unicode) return '';
    $prefix = '.' . $order_class . ' ';

    // Target only numeric links (exclude prev/next links by class if present)
    $base = $prefix . '.et_pb_gallery_pagination a:not(.page-prev):not(.page-next)';

    $css  = "<style type=\"text/css\">\n";
    $css .= $base . "{ position: relative; }\n";
    $css .= $base . '::before{ content: "' . esc_attr($css_unicode) . '"; font-family: \'' . esc_attr($icon['fontFamily'] ?? 'ETmodules') . '\' !important; display:inline; vertical-align:baseline; color: inherit; }' . "\n";
    $css .= "</style>";
    return $css;
}

// === Divi 5 Attribute Definitions (helpers) ===
function get_d5_display_attr_definition() {
    return [
        'type' => 'object',
        'settings' => [
            'innerContent' => [
                'groupType' => 'group-items',
                'items' => [
                    'paginationNumberDisplay' => [
                        'groupSlug'   => 'contentElements',
                        'attrName'    => D5_DISPLAY_MODE,
                        'label'       => __('Pagination Number Display', 'divi-booster'),
                        'description' => __('Choose how to display the numeric pagination links for the gallery grid.', 'divi-booster'),
                        'features'    => [ 'hover' => false, 'sticky' => false, 'responsive' => false, 'preset' => 'elements' ],
                        'render'      => true,
                        'priority'    => 65,
                        'component'   => [ 'type' => 'field', 'name' => 'divi/select', 'props' => [ 'options' => [
                            'default'     => [ 'label' => __('Default (Numbers)', 'divi-booster') ],
                            'icon'        => [ 'label' => __('Icon', 'divi-booster') ],
                        ]]],
                        'defaultAttr' => [ 'desktop' => [ 'value' => 'default' ] ],
                    ],
                ],
            ],
        ],
    ];
}
function get_d5_icon_attr_definition() {
    return [
        'type' => 'object',
        'settings' => [
            'innerContent' => [
                'groupType' => 'group-items',
                'items' => [
                    'paginationNumberIcon' => [
                        'groupSlug'   => 'contentElements',
                        'attrName'    => D5_NUMBER_ICON . '.innerContent',
                        'label'       => __('Pagination Number Icon', 'divi-booster'),
                        'description' => __('Choose an icon to display in place of the numeric pagination links.', 'divi-booster'),
                        'features'    => [ 'hover' => false ],
                        'render'      => true,
                        'priority'    => 66,
                        'component'   => [ 'type' => 'field', 'name' => 'divi/icon-picker' ],
                    ],
                ],
            ],
        ],
    ];
}

function get_d5_vb_inline_js() {
    $defs = [
        D5_DISPLAY_MODE => get_d5_display_attr_definition(),
        D5_NUMBER_ICON  => get_d5_icon_attr_definition(),
    ];
    $defs_json = [];
    foreach ($defs as $k => $v) { $defs_json[$k] = $v; }
    $defs_json = wp_json_encode($defs_json);

    $display_key = wp_json_encode(D5_DISPLAY_MODE);
    $icon_key    = wp_json_encode(D5_NUMBER_ICON);
    $d4slug      = wp_json_encode(DIVI4_MODULE_SLUG);

    return <<<JS
(function(){
  const hooks = window.vendor?.wp?.hooks; if (!hooks) return; const { addFilter } = hooks;

  const visibleInGridWithPagination = ({ attrs }) => {
    const fullwidth = attrs?.module?.advanced?.fullwidth?.desktop?.value ?? "off";
    const showPagination = attrs?.pagination?.advanced?.showPagination?.desktop?.value ?? "on";
    return fullwidth === "off" && showPagination === "on";
  };
  const getDisplayMode = attrs => attrs?.diviboosterPaginationNumberDisplay?.desktop?.value
      ?? attrs?.diviboosterPaginationNumberDisplay?.value ?? 'default';
    const iconVisible = (ctx) => visibleInGridWithPagination(ctx) && ["icon"].includes(getDisplayMode(ctx?.attrs||{}));

  addFilter('divi.moduleLibrary.moduleAttributes.divi.gallery', 'divi', (attributes) => {
    const defs = {$defs_json};
    try {
      if (defs[{$display_key}]?.settings?.innerContent?.items?.paginationNumberDisplay) {
        defs[{$display_key}].settings.innerContent.items.paginationNumberDisplay.visible = visibleInGridWithPagination;
      }
      if (defs[{$icon_key}]?.settings?.innerContent?.items?.paginationNumberIcon) {
        defs[{$icon_key}].settings.innerContent.items.paginationNumberIcon.visible = iconVisible;
      }
    } catch(e){}
    attributes[{$display_key}] = defs[{$display_key}];
    attributes[{$icon_key}]    = defs[{$icon_key}];
    return attributes;
  });

  addFilter('divi.moduleLibrary.conversion.moduleConversionOutline', 'divi', (outline, name) => {
    if (name !== {$d4slug}) return outline;
    const { convertFontIcon } = window?.divi?.conversion || {};
    if (!outline.module) outline.module = {};
    outline.module['divibooster_pagination_number_display'] = 'diviboosterPaginationNumberDisplay.*';
    outline.module['divibooster_pagination_number_icon']    = 'diviboosterPaginationNumberIcon.innerContent.*';
    outline.valueExpansionFunctionMap = outline.valueExpansionFunctionMap || {};
    outline.valueExpansionFunctionMap['divibooster_pagination_number_icon'] = convertFontIcon;
    return outline;
  });
})();
JS;
}

function inject_config_into_pagination_number_container($html, $config) {
    if (!is_string($html) || empty($config['mode'])) return $html;
    $mode = $config['mode'];
    // Always set data-pagination-number-display
    $html = preg_replace('/(<div[^>]*class="[^"]*et_pb_gallery[^"]*"[^>]*)/i', '$1 data-pagination-number-display="' . esc_attr($mode) . '"', $html, 1);
    return $html;
}

// === End of file ===
// Created at 1756158363.

function divibooster_gallery_booster_grid_number_icons_wp_footer() {
    static $done = false;
    if ($done) return;
    $done = true;
    ?>
    <style>
    /* Hide pagination numbers until JS updates them */
    .et_pb_gallery.et_pb_gallery_grid[data-pagination-number-display="icon"] .et_pb_gallery_pagination a:not(.page-prev):not(.page-next) {
        visibility: hidden;
    }
    </style>
    <script>
    (function(){
        document.querySelectorAll('.et_pb_gallery.et_pb_gallery_grid').forEach(function(gallery){
            var displayMode = gallery.getAttribute('data-pagination-number-display') || 'default';
            var pagination = gallery.querySelector('.et_pb_gallery_pagination');
            if (!pagination) return;
            var updateNumberLinks = function(){
                setTimeout(function() {
                    var numberLinks = pagination.querySelectorAll('a:not(.page-prev):not(.page-next)');
                    if (displayMode === 'icon') {
                        numberLinks.forEach(function(link){ link.textContent = ''; link.style.visibility = 'visible'; });
                    }
                }, 1000);
            };
            updateNumberLinks();
            var observer = new MutationObserver(function(mutations){
                updateNumberLinks();
                observer.disconnect();
            });
            observer.observe(pagination, { childList: true, subtree: true });
        });
    })();
    </script>
    <?php
}
