Plugin Directory

Changeset 3453804


Ignore:
Timestamp:
02/04/2026 12:59:39 PM (8 weeks ago)
Author:
3task
Message:

v2.2.0

Location:
3task-glossary/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • 3task-glossary/trunk/3task-glossary.php

    r3447608 r3453804  
    44 * Plugin URI: https://wordpress.org/plugins/3task-glossary/
    55 * Description: Create glossaries, dictionaries & knowledge bases using WordPress pages. A-Z navigation, auto-linking, dark mode. No database, just pages.
    6  * Version: 2.1.0
     6 * Version: 2.2.0
    77 * Requires at least: 5.8
    88 * Requires PHP: 7.4
     
    1515 *
    1616 * @package 3Task_Glossary
    17  * @version 2.1.0
     17 * @version 2.2.0
    1818 */
    1919
     
    2323}
    2424
    25 // Plugin constants.
    26 define( 'AZGL_VERSION', '2.1.0' );
    27 define( 'AZGL_PLUGIN_FILE', __FILE__ );
    28 define( 'AZGL_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    29 define( 'AZGL_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
    30 define( 'AZGL_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
    31 
    32 // Limits for Lite version.
    33 // Removed limits for WordPress.org compliance - fully functional lite version
    34 define( 'AZGL_MAX_GLOSSARIES', 999 ); // No functional limits
    35 define( 'AZGL_MAX_ENTRIES', 999999 ); // No functional limits
    36 define( 'AZGL_SUPPORTER_MAX_GLOSSARIES', 999 );
    37 define( 'AZGL_SUPPORTER_MAX_ENTRIES', 999999 );
     25// Prevent conflict with old simple-seo-glossary plugin.
     26// Check for the specific old plugin file, not just the class name.
     27if ( defined( 'AZGL_PLUGIN_FILE' ) && strpos( AZGL_PLUGIN_FILE, '3task-glossary' ) === false ) {
     28    add_action( 'admin_notices', function() {
     29        echo '<div class="notice notice-error"><p><strong>3task Glossary:</strong> ';
     30        echo esc_html__( 'Please deactivate the old "Simple SEO Glossary" plugin. Both plugins cannot run simultaneously.', '3task-glossary' );
     31        echo '</p></div>';
     32    } );
     33    return;
     34}
     35
     36// Plugin constants (with defined checks for safety).
     37if ( ! defined( 'AZGL_VERSION' ) ) {
     38    define( 'AZGL_VERSION', '2.2.0' );
     39}
     40if ( ! defined( 'AZGL_PLUGIN_FILE' ) ) {
     41    define( 'AZGL_PLUGIN_FILE', __FILE__ );
     42}
     43if ( ! defined( 'AZGL_PLUGIN_DIR' ) ) {
     44    define( 'AZGL_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
     45}
     46if ( ! defined( 'AZGL_PLUGIN_URL' ) ) {
     47    define( 'AZGL_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
     48}
     49if ( ! defined( 'AZGL_PLUGIN_BASENAME' ) ) {
     50    define( 'AZGL_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
     51}
     52
     53// Limits for Lite version (no functional limits for WordPress.org compliance).
     54if ( ! defined( 'AZGL_MAX_GLOSSARIES' ) ) {
     55    define( 'AZGL_MAX_GLOSSARIES', 999 );
     56}
     57if ( ! defined( 'AZGL_MAX_ENTRIES' ) ) {
     58    define( 'AZGL_MAX_ENTRIES', 999999 );
     59}
     60if ( ! defined( 'AZGL_SUPPORTER_MAX_GLOSSARIES' ) ) {
     61    define( 'AZGL_SUPPORTER_MAX_GLOSSARIES', 999 );
     62}
     63if ( ! defined( 'AZGL_SUPPORTER_MAX_ENTRIES' ) ) {
     64    define( 'AZGL_SUPPORTER_MAX_ENTRIES', 999999 );
     65}
    3866
    3967/**
     
    365393 * @return AZ_Glossary_Lite
    366394 */
    367 function azgl() {
    368     return AZ_Glossary_Lite::get_instance();
     395if ( ! function_exists( 'azgl' ) ) {
     396    function azgl() {
     397        return AZ_Glossary_Lite::get_instance();
     398    }
    369399}
    370400
  • 3task-glossary/trunk/includes/class-admin.php

    r3447608 r3453804  
    258258        $settings = array(
    259259            'nav_style'        => isset( $_POST['nav_style'] ) ? sanitize_key( wp_unslash( $_POST['nav_style'] ) ) : 'buttons',
    260             'inactive_letters' => isset( $_POST['inactive_letters'] ),
     260            'inactive_letters' => isset( $_POST['inactive_letters'] ) ? sanitize_key( wp_unslash( $_POST['inactive_letters'] ) ) : 'accessible',
    261261            'color_scheme'     => isset( $_POST['color_scheme'] ) ? sanitize_key( wp_unslash( $_POST['color_scheme'] ) ) : 'emerald',
    262262            'dark_mode'        => isset( $_POST['dark_mode'] ) ? sanitize_key( wp_unslash( $_POST['dark_mode'] ) ) : 'auto',
     
    268268        if ( ! in_array( $settings['nav_style'], $valid_styles, true ) ) {
    269269            $settings['nav_style'] = 'buttons';
     270        }
     271
     272        // Validate inactive_letters.
     273        $valid_inactive = array_keys( $this->options->get_inactive_letter_modes() );
     274        if ( ! in_array( $settings['inactive_letters'], $valid_inactive, true ) ) {
     275            $settings['inactive_letters'] = 'accessible';
    270276        }
    271277
     
    718724    private function render_design_tab() {
    719725        $nav_style        = $this->options->get( 'nav_style', 'buttons' );
    720         $inactive_letters = $this->options->get( 'inactive_letters', true );
     726        $inactive_letters = $this->options->get( 'inactive_letters', 'accessible' );
    721727        $color_scheme     = $this->options->get( 'color_scheme', 'emerald' );
    722728        $dark_mode        = $this->options->get( 'dark_mode', 'auto' );
    723729
    724         $nav_styles    = $this->options->get_nav_styles();
    725         $color_schemes = $this->options->get_color_schemes();
    726         $dark_modes    = $this->options->get_dark_mode_options();
     730        // Migrate old boolean value to new string format.
     731        if ( true === $inactive_letters || '1' === $inactive_letters ) {
     732            $inactive_letters = 'show';
     733        } elseif ( false === $inactive_letters || '' === $inactive_letters ) {
     734            $inactive_letters = 'none';
     735        }
     736
     737        $nav_styles     = $this->options->get_nav_styles();
     738        $inactive_modes = $this->options->get_inactive_letter_modes();
     739        $color_schemes  = $this->options->get_color_schemes();
     740        $dark_modes     = $this->options->get_dark_mode_options();
    727741        ?>
    728742        <div class="azgl-card">
     
    753767                    <tr>
    754768                        <th scope="row">
    755                             <?php esc_html_e( 'Inactive Letters', '3task-glossary' ); ?>
     769                            <label for="inactive_letters"><?php esc_html_e( 'Inactive Letters', '3task-glossary' ); ?></label>
    756770                        </th>
    757771                        <td>
    758                             <label>
    759                                 <input type="checkbox" name="inactive_letters" value="1" <?php checked( $inactive_letters ); ?>>
    760                                 <?php esc_html_e( 'Show letters without entries (greyed out)', '3task-glossary' ); ?>
    761                             </label>
     772                            <select name="inactive_letters" id="inactive_letters">
     773                                <?php foreach ( $inactive_modes as $value => $mode ) : ?>
     774                                    <option value="<?php echo esc_attr( $value ); ?>" <?php selected( $inactive_letters, $value ); ?>>
     775                                        <?php echo esc_html( $mode['label'] ); ?>
     776                                    </option>
     777                                <?php endforeach; ?>
     778                            </select>
     779                            <p class="description">
     780                                <?php
     781                                $current_mode = isset( $inactive_modes[ $inactive_letters ] ) ? $inactive_modes[ $inactive_letters ] : $inactive_modes['accessible'];
     782                                echo esc_html( $current_mode['description'] );
     783                                ?>
     784                            </p>
     785                            <p class="description" style="margin-top:8px;color:#666;">
     786                                <span class="dashicons dashicons-universal-access" style="font-size:14px;"></span>
     787                                <?php esc_html_e( 'Accessibility: "Accessible" mode is recommended for screen reader compatibility.', '3task-glossary' ); ?>
     788                            </p>
    762789                        </td>
    763790                    </tr>
  • 3task-glossary/trunk/includes/class-frontend.php

    r3447608 r3453804  
    137137        $alphabetic_list = $this->get_alphabetic_list( $entries );
    138138        $nav_style       = $this->options->get( 'nav_style', 'buttons' );
    139         $show_inactive   = $this->options->get( 'inactive_letters', true );
     139        $inactive_mode   = $this->options->get( 'inactive_letters', 'accessible' );
    140140        $color_scheme    = $this->options->get( 'color_scheme', 'emerald' );
     141
     142        // Migrate old boolean values.
     143        if ( true === $inactive_mode || '1' === $inactive_mode ) {
     144            $inactive_mode = 'show';
     145        } elseif ( false === $inactive_mode || '' === $inactive_mode ) {
     146            $inactive_mode = 'none';
     147        }
    141148
    142149        $output = '';
     
    144151        // A-Z Navigation.
    145152        if ( ! empty( $glossary['navigation'] ) ) {
    146             $output .= $this->render_navigation( $alphabetic_list, $nav_style, $color_scheme, $show_inactive );
     153            $output .= $this->render_navigation( $alphabetic_list, $nav_style, $color_scheme, $inactive_mode );
    147154        }
    148155
     
    207214     * @param string $nav_style       Navigation style.
    208215     * @param string $color_scheme    Color scheme.
    209      * @param bool   $show_inactive   Show inactive letters.
     216     * @param string $inactive_mode   Inactive letters display mode (accessible, hidden, show, none).
    210217     * @return string HTML.
    211218     */
    212     private function render_navigation( $alphabetic_list, $nav_style, $color_scheme, $show_inactive ) {
     219    private function render_navigation( $alphabetic_list, $nav_style, $color_scheme, $inactive_mode ) {
    213220        $output  = '<nav class="azgl-nav azgl-nav-' . esc_attr( $nav_style ) . ' azgl-scheme-' . esc_attr( $color_scheme ) . '" ';
    214221        $output .= 'role="navigation" aria-label="' . esc_attr__( 'Alphabetical navigation', '3task-glossary' ) . '">';
     
    216223        foreach ( $alphabetic_list as $letter => $entries ) {
    217224            if ( ! empty( $entries ) ) {
     225                // Active letter - always a link.
    218226                $output .= '<a href="#azgl-' . esc_attr( strtolower( $letter ) ) . '" class="azgl-nav-letter">';
    219227                $output .= esc_html( $letter );
    220228                $output .= '</a>';
    221             } elseif ( $show_inactive ) {
    222                 $output .= '<span class="azgl-nav-letter azgl-nav-inactive">' . esc_html( $letter ) . '</span>';
     229            } else {
     230                // Inactive letter - render based on accessibility mode.
     231                $output .= $this->render_inactive_letter( $letter, $inactive_mode );
    223232            }
    224233        }
     
    227236
    228237        return $output;
     238    }
     239
     240    /**
     241     * Render an inactive letter based on accessibility mode.
     242     *
     243     * @param string $letter        The letter to render.
     244     * @param string $inactive_mode Display mode (accessible, hidden, show, none).
     245     * @return string HTML.
     246     */
     247    private function render_inactive_letter( $letter, $inactive_mode ) {
     248        switch ( $inactive_mode ) {
     249            case 'accessible':
     250                // Screen reader announces "X, no entries" - best for accessibility.
     251                return '<span class="azgl-nav-letter azgl-nav-inactive" aria-label="' .
     252                    /* translators: %s: Letter that has no glossary entries */
     253                    esc_attr( sprintf( __( '%s, no entries', '3task-glossary' ), $letter ) ) .
     254                    '" role="text">' . esc_html( $letter ) . '</span>';
     255
     256            case 'hidden':
     257                // Visible but hidden from screen readers.
     258                return '<span class="azgl-nav-letter azgl-nav-inactive" aria-hidden="true">' .
     259                    esc_html( $letter ) . '</span>';
     260
     261            case 'show':
     262                // Legacy mode - visual only, may cause accessibility issues.
     263                return '<span class="azgl-nav-letter azgl-nav-inactive">' .
     264                    esc_html( $letter ) . '</span>';
     265
     266            case 'none':
     267            default:
     268                // Don't render inactive letters at all.
     269                return '';
     270        }
    229271    }
    230272
  • 3task-glossary/trunk/includes/class-options.php

    r3447608 r3453804  
    5151        // Display settings.
    5252        'nav_style'        => 'buttons', // buttons, pills, minimal.
    53         'inactive_letters' => true,
     53        'inactive_letters' => 'accessible', // show, accessible, hidden, none.
    5454        'color_scheme'     => 'emerald', // emerald, ocean, sunset, berry, slate, auto.
    5555        'dark_mode'        => 'auto', // auto, light, dark.
     
    367367
    368368    /**
     369     * Get available inactive letter display modes.
     370     *
     371     * Accessibility options for how to handle letters without entries.
     372     *
     373     * @return array Inactive letter modes with labels and descriptions.
     374     */
     375    public function get_inactive_letter_modes() {
     376        return array(
     377            'accessible' => array(
     378                'label'       => __( 'Accessible (Recommended)', '3task-glossary' ),
     379                'description' => __( 'Screen readers announce "X, no entries"', '3task-glossary' ),
     380            ),
     381            'hidden'     => array(
     382                'label'       => __( 'Hidden for Screen Readers', '3task-glossary' ),
     383                'description' => __( 'Visible but ignored by screen readers', '3task-glossary' ),
     384            ),
     385            'show'       => array(
     386                'label'       => __( 'Show (Visual Only)', '3task-glossary' ),
     387                'description' => __( 'May cause accessibility issues', '3task-glossary' ),
     388            ),
     389            'none'       => array(
     390                'label'       => __( 'Hide Completely', '3task-glossary' ),
     391                'description' => __( 'Only show letters with entries', '3task-glossary' ),
     392            ),
     393        );
     394    }
     395
     396    /**
    369397     * Get available linking modes.
    370398     *
  • 3task-glossary/trunk/readme.txt

    r3447608 r3453804  
    44Requires at least: 5.8
    55Tested up to: 6.9
    6 Stable tag: 2.1.0
     6Stable tag: 2.2.0
    77Requires PHP: 7.4
    88License: GPLv2 or later
     
    128128
    129129== Changelog ==
     130
     131= 2.2.0 =
     132* New: Accessibility options for inactive letters (screen reader support)
     133* New: Four display modes for letters without entries: Accessible (with aria-label), Hidden (aria-hidden), Show (visual only), None (hide completely)
     134* Improved: Screen readers now properly announce "X, no entries" instead of reading letters as one string
     135* Thanks to Elena Brescacin for reporting the accessibility issue and contributing the Italian translation
    130136
    131137= 2.1.0 =
     
    151157== Upgrade Notice ==
    152158
     159= 2.2.0 =
     160Accessibility improvement: Inactive letters now work properly with screen readers. Choose from 4 display modes in Design settings.
     161
    153162= 2.1.0 =
    154163Plugin renamed to 3task Glossary. Now optimized for glossaries, dictionaries, wikis and knowledge bases.
Note: See TracChangeset for help on using the changeset viewer.