Plugin Directory

Changeset 3443619


Ignore:
Timestamp:
01/20/2026 10:58:30 PM (2 months ago)
Author:
bsolveit
Message:

Version 1.7.0 - Add inline help documentation popovers

Location:
365i-queue-optimizer/trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • 365i-queue-optimizer/trunk/365i-queue-optimizer.php

    r3443609 r3443619  
    44 * Plugin URI: https://www.365i.co.uk/blog/2025/04/20/fix-wordpress-6-8-slow-image-uploads-with-365i-queue-optimizer/
    55 * Description: A lightweight WordPress plugin to optimize ActionScheduler queue processing for faster image optimization and background tasks.
    6  * Version: 1.6.0
     6 * Version: 1.7.0
    77 * Author: 365i
    88 * Author URI: https://www.mcneece.com/author/mark-mcneece/
     
    2222
    2323// Define plugin constants.
    24 define( 'QUEUE_OPTIMIZER_VERSION', '1.6.0' );
     24define( 'QUEUE_OPTIMIZER_VERSION', '1.7.0' );
    2525define( 'QUEUE_OPTIMIZER_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    2626define( 'QUEUE_OPTIMIZER_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
  • 365i-queue-optimizer/trunk/CHANGELOG.md

    r3443609 r3443619  
    22
    33All notable changes to this project will be documented in this file.
     4
     5### [1.7.0] - 2025-01-20
     6
     7#### Added
     8- Inline help popovers with detailed explanations for each setting
     9- Click (?) icon next to fields to learn what they do and see recommended values
     10- Server-specific recommendations and tips in help content
     11- Accessible keyboard navigation and screen reader support
    412
    513### [1.6.0] - 2025-01-20
  • 365i-queue-optimizer/trunk/admin/class-settings-page.php

    r3443609 r3443619  
    362362
    363363    /**
     364     * Render a help trigger button.
     365     *
     366     * @since 1.6.0
     367     * @param string $help_id The help content identifier.
     368     */
     369    private function render_help_trigger( $help_id ) {
     370        ?>
     371        <button type="button"
     372                class="qo-help-trigger"
     373                data-help="<?php echo esc_attr( $help_id ); ?>"
     374                aria-expanded="false"
     375                aria-label="<?php esc_attr_e( 'Help', '365i-queue-optimizer' ); ?>">?</button>
     376        <?php
     377    }
     378
     379    /**
    364380     * Render time limit field.
    365381     */
     
    367383        $value = get_option( 'queue_optimizer_time_limit', 60 );
    368384        ?>
    369         <input type="number"
    370                id="queue_optimizer_time_limit"
    371                name="queue_optimizer_time_limit"
    372                value="<?php echo esc_attr( $value ); ?>"
    373                min="10"
    374                max="300"
    375                step="1"
    376                class="small-text" />
     385        <div class="qo-field-with-help">
     386            <input type="number"
     387                   id="queue_optimizer_time_limit"
     388                   name="queue_optimizer_time_limit"
     389                   value="<?php echo esc_attr( $value ); ?>"
     390                   min="10"
     391                   max="300"
     392                   step="1"
     393                   class="small-text" />
     394            <?php $this->render_help_trigger( 'time_limit' ); ?>
     395        </div>
    377396        <span class="description">
    378             <?php esc_html_e( 'seconds (10-300). Maximum time for queue processing per run.', '365i-queue-optimizer' ); ?>
     397            <?php esc_html_e( 'seconds (10-300)', '365i-queue-optimizer' ); ?>
    379398        </span>
    380399        <?php
     
    387406        $value = get_option( 'queue_optimizer_concurrent_batches', 4 );
    388407        ?>
    389         <input type="number"
    390                id="queue_optimizer_concurrent_batches"
    391                name="queue_optimizer_concurrent_batches"
    392                value="<?php echo esc_attr( $value ); ?>"
    393                min="1"
    394                max="10"
    395                step="1"
    396                class="small-text" />
     408        <div class="qo-field-with-help">
     409            <input type="number"
     410                   id="queue_optimizer_concurrent_batches"
     411                   name="queue_optimizer_concurrent_batches"
     412                   value="<?php echo esc_attr( $value ); ?>"
     413                   min="1"
     414                   max="10"
     415                   step="1"
     416                   class="small-text" />
     417            <?php $this->render_help_trigger( 'concurrent_batches' ); ?>
     418        </div>
    397419        <span class="description">
    398             <?php esc_html_e( 'batches (1-10). Simultaneous processing threads.', '365i-queue-optimizer' ); ?>
     420            <?php esc_html_e( 'batches (1-10)', '365i-queue-optimizer' ); ?>
    399421        </span>
    400422        <?php
     
    409431        $value = get_option( 'queue_optimizer_batch_size', 50 );
    410432        ?>
    411         <input type="number"
    412                id="queue_optimizer_batch_size"
    413                name="queue_optimizer_batch_size"
    414                value="<?php echo esc_attr( $value ); ?>"
    415                min="25"
    416                max="200"
    417                step="5"
    418                class="small-text" />
     433        <div class="qo-field-with-help">
     434            <input type="number"
     435                   id="queue_optimizer_batch_size"
     436                   name="queue_optimizer_batch_size"
     437                   value="<?php echo esc_attr( $value ); ?>"
     438                   min="25"
     439                   max="200"
     440                   step="5"
     441                   class="small-text" />
     442            <?php $this->render_help_trigger( 'batch_size' ); ?>
     443        </div>
    419444        <span class="description">
    420             <?php esc_html_e( 'actions (25-200). Actions claimed per batch.', '365i-queue-optimizer' ); ?>
     445            <?php esc_html_e( 'actions (25-200)', '365i-queue-optimizer' ); ?>
    421446        </span>
    422447        <?php
     
    431456        $value = get_option( 'queue_optimizer_retention_days', 7 );
    432457        ?>
    433         <input type="number"
    434                id="queue_optimizer_retention_days"
    435                name="queue_optimizer_retention_days"
    436                value="<?php echo esc_attr( $value ); ?>"
    437                min="1"
    438                max="30"
    439                step="1"
    440                class="small-text" />
     458        <div class="qo-field-with-help">
     459            <input type="number"
     460                   id="queue_optimizer_retention_days"
     461                   name="queue_optimizer_retention_days"
     462                   value="<?php echo esc_attr( $value ); ?>"
     463                   min="1"
     464                   max="30"
     465                   step="1"
     466                   class="small-text" />
     467            <?php $this->render_help_trigger( 'retention_days' ); ?>
     468        </div>
    441469        <span class="description">
    442             <?php esc_html_e( 'days (1-30). How long to keep completed action logs.', '365i-queue-optimizer' ); ?>
     470            <?php esc_html_e( 'days (1-30)', '365i-queue-optimizer' ); ?>
    443471        </span>
    444472        <?php
     
    453481        $gd_available      = extension_loaded( 'gd' ) && function_exists( 'gd_info' );
    454482        ?>
    455         <select id="queue_optimizer_image_engine" name="queue_optimizer_image_engine">
    456             <option value="WP_Image_Editor_Imagick" <?php selected( $value, 'WP_Image_Editor_Imagick' ); ?>>
    457                 <?php
    458                 if ( $imagick_available ) {
    459                     esc_html_e( 'ImageMagick (Recommended)', '365i-queue-optimizer' );
    460                 } else {
    461                     esc_html_e( 'ImageMagick (Not Available)', '365i-queue-optimizer' );
    462                 }
    463                 ?>
    464             </option>
    465             <option value="WP_Image_Editor_GD" <?php selected( $value, 'WP_Image_Editor_GD' ); ?>>
    466                 <?php
    467                 if ( $gd_available ) {
    468                     esc_html_e( 'GD Library', '365i-queue-optimizer' );
    469                 } else {
    470                     esc_html_e( 'GD Library (Not Available)', '365i-queue-optimizer' );
    471                 }
    472                 ?>
    473             </option>
    474         </select>
     483        <div class="qo-field-with-help">
     484            <select id="queue_optimizer_image_engine" name="queue_optimizer_image_engine">
     485                <option value="WP_Image_Editor_Imagick" <?php selected( $value, 'WP_Image_Editor_Imagick' ); ?>>
     486                    <?php
     487                    if ( $imagick_available ) {
     488                        esc_html_e( 'ImageMagick (Recommended)', '365i-queue-optimizer' );
     489                    } else {
     490                        esc_html_e( 'ImageMagick (Not Available)', '365i-queue-optimizer' );
     491                    }
     492                    ?>
     493                </option>
     494                <option value="WP_Image_Editor_GD" <?php selected( $value, 'WP_Image_Editor_GD' ); ?>>
     495                    <?php
     496                    if ( $gd_available ) {
     497                        esc_html_e( 'GD Library', '365i-queue-optimizer' );
     498                    } else {
     499                        esc_html_e( 'GD Library (Not Available)', '365i-queue-optimizer' );
     500                    }
     501                    ?>
     502                </option>
     503            </select>
     504            <?php $this->render_help_trigger( 'image_engine' ); ?>
     505        </div>
    475506        <?php if ( ! $imagick_available && 'WP_Image_Editor_Imagick' === $value ) : ?>
    476507            <span class="qo-warning">
     
    562593        );
    563594        ?>
    564         <select id="queue_optimizer_server_type_override" name="queue_optimizer_server_type_override">
    565             <?php foreach ( $types as $type_value => $type_label ) : ?>
    566                 <option value="<?php echo esc_attr( $type_value ); ?>" <?php selected( $value, $type_value ); ?>>
    567                     <?php echo esc_html( $type_label ); ?>
    568                 </option>
    569             <?php endforeach; ?>
    570         </select>
     595        <div class="qo-field-with-help">
     596            <select id="queue_optimizer_server_type_override" name="queue_optimizer_server_type_override">
     597                <?php foreach ( $types as $type_value => $type_label ) : ?>
     598                    <option value="<?php echo esc_attr( $type_value ); ?>" <?php selected( $value, $type_value ); ?>>
     599                        <?php echo esc_html( $type_label ); ?>
     600                    </option>
     601                <?php endforeach; ?>
     602            </select>
     603            <?php $this->render_help_trigger( 'server_type' ); ?>
     604        </div>
    571605        <span class="description">
    572             <?php esc_html_e( 'Override auto-detection if recommendations don\'t match your server.', '365i-queue-optimizer' ); ?>
     606            <?php esc_html_e( 'Changing this will auto-apply recommended settings.', '365i-queue-optimizer' ); ?>
    573607        </span>
    574608        <?php
  • 365i-queue-optimizer/trunk/assets/css/admin.css

    r3436746 r3443619  
    409409    }
    410410}
     411
     412/* ==========================================================================
     413   HELP POPOVERS
     414   ========================================================================== */
     415
     416/* Help trigger button */
     417.qo-help-trigger {
     418    display: inline-flex;
     419    align-items: center;
     420    justify-content: center;
     421    width: 18px;
     422    height: 18px;
     423    margin-left: 6px;
     424    padding: 0;
     425    background: transparent;
     426    border: 1.5px solid #8c8f94;
     427    border-radius: 50%;
     428    color: #8c8f94;
     429    font-size: 11px;
     430    font-weight: 600;
     431    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
     432    line-height: 1;
     433    cursor: pointer;
     434    transition: all 0.15s ease;
     435    vertical-align: middle;
     436    position: relative;
     437}
     438
     439.qo-help-trigger:hover,
     440.qo-help-trigger:focus {
     441    background: #2271b1;
     442    border-color: #2271b1;
     443    color: #fff;
     444    outline: none;
     445}
     446
     447.qo-help-trigger:focus {
     448    box-shadow: 0 0 0 2px #fff, 0 0 0 4px #2271b1;
     449}
     450
     451.qo-help-trigger[aria-expanded="true"] {
     452    background: #1d2327;
     453    border-color: #1d2327;
     454    color: #fff;
     455}
     456
     457/* Help popover container */
     458.qo-help-popover {
     459    position: absolute;
     460    z-index: 100000;
     461    width: 320px;
     462    max-width: calc(100vw - 40px);
     463    background: #fff;
     464    border-radius: 6px;
     465    box-shadow:
     466        0 0 0 1px rgba(0, 0, 0, 0.04),
     467        0 4px 8px rgba(0, 0, 0, 0.08),
     468        0 12px 32px rgba(0, 0, 0, 0.12);
     469    opacity: 0;
     470    visibility: hidden;
     471    transform: translateY(-8px);
     472    transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
     473}
     474
     475.qo-help-popover.qo-popover-visible {
     476    opacity: 1;
     477    visibility: visible;
     478    transform: translateY(0);
     479}
     480
     481/* Popover arrow */
     482.qo-help-popover::before {
     483    content: "";
     484    position: absolute;
     485    top: -6px;
     486    left: 24px;
     487    width: 12px;
     488    height: 12px;
     489    background: #fff;
     490    border-top: 1px solid rgba(0, 0, 0, 0.08);
     491    border-left: 1px solid rgba(0, 0, 0, 0.08);
     492    transform: rotate(45deg);
     493    border-radius: 2px 0 0 0;
     494}
     495
     496/* Popover header */
     497.qo-popover-header {
     498    display: flex;
     499    align-items: center;
     500    justify-content: space-between;
     501    padding: 12px 16px;
     502    background: linear-gradient(to bottom, #f8f9fa 0%, #f0f0f1 100%);
     503    border-bottom: 1px solid #e1e1e3;
     504    border-radius: 6px 6px 0 0;
     505}
     506
     507.qo-popover-title {
     508    margin: 0;
     509    font-size: 13px;
     510    font-weight: 600;
     511    color: #1d2327;
     512    line-height: 1.4;
     513}
     514
     515.qo-popover-close {
     516    display: flex;
     517    align-items: center;
     518    justify-content: center;
     519    width: 24px;
     520    height: 24px;
     521    padding: 0;
     522    background: transparent;
     523    border: none;
     524    border-radius: 4px;
     525    color: #646970;
     526    font-size: 18px;
     527    line-height: 1;
     528    cursor: pointer;
     529    transition: all 0.1s ease;
     530}
     531
     532.qo-popover-close:hover {
     533    background: #dcdcde;
     534    color: #1d2327;
     535}
     536
     537.qo-popover-close:focus {
     538    outline: none;
     539    box-shadow: 0 0 0 2px #2271b1;
     540}
     541
     542/* Popover content */
     543.qo-popover-content {
     544    padding: 16px;
     545}
     546
     547.qo-popover-content p {
     548    margin: 0 0 12px 0;
     549    font-size: 13px;
     550    line-height: 1.6;
     551    color: #3c434a;
     552}
     553
     554.qo-popover-content p:last-child {
     555    margin-bottom: 0;
     556}
     557
     558.qo-popover-content strong {
     559    color: #1d2327;
     560}
     561
     562.qo-popover-content code {
     563    background: #f0f0f1;
     564    padding: 2px 6px;
     565    border-radius: 3px;
     566    font-size: 12px;
     567    color: #1d2327;
     568}
     569
     570/* Recommended values list */
     571.qo-popover-recommendations {
     572    margin: 12px 0 0 0;
     573    padding: 12px;
     574    background: #f8f9fa;
     575    border-radius: 4px;
     576    border-left: 3px solid #2271b1;
     577}
     578
     579.qo-popover-recommendations strong {
     580    display: block;
     581    font-size: 11px;
     582    text-transform: uppercase;
     583    letter-spacing: 0.5px;
     584    color: #646970;
     585    margin-bottom: 8px;
     586}
     587
     588.qo-popover-recommendations ul {
     589    margin: 0;
     590    padding: 0;
     591    list-style: none;
     592}
     593
     594.qo-popover-recommendations li {
     595    display: flex;
     596    justify-content: space-between;
     597    padding: 3px 0;
     598    font-size: 12px;
     599    color: #3c434a;
     600}
     601
     602.qo-popover-recommendations li span:last-child {
     603    font-weight: 600;
     604    color: #1d2327;
     605}
     606
     607/* Tips/notes styling */
     608.qo-popover-tip {
     609    margin-top: 12px;
     610    padding: 10px 12px;
     611    background: #fff8e5;
     612    border-radius: 4px;
     613    font-size: 12px;
     614    color: #996800;
     615}
     616
     617.qo-popover-tip::before {
     618    content: "💡";
     619    margin-right: 6px;
     620}
     621
     622/* Mobile responsive */
     623@media screen and (max-width: 782px) {
     624    .qo-help-popover {
     625        position: fixed;
     626        left: 10px !important;
     627        right: 10px !important;
     628        top: auto !important;
     629        bottom: 20px !important;
     630        width: auto;
     631        max-width: none;
     632        transform: translateY(20px);
     633    }
     634
     635    .qo-help-popover.qo-popover-visible {
     636        transform: translateY(0);
     637    }
     638
     639    .qo-help-popover::before {
     640        display: none;
     641    }
     642
     643    .qo-popover-content {
     644        max-height: 50vh;
     645        overflow-y: auto;
     646    }
     647}
     648
     649/* Field wrapper for positioning */
     650.qo-field-with-help {
     651    position: relative;
     652    display: inline-flex;
     653    align-items: center;
     654}
  • 365i-queue-optimizer/trunk/assets/js/admin.js

    r3443609 r3443619  
    1717        initApplyRecommended();
    1818        initRunQueue();
    19         initHelpText();
     19        initHelpPopovers();
    2020        initSaveNotification();
    2121    }
     
    203203
    204204    /**
    205      * Initialize help text interactions
    206      */
    207     function initHelpText() {
    208         $('.description').each(function() {
    209             $(this).attr('title', $(this).text().trim());
    210         });
     205     * Initialize help popovers
     206     */
     207    function initHelpPopovers() {
     208        var $activePopover = null;
     209
     210        // Close popover function
     211        function closePopover() {
     212            if ($activePopover) {
     213                $activePopover.removeClass('qo-popover-visible');
     214                $activePopover.prev('.qo-help-trigger').attr('aria-expanded', 'false');
     215                setTimeout(function() {
     216                    $activePopover.remove();
     217                    $activePopover = null;
     218                }, 200);
     219            }
     220        }
     221
     222        // Handle help trigger clicks
     223        $(document).on('click', '.qo-help-trigger', function(e) {
     224            e.preventDefault();
     225            e.stopPropagation();
     226
     227            var $trigger = $(this);
     228            var helpId = $trigger.data('help');
     229
     230            // If clicking same trigger, close it
     231            if ($activePopover && $trigger.attr('aria-expanded') === 'true') {
     232                closePopover();
     233                return;
     234            }
     235
     236            // Close any existing popover
     237            closePopover();
     238
     239            // Get help content
     240            var helpContent = getHelpContent(helpId);
     241            if (!helpContent) {
     242                return;
     243            }
     244
     245            // Create popover
     246            var $popover = $(
     247                '<div class="qo-help-popover" role="dialog" aria-modal="true">' +
     248                    '<div class="qo-popover-header">' +
     249                        '<h4 class="qo-popover-title">' + helpContent.title + '</h4>' +
     250                        '<button type="button" class="qo-popover-close" aria-label="Close">&times;</button>' +
     251                    '</div>' +
     252                    '<div class="qo-popover-content">' + helpContent.content + '</div>' +
     253                '</div>'
     254            );
     255
     256            // Position popover
     257            $trigger.after($popover);
     258            $trigger.attr('aria-expanded', 'true');
     259
     260            // Calculate position
     261            var triggerOffset = $trigger.offset();
     262            var triggerHeight = $trigger.outerHeight();
     263
     264            $popover.css({
     265                position: 'absolute',
     266                top: triggerHeight + 8,
     267                left: 0
     268            });
     269
     270            // Show with animation
     271            setTimeout(function() {
     272                $popover.addClass('qo-popover-visible');
     273            }, 10);
     274
     275            $activePopover = $popover;
     276
     277            // Focus close button for accessibility
     278            $popover.find('.qo-popover-close').focus();
     279        });
     280
     281        // Close button click
     282        $(document).on('click', '.qo-popover-close', function(e) {
     283            e.preventDefault();
     284            closePopover();
     285        });
     286
     287        // Close on outside click
     288        $(document).on('click', function(e) {
     289            if ($activePopover && !$(e.target).closest('.qo-help-popover, .qo-help-trigger').length) {
     290                closePopover();
     291            }
     292        });
     293
     294        // Close on Escape key
     295        $(document).on('keydown', function(e) {
     296            if (e.key === 'Escape' && $activePopover) {
     297                closePopover();
     298            }
     299        });
     300    }
     301
     302    /**
     303     * Get help content for a specific field
     304     */
     305    function getHelpContent(helpId) {
     306        var helpData = {
     307            'time_limit': {
     308                title: 'Time Limit',
     309                content: '<p>Controls how long ActionScheduler is allowed to process tasks in a single run before stopping.</p>' +
     310                    '<p><strong>Higher values</strong> = more tasks processed per run, but longer server load.</p>' +
     311                    '<p><strong>Lower values</strong> = shorter processing bursts, better for shared hosting.</p>' +
     312                    '<div class="qo-popover-recommendations">' +
     313                        '<strong>Recommended by Server Type</strong>' +
     314                        '<ul>' +
     315                            '<li><span>Shared Hosting</span><span>30 seconds</span></li>' +
     316                            '<li><span>VPS / Managed</span><span>45 seconds</span></li>' +
     317                            '<li><span>Dedicated</span><span>60 seconds</span></li>' +
     318                        '</ul>' +
     319                    '</div>'
     320            },
     321            'concurrent_batches': {
     322                title: 'Concurrent Batches',
     323                content: '<p>The number of simultaneous queue runners that can process actions at the same time.</p>' +
     324                    '<p><strong>Higher values</strong> = faster processing but more server resources used.</p>' +
     325                    '<p><strong>Lower values</strong> = slower processing but gentler on the server.</p>' +
     326                    '<div class="qo-popover-recommendations">' +
     327                        '<strong>Recommended by Server Type</strong>' +
     328                        '<ul>' +
     329                            '<li><span>Shared Hosting</span><span>1 batch</span></li>' +
     330                            '<li><span>VPS / Managed</span><span>2 batches</span></li>' +
     331                            '<li><span>Dedicated</span><span>4 batches</span></li>' +
     332                        '</ul>' +
     333                    '</div>' +
     334                    '<div class="qo-popover-tip">Start low and increase gradually while monitoring server performance.</div>'
     335            },
     336            'batch_size': {
     337                title: 'Batch Size',
     338                content: '<p>The maximum number of actions that can be claimed and processed in each batch.</p>' +
     339                    '<p><strong>Higher values</strong> = more actions processed per batch, faster overall.</p>' +
     340                    '<p><strong>Lower values</strong> = smaller batches, reduces memory usage and timeout risk.</p>' +
     341                    '<div class="qo-popover-recommendations">' +
     342                        '<strong>Recommended by Server Type</strong>' +
     343                        '<ul>' +
     344                            '<li><span>Shared Hosting</span><span>25 actions</span></li>' +
     345                            '<li><span>VPS / Managed</span><span>35 actions</span></li>' +
     346                            '<li><span>Dedicated</span><span>50 actions</span></li>' +
     347                        '</ul>' +
     348                    '</div>'
     349            },
     350            'retention_days': {
     351                title: 'Data Retention',
     352                content: '<p>How many days to keep completed action logs in the database before they are automatically deleted.</p>' +
     353                    '<p><strong>Higher values</strong> = longer history for debugging, but larger database.</p>' +
     354                    '<p><strong>Lower values</strong> = smaller database, faster queries.</p>' +
     355                    '<div class="qo-popover-recommendations">' +
     356                        '<strong>Recommended by Server Type</strong>' +
     357                        '<ul>' +
     358                            '<li><span>Shared Hosting</span><span>3 days</span></li>' +
     359                            '<li><span>VPS / Managed</span><span>5 days</span></li>' +
     360                            '<li><span>Dedicated</span><span>7 days</span></li>' +
     361                        '</ul>' +
     362                    '</div>' +
     363                    '<div class="qo-popover-tip">Shorter retention keeps your database lean and improves performance.</div>'
     364            },
     365            'image_engine': {
     366                title: 'Image Processing Engine',
     367                content: '<p>Choose which PHP image library WordPress should prioritize for image processing.</p>' +
     368                    '<p><strong>ImageMagick</strong> (Recommended)</p>' +
     369                    '<ul style="margin: 8px 0 8px 20px; font-size: 12px;">' +
     370                        '<li>Better quality for resizing and compression</li>' +
     371                        '<li>More memory efficient for large images</li>' +
     372                        '<li>Better color profile handling</li>' +
     373                        '<li>Supports more image formats</li>' +
     374                    '</ul>' +
     375                    '<p><strong>GD Library</strong></p>' +
     376                    '<ul style="margin: 8px 0 8px 20px; font-size: 12px;">' +
     377                        '<li>More widely available on shared hosting</li>' +
     378                        '<li>Simpler, fewer dependencies</li>' +
     379                        '<li>May be faster for simple operations</li>' +
     380                    '</ul>' +
     381                    '<div class="qo-popover-tip">If ImageMagick is available, use it. Only switch to GD if you experience issues.</div>'
     382            },
     383            'server_type': {
     384                title: 'Server Type',
     385                content: '<p>Select your hosting environment to get appropriate recommended settings.</p>' +
     386                    '<p><strong>Auto-detect</strong> analyzes your PHP memory limit and execution time to guess your server type.</p>' +
     387                    '<p><strong>Shared Hosting</strong> - Budget hosting with limited resources (e.g., Bluehost, SiteGround shared plans)</p>' +
     388                    '<p><strong>VPS / Managed</strong> - Virtual private server or managed WordPress hosting (e.g., Cloudways, Kinsta)</p>' +
     389                    '<p><strong>Dedicated</strong> - High-performance dedicated server or enterprise hosting</p>' +
     390                    '<div class="qo-popover-tip">If auto-detect gets it wrong, manually select your actual hosting type for better recommendations.</div>'
     391            }
     392        };
     393
     394        return helpData[helpId] || null;
    211395    }
    212396
  • 365i-queue-optimizer/trunk/readme.txt

    r3443609 r3443619  
    44Requires at least: 5.8
    55Tested up to: 6.9
    6 Stable tag: 1.6.0
     6Stable tag: 1.7.0
    77Requires PHP: 8.0
    88License: GPLv2 or later
     
    191191
    192192== Changelog ==
     193
     194= 1.7.0 - 2025-01-20 =
     195
     196**Inline Help Documentation**
     197
     198* Added help popovers with detailed explanations for each setting
     199* Click the (?) icon next to any field to see what it does and recommended values
     200* Help content includes server-specific recommendations and tips
     201* Fully accessible with keyboard navigation and screen reader support
     202* Mobile-friendly design that works on all screen sizes
    193203
    194204= 1.6.0 - 2025-01-20 =
Note: See TracChangeset for help on using the changeset viewer.