__( 'Display A-Z glossary navigation in your sidebar.', '3task-glossary' ), 'customize_selective_refresh' => true, ) ); } /** * Output the widget content. * * @param array $args Widget arguments. * @param array $instance Widget instance settings. */ public function widget( $args, $instance ) { $title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Glossary', '3task-glossary' ); $glossary_id = ! empty( $instance['glossary_id'] ) ? absint( $instance['glossary_id'] ) : 0; $show_count = ! empty( $instance['show_count'] ); $display = ! empty( $instance['display'] ) ? $instance['display'] : 'az'; // Get glossary. if ( 0 === $glossary_id ) { // Use first active glossary. $options = azgl()->get_options(); $glossaries = $options->get( 'glossaries', array() ); foreach ( $glossaries as $glossary ) { if ( ! empty( $glossary['active'] ) ) { $glossary_id = absint( $glossary['page_id'] ); break; } } } if ( 0 === $glossary_id ) { return; // No glossary found. } $entries = azgl()->get_glossary_entries( $glossary_id ); if ( empty( $entries ) ) { return; // No entries. } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget args are escaped by theme. echo $args['before_widget']; if ( $title ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget args are escaped by theme. echo $args['before_title'] . esc_html( apply_filters( 'widget_title', $title ) ) . $args['after_title']; } echo '
'; if ( 'az' === $display ) { $this->render_az_navigation( $entries, $glossary_id ); } elseif ( 'recent' === $display ) { $this->render_recent_terms( $entries, $show_count ? 10 : 5 ); } elseif ( 'popular' === $display ) { $this->render_popular_terms( $glossary_id, $show_count ? 10 : 5 ); } echo '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Widget args are escaped by theme. echo $args['after_widget']; } /** * Render A-Z navigation. * * @param array $entries Glossary entries. * @param int $glossary_id Glossary page ID. */ private function render_az_navigation( $entries, $glossary_id ) { $letters = array(); foreach ( $entries as $entry ) { $first_letter = $this->get_first_letter( $entry->post_title ); if ( ! isset( $letters[ $first_letter ] ) ) { $letters[ $first_letter ] = 0; } ++$letters[ $first_letter ]; } ksort( $letters ); $glossary_url = get_permalink( $glossary_id ); echo '
'; foreach ( range( 'A', 'Z' ) as $letter ) { $count = isset( $letters[ $letter ] ) ? $letters[ $letter ] : 0; $url = $glossary_url . '#azgl-' . strtolower( $letter ); if ( $count > 0 ) { echo ''; echo esc_html( $letter ); echo ''; } else { echo '' . esc_html( $letter ) . ''; } } echo '
'; echo ''; } /** * Render recent terms. * * @param array $entries Glossary entries. * @param int $limit Number of terms to show. */ private function render_recent_terms( $entries, $limit = 5 ) { // Sort by date (newest first) - entries are already sorted by title. usort( $entries, function ( $a, $b ) { return strtotime( $b->post_date ) - strtotime( $a->post_date ); } ); $entries = array_slice( $entries, 0, $limit ); echo ''; } /** * Render popular terms (most viewed - placeholder, uses alphabetical for now). * * @param int $glossary_id Glossary page ID. * @param int $limit Number of terms to show. */ private function render_popular_terms( $glossary_id, $limit = 5 ) { $entries = azgl()->get_glossary_entries( $glossary_id ); $entries = array_slice( $entries, 0, $limit ); echo ''; } /** * Get first letter of a string, handling umlauts. * * @param string $str Input string. * @return string First letter (uppercase). */ private function get_first_letter( $str ) { $str = trim( $str ); $first = mb_strtoupper( mb_substr( $str, 0, 1, 'UTF-8' ), 'UTF-8' ); // Map umlauts to base letters. $umlaut_map = array( 'Ä' => 'A', 'Ö' => 'O', 'Ü' => 'U', 'ß' => 'S', ); return isset( $umlaut_map[ $first ] ) ? $umlaut_map[ $first ] : $first; } /** * Output the widget settings form. * * @param array $instance Current widget settings. * @return void */ public function form( $instance ) { $title = ! empty( $instance['title'] ) ? $instance['title'] : __( 'Glossary', '3task-glossary' ); $glossary_id = ! empty( $instance['glossary_id'] ) ? absint( $instance['glossary_id'] ) : 0; $display = ! empty( $instance['display'] ) ? $instance['display'] : 'az'; $options = azgl()->get_options(); $glossaries = $options->get( 'glossaries', array() ); ?>