<?php
//ANCHOR - Show Stories

function dacdb_stories($atts)
{
    global $fDebug, $data_path, $options;
    $options = get_mmp_options();

    // Enqueue required JavaScript
    wp_enqueue_script(
        'dacdb-plus',
        plugins_url('js/dacdb_plus.js', dirname(__FILE__)),
        array('jquery'),
        MMPDB_PLUGIN_VERSION,
        true
    );

    $stories = '';
    $account_id = $options['dacdb_district'];
    $club_id = $options['dacdb_club'];

    $default_atts = [
        'storyid' => '',
        'storyids' => '',
        'story_output_style' => 0,
        'story_summary' => 0,
        'story_sep' => 0,
        'story_image' => 0,
        'story_open' => 0,
        'story_share' => 1,
        'story_social' => 0,
        'story_limit' => 0,
        'catid' => '',
        'pagetitle' => '',
        'headline' => '',
        'show_headline' => 1
    ];

    // Log default attributes
    error_log('Default attributes: ' . print_r($default_atts, true));

    // Log initial states with filtered options
    $filtered_options = filter_relevant_settings($options);
    error_log('Filtered options: ' . print_r($filtered_options, true));
    error_log('Shortcode attributes: ' . print_r($atts, true));
    error_log('Query string parameters: ' . print_r($_GET, true));

    // Normalize show_headline
    $raw_show_headline = $_GET['show_headline'] ?? $_GET['headline'] ?? $_GET['pagetitle'] ?? $atts['show_headline'] ?? $atts['headline'] ?? $atts['pagetitle'] ?? 1;
    $show_headline = normalize_boolean($raw_show_headline);

    // Build $variables array with existence checks
    $variables = [
        'storyid' => isset($_GET['storyid']) ? $_GET['storyid'] : (isset($atts['storyid']) ? $atts['storyid'] : (isset($options['storyid']) ? $options['storyid'] : $default_atts['storyid'])),
        'storyids' => isset($_GET['storyids']) ? $_GET['storyids'] : (isset($atts['storyids']) ? $atts['storyids'] : (isset($options['storyids']) ? $options['storyids'] : $default_atts['storyids'])),
        'story_output_style' => isset($_GET['story_output_style']) ? $_GET['story_output_style'] : (isset($atts['story_output_style']) ? $atts['story_output_style'] : (isset($options['story_output_style']) ? $options['story_output_style'] : $default_atts['story_output_style'])),
        'story_summary' => isset($_GET['story_summary']) ? $_GET['story_summary'] : (isset($atts['story_summary']) ? $atts['story_summary'] : (isset($options['story_summary']) ? $options['story_summary'] : $default_atts['story_summary'])),
        'story_sep' => isset($_GET['story_sep']) ? $_GET['story_sep'] : (isset($atts['story_sep']) ? $atts['story_sep'] : (isset($options['story_sep']) ? $options['story_sep'] : $default_atts['story_sep'])),
        'story_image' => isset($_GET['story_image']) ? $_GET['story_image'] : (isset($atts['story_image']) ? $atts['story_image'] : (isset($options['story_image']) ? $options['story_image'] : $default_atts['story_image'])),
        'story_open' => isset($_GET['story_open']) ? $_GET['story_open'] : (isset($atts['story_open']) ? $atts['story_open'] : (isset($options['story_open']) ? $options['story_open'] : $default_atts['story_open'])),
        'story_share' => isset($_GET['story_share']) ? $_GET['story_share'] : (isset($atts['story_share']) ? $atts['story_share'] : (isset($options['story_share']) ? $options['story_share'] : $default_atts['story_share'])),
        'story_social' => isset($_GET['story_social']) ? $_GET['story_social'] : (isset($atts['story_social']) ? $atts['story_social'] : (isset($options['story_social']) ? $options['story_social'] : $default_atts['story_social'])),
        'story_limit' => isset($_GET['story_limit']) ? $_GET['story_limit'] : (isset($_GET['n']) ? $_GET['n'] : (isset($_GET['limit']) ? $_GET['limit'] : (isset($_GET['count']) ? $_GET['count'] : (isset($atts['story_limit']) ? $atts['story_limit'] : (isset($options['story_limit']) ? $options['story_limit'] : $default_atts['story_limit']))))),
        'catid' => isset($_GET['catid']) ? $_GET['catid'] : (isset($atts['catid']) ? $atts['catid'] : (isset($options['catid']) ? $options['catid'] : $default_atts['catid'])),
        'show_headline' => $show_headline
    ];

    // Log variable assignment
    error_log('Variables after assignment: ' . print_r($variables, true));

    // Filter and process story IDs
    $variables['storyids'] = array_filter(array_map('trim', explode(',', $variables['storyids'])));
    if (!empty($variables['storyid']) && !empty($variables['storyids'])) {
        $variables['storyids'][] = $variables['storyid'];
    }
    if (empty($variables['storyid']) && count($variables['storyids']) === 1) {
        $variables['storyid'] = $variables['storyids'][0];
        $variables['storyids'] = [];
    } elseif (count($variables['storyids']) === 1) {
        $variables['storyid'] = $variables['storyids'][0];
        $variables['storyids'] = [];
    }
    $variables['storyids'] = implode(',', $variables['storyids']);

    // Log processed story IDs
    error_log('Processed story IDs: ' . print_r($variables['storyids'], true));

    // Prepare parameters for the query
    $params = [
        'AccountID' => $account_id,
        'ClubID' => $club_id,
        'CatIDs' => $variables['catid'],
        'StoryID' => $variables['storyid'],
        'StoryIDs' => $variables['storyids'],
        'N' => $variables['story_limit']
    ];
    $params = array_filter($params);

    // Build query URL
    $query = http_build_query($params);
    $url = $data_path . 'wp_stories.cfm?' . $query;

    // Enqueue styles
    wp_enqueue_style('show-stories', MMPDB_PLUGIN_URL . 'css/show-stories.css', array('dacdb-bootstrap'), MMPDB_PLUGIN_VERSION, 'all');

    // Load XML using the robust utility function
    $xml = dacdb_load_xml($url . '&R=' . rand(), 'stories');
    
    if ($xml === false) {
        if (current_user_can('administrator')) {
            return "Error loading stories: Failed to load XML. Please check the error logs.";
        }
        return 'There are no stories at this time.';
    }

    // Debug output
    if ($fDebug && dacdb_is_admin()) {
        $stories .= debug_output($options, $atts, $_GET, $url, $xml, $variables);
    }

    if (empty($xml->story)) {
        return 'There are no stories at this time.';
    }

    // Process stories
    $story_count = 0;
    if (!empty($variables['storyid'])) {
        $stories .= '<div class="mmp-stories">';
        $stories .= format_full_story($variables['storyid'], $options, $variables);
        $stories .= '</div>';
        return $stories;
    } else {
        foreach ($xml->story as $story) {
            if ($variables['story_limit'] != 0 && $story_count >= $variables['story_limit']) {
                break;
            }
            $stories .= '<div class="mmp-stories">';
            $stories .= ($variables['story_output_style'] === 1) ? format_story_summary_modern($story, $options, $variables) : format_story_summary_legacy($story, $options, $variables);
            $stories .= '</div>';
            $story_count++;
        }
        return $stories;
    }
}

function generate_summary($text, $word_limit)
{
    // Strip HTML tags from the text
    $text = strip_tags($text);

    // Split the text into words
    $words = preg_split('/\s+/', $text, -1, PREG_SPLIT_NO_EMPTY);
    if (count($words) > $word_limit) {
        return implode(' ', array_slice($words, 0, $word_limit)) . '...';
    }
    return implode(' ', $words);
}
function format_story_summary_legacy($story, $options, $variables)
{
    static $counter = 1; // Static counter for image alignment alternation
    $markup = '<article id="storyid-' . htmlspecialchars($story->storyid) . '">';
    $markup .= '<header>';

    // Story header
    if ($variables['show_headline']) {
        $markup .= '<h1>' . htmlspecialchars($story->headline) . '</h1>';
    }

    // Date and byline
    if ($story->bitbyline == 1 || $story->biteditedby == 1 || $story->bitstorydate == 1) {
        $markup .= '<div class="attribution">';

        if ($story->bitbyline == 1) {
            $byline = !empty($story->submittedby) ? $story->submittedby : (!empty($story->createdby) ? $story->createdby : bloginfo('name'));
            if (!empty($byline)) {
                $markup .= '<span class="posted-by">By <strong itemprop="author" itemscope="" itemtype="http://schema.org/Person">' . htmlspecialchars($byline) . '</strong></span>';
            }
        }

        if ($story->biteditedby == 1) {
            $editedby = !empty($story->modifiedby) ? $story->modifiedby : bloginfo('name');
            if (!empty($editedby)) {
                $editorClass = $story->bitbyline == 0 ? 'posted-by' : 'edited-by';
                $markup .= '<span class="' . $editorClass . '">Edited By <strong itemprop="editor" itemscope="" itemtype="http://schema.org/Person">' . htmlspecialchars($editedby) . '</strong></span>';
            }
        }

        if ($story->bitstorydate == 1) {
            $markup .= '<span class="posted-on">' . htmlspecialchars($story->storydate) . '</span>';
        }

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

    if (isset($options['story_share']) && $options['story_share'] == 1) {
        $markup .= get_social_share_links($story->headline, $story->summary, $story->storyid, $story->smsoptions, $variables['story_social']);
    }

    $markup .= '</header>';

    // Image handling
    if (!empty($story->image)) {
        $imageAlignment = $variables['story_image'] == 1 ? 'left' : ($variables['story_image'] == 2 ? 'right' : (($counter % 2 == 0) ? 'right' : 'left'));
        $counter++;

        $markup .= '<img src="' . htmlspecialchars($story->image) . '" align="' . $imageAlignment . '" class="' . $imageAlignment . '" loading="lazy" alt="Main article image for story titled \'' . htmlspecialchars($story->headline) . '\'" title="' . htmlspecialchars($story->headline) . '">';
    }

    // Summary and description
    $generated = empty(trim($story->summary));
    $summary = $generated ? generate_summary($story->description, 50) : $story->summary;
    $class = $generated ? 'generated summary' : 'summary';

    $final_output = '<div><p class="' . $class . '">' . $summary . '</p>';

    $markup .= $final_output;
    if (!empty($story->description)) {
        if ($variables['story_open'] == 0) {
            $markup .= '<span id="description-' . htmlspecialchars($story->storyid) . '" class="description" style="display:none;">' . wp_kses_post($story->description) . '</span>';
            $markup .= '<p><a href="#" onclick="return showdiv(' . htmlspecialchars($story->storyid) . ')" id="more-' . htmlspecialchars($story->storyid) . '" class="read-more">Read More</a></p>';
        } else {
            $markup .= '<p><a href="?storyid=' . htmlspecialchars($story->storyid) . '"' . ($variables['story_open'] == 2 ? ' target="_blank"' : '') . ' class="read-more">Read More</a></p>';
        }
    }

    // Separator if needed
    if (isset($options['story_sep']) && $options['story_sep'] != '9') {
        $hrstyles = [
            "0" => '', "1" => 'style-one', "2" => 'style-two', "3" => 'style-three',
            "4" => 'style-four', "5" => 'style-five', "6" => 'style-six',
            "7" => 'style-seven', "8" => 'style-eight', "9" => 'style-nine'
        ];
        $hrstyle = isset($hrstyles[$options['story_sep']]) ? $hrstyles[$options['story_sep']] : '';
        
        $markup .= '<hr class="' . $hrstyle . '">';
    }

    $markup .= '</article>'; // Close the main div
    return $markup;
}

function format_story_summary_modern($story, $options, $variables)
{
    $markup = '<article class="story" itemscope itemtype="https://schema.org/NewsArticle">';
    $summary = !empty($story->summary) ? $story->summary : generate_summary($story->description);
    // Header section with headline
    $markup .= '<header>';
    $markup .= '<h2 itemprop="headline">' . htmlspecialchars($story->headline) . '</h2>';
    if (!empty($story->storydate)) {
        $markup .= '<time datetime="' . formatDateToISO($story->storydate) . '">' . htmlspecialchars($story->storydate) . '</time>';
    }


    if (isset($options['story_share']) && $options['story_share'] == 1) {
        $markup .= get_social_share_links($story->headline, $story->summary, $story->storyid, $story->smsoptions, $variables['story_social']);
    }

    $markup .= '</header>';

    // Image section
    if (!empty($story->image)) {
        $markup .= '<img src="' . htmlspecialchars($story->image) . '" loading="lazy" alt="Main article image for story titled \'' . htmlspecialchars($story->headline) . '\'">';
    }

    // Summary section
    if (!empty($story->summary)) {
        $markup .= '<p class="summary">' . htmlspecialchars($summary) . '</p>';
    }

    // Footer section with byline
    if (!empty($story->submittedby) || !empty($story->modifiedby)) {
        $markup .= '<footer>';
        $byline = !empty($story->submittedby) ? $story->submittedby : $story->modifiedby;
        $markup .= '<p>By: ' . htmlspecialchars($byline) . '</p>';
        $markup .= '</footer>';
    }

    // Full story content in a hidden div
    $markup .= '<div id="description-' . htmlspecialchars($story->storyid) . '" class="description" style="display:none;">';
    
    // Allow style tags for this content by setting it as a data attribute instead
    // This will prevent WordPress from stripping the style tags and display as text
    $markup .= '<div class="story-content" 
                     data-story-id="' . htmlspecialchars($story->storyid) . '" 
                     data-story-content="' . htmlspecialchars($story->description) . '">
               </div>';
    
    $markup .= '</div>';

    // Read More link
    if ($options['story_open'] == '0') {
        $markup .= '<a href="#" onclick="showdiv(' . htmlspecialchars($story->storyid) . '); return false;"  id="more-' . htmlspecialchars($story->storyid) . '" class="read-more">Read More</a>';
    } else {
        $target = $options['story_open'] == '2' ? ' target="_blank"' : '';
        $markup .= '<a href="?storyid=' . htmlspecialchars($story->storyid) . '"' . $target . '  id="more-' . htmlspecialchars($story->storyid) . '" class="read-more">Read More</a>';
    }

    $markup .= '</article>';
    return $markup;
}
function format_full_story($storyid, $options, $variables)
{
    global $data_path, $options;
    $options = get_mmp_options();

    // Base URL setup for fetching a specific story
    $url = $data_path . 'wp_stories.cfm?AccountID=' . $options['dacdb_district'] . '&ClubID=' . $options['dacdb_club'] . '&StoryID=' . $storyid;
    $xml = dacdb_load_xml($url, 'story');

    if ($xml === false || empty($xml->story)) {
        return 'Story not found.';
    }

    // Build the link back to the stories list page
    $url_components = parse_url($_SERVER['REQUEST_URI']);
    parse_str($url_components['query'] ?? '', $params);
    unset($params['storyid']);
    $new_query_string = http_build_query($params);
    $storypage_url = $url_components['path'] . ($new_query_string ? '?' . $new_query_string : '');

    $story = $xml->story[0]; // Assuming the XML returns a single story node
    $show_summary = $variables['story_summary'];

    // Render the article
    $markup = '<article id="storyid-' . htmlspecialchars($story->storyid) . '" class="full">';
    $markup .= '<header>';
    // Story header
    if ($variables['show_headline']) {
        $markup .= '<h1>' . htmlspecialchars($story->headline) . '</h1>';
    }
    $markup .= $show_summary == 1 ? '<h2>' . $story->summary . '</h2>' : '';

    // Date and byline
    if ($story->bitbyline == 1 || $story->biteditedby == 1 || $story->bitstorydate == 1) {
        $markup .= '<div class="attribution">';

        if ($story->bitbyline == 1) {
            $byline = !empty($story->submittedby) ? $story->submittedby : (!empty($story->createdby) ? $story->createdby : bloginfo('name'));
            if (!empty($byline)) {
                $markup .= '<span class="posted-by">By <strong itemprop="author" itemscope="" itemtype="http://schema.org/Person">' . htmlspecialchars($byline) . '</strong></span>';
            }
        }

        if ($story->biteditedby == 1) {
            $editedby = !empty($story->modifiedby) ? $story->modifiedby : bloginfo('name');
            if (!empty($editedby)) {
                $editorClass = $story->bitbyline == 0 ? 'posted-by' : 'edited-by';
                $markup .= '<span class="' . $editorClass . '">Edited By <strong itemprop="editor" itemscope="" itemtype="http://schema.org/Person">' . htmlspecialchars($editedby) . '</strong></span>';
            }
        }

        if ($story->bitstorydate == 1) {
            $markup .= '<span class="posted-on">' . htmlspecialchars($story->storydate) . '</span>';
        }

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

    if (isset($options['story_share']) && $options['story_share'] == 1) {
        $markup .= get_social_share_links($story->headline, $story->summary, $story->storyid, $story->smsoptions, $variables['story_social']);
    }

    $markup .= '</header>';

    // Image handling
    $mainImage = '';
    if (!empty($story->image)) {
        $imageAlignment = ($variables['story_image'] == 1) ? 'left' : ($variables['story_image'] == 2 ? 'right' : 'left');
        $mainImage .= '<img src="' . htmlspecialchars($story->image) . '" align="' . $imageAlignment . '" class="' . $imageAlignment . '" loading="lazy" alt="Main article image for story titled \'' . htmlspecialchars($story->headline) . '\'" title="' . htmlspecialchars($story->headline) . '">';
    }

    // Summary and description
    if (!isset($show_summary) || $show_summary == 0) {
        $markup .= '<div class="description-full">' . $mainImage . $story->summary;
        $markup .= '<div class="story-content" data-story-id="' . htmlspecialchars($story->storyid) . '" data-story-content="' . htmlspecialchars($story->description) . '"></div>';
        $markup .= '</div>';  // Full story description
    }

    // Show Summary Option 1: Show summary as a styled subhead above the story
    if (isset($show_summary) && $show_summary == 1) {
        $markup .= '<div class="description-full">' . $mainImage;
        $markup .= '<div class="story-content" data-story-id="' . htmlspecialchars($story->storyid) . '" data-story-content="' . htmlspecialchars($story->description) . '"></div>';
        $markup .= '</div>';  // Full story description
    }

    // Show Summary Option 2: Show summary as a caption for the main image
    if (isset($show_summary) && $show_summary == 2) {
        $markup .= '<div class="description-full">';
        $markup .= '<figure>' . $mainImage . '<figcaption>' . wp_kses_post($story->summary) . '</figcaption></figure>';
        $markup .= '<div class="story-content" data-story-id="' . htmlspecialchars($story->storyid) . '" data-story-content="' . htmlspecialchars($story->description) . '"></div>';
        $markup .= '</div>';  // Full story description
    }

    // Show Summary Option 3: Hide the summary and show only the full story
    if (isset($show_summary) && $show_summary == 3) {
        $markup .= '<div class="description-full">' . $mainImage;
        $markup .= '<div class="story-content" data-story-id="' . htmlspecialchars($story->storyid) . '" data-story-content="' . htmlspecialchars($story->description) . '"></div>';
        $markup .= '</div>';  // Full story description
    }

    $markup .= '<p><a href="' . $storypage_url . '" class="back-to-list">Back to Stories List</a></p>';
    $markup .= '</article>';
    return $markup;
}
function get_social_share_links($story_title, $story_summary, $storyid, $smsoptions, $story_social)
{
    $options = get_mmp_options();
    // Split the smsoptions string into an array
    $active_social_options = explode(',', $smsoptions);

    $site_name = get_bloginfo('name'); // Fetches the website name from WordPress settings
    $current_page_url = home_url($_SERVER['REQUEST_URI']); // Fetches the current URL
    $story_url = add_query_arg('storyid', (string)$storyid, $current_page_url);
    $encoded_url = urlencode($story_url);
    $encoded_title = urlencode($story_title);
    $subject = rawurlencode("{$story_title} (From {$site_name})");
    $email_body = rawurlencode("{$story_summary}\n\nRead more at: {$story_url}");
    $mail_url = "mailto:?subject={$subject}&body={$email_body}";

    $html = '<div class="mmpro-share">';
    $html .= '<span class="mmpro-share__label">Share:</span>';
    $html .= '<a class="mmpro-share__link" href="' . $story_url . '" title="Permalink"><i class="mmpro-share__icon mmpro-share__icon--link fa fa-link"></i><span class="a11y-sr-only">Permalink</span></a>';
    $html .= '<a class="mmpro-share__link" href="' . $mail_url . '" title="Send by email"><i class="mmpro-share__icon mmpro-share__icon--email fa fa-envelope"></i><span class="a11y-sr-only">Email this Page</span></a>';

    if (isset($options['story_social']) && $options['story_social'] == 1) {
        // URLs for sharing on social media
        $facebook_url = "https://www.facebook.com/sharer/sharer.php?u={$encoded_url}";
        $twitter_url = "https://twitter.com/share?url={$encoded_url}&text={$subject}&via=rotary";
        $linkedin_url = "https://www.linkedin.com/shareArticle?mini=true&url={$encoded_url}";
        $tumblr_url = "https://www.tumblr.com/share/link?url={$encoded_url}&name={$encoded_title}";
        $reddit_url = "https://reddit.com/submit?url={$encoded_url}&title={$encoded_title}";
        $pinterest_url = "https://pinterest.com/pin/create/button/?url={$encoded_url}";
        $mastodon_url = "https://mastodon.social/share?text={$encoded_title} {$encoded_url}";
        $evernote_url = "https://www.evernote.com/clip.action?url={$encoded_url}&title={$encoded_title}";

        $social_media_links = [
            'FB' => ['url' => $facebook_url, 'icon' => 'facebook-f', 'name' => 'Facebook', 'prefix' => 'fab'],
            'TW' => ['url' => $twitter_url, 'icon' => 'twitter', 'name' => 'Twitter', 'prefix' => 'fab'],
            'LI' => ['url' => $linkedin_url, 'icon' => 'linkedin', 'name' => 'LinkedIn', 'prefix' => 'fab'],
            'TU' => ['url' => $tumblr_url, 'icon' => 'tumblr', 'name' => 'Tumblr', 'prefix' => 'fab'],
            'RE' => ['url' => $reddit_url, 'icon' => 'reddit', 'name' => 'Reddit', 'prefix' => 'fab'],
            'PT' => ['url' => $pinterest_url, 'icon' => 'pinterest', 'name' => 'Pinterest', 'prefix' => 'fab'],
            'MA' => ['url' => $mastodon_url, 'icon' => 'mastodon', 'name' => 'Mastodon', 'prefix' => 'fab'],
            'EN' => ['url' => $evernote_url, 'icon' => 'bookmark', 'name' => 'Evernote', 'prefix' => 'fas']
        ];

        foreach ($social_media_links as $key => $data) {
            if (in_array($key, $active_social_options)) {
                $html .= '<a class="mmpro-share__link" href="' . $data['url'] . '" target="_blank" title="Share to ' . $data['name'] . '"><i class="mmpro-share__icon mmpro-share__icon--' . strtolower($data['icon']) . ' ' . $data['prefix'] . ' fa-' . $data['icon'] . '"></i><span class="a11y-sr-only">Share on ' . $data['name'] . '</span></a>';
            }
        }
    }

    $html .= '</div>';
    return $html;
}
function filter_relevant_settings($settings)
{
    $filtered_settings = [];
    foreach ($settings as $key => $value) {
        if (strpos($key, 'dacdb_') === 0 || strpos($key, 'story_') === 0) {
            $filtered_settings[$key] = $value;
        }
    }
    return $filtered_settings;
}
function debug_output($options, $atts, $get_vars, $url, $xml, $variables)
{
    $debugInfo = '<div class="debug-output">';
    $debugInfo .= '<h5>function <em><strong>dacdb_stories</strong></em> called:</h5>';

    // Show Shortcode Settings
    $debugInfo .= '<h4 class="drawer">Shortcode Settings</h4><pre class="panel">';
    foreach ($options as $key => $value) {
        $debugInfo .= "<dt>$key</dt><dd>" . (isset($value) ? $value : 'Not set') . "</dd>";
    }
    $debugInfo .= '</pre>';

    // Show Shortcode Attributes if there are any
    if (count($atts) > 0) {
        $debugInfo .= '<h4 class="drawer">Shortcode Attributes</h4><pre class="panel">';
        foreach ($atts as $key => $value) {
            $debugInfo .= "<dt>$key</dt><dd>$value</dd>";
        }
        $debugInfo .= '</pre>';
    }

    // Show URL parameters if there are any (except for "debug")
    if (count($get_vars) > 1 || (count($get_vars) == 1 && !array_key_exists("debug", $get_vars))) {
        $debugInfo .= '<h4 class="drawer">URL Parameters</h4><pre class="panel">';
        foreach ($get_vars as $key => $value) {
            if ($key !== "debug") {
                $debugInfo .= "<dt>$key</dt><dd>$value</dd>";
            }
        }
        $debugInfo .= '</pre>';
    }

    // Include named variables and their values based on $variables
    $debugInfo .= '<h4 class="drawer">Named Variables</h4><pre class="panel"><dl>';
    foreach ($variables as $key => $value) {
        $debugInfo .= "<dt>\$$key</dt><dd>" . (isset($value) ? $value : 'Not set') . "</dd>";
    }
    $debugInfo .= '</dl></pre>';

    // Include URL
    $debugInfo .= '<h4 class="drawer">URLs</h4><pre class="panel"><dl>';
    $debugInfo .= '<dt>URL</dt><dd><a href="' . $url . '" target="debug-tab">' . $url . '</a></dd>';
    $debugInfo .= '</dl></pre>';

    // XML Output
    $dom = new DOMDocument();
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;
    $dom->loadXML($xml->asXML());
    $formattedXml = $dom->saveXML();
    $debugInfo .= '<h4 class="drawer">XML Output</h4><div class="panel"><pre>' . htmlspecialchars($formattedXml) . '</pre></div>';

    $debugInfo .= '</div>';
    // The extra div is to close the debug-output div from the main plugin debug function
    $debugInfo .= '</div>';
    return $debugInfo;
}
