• Abdur

    (@archoudhury)


    Hello WordPress Glossary users,

    I’ve found a solution to enable tooltips for every occurrence of each glossary term, rather than just the first instance. This modification allows the plugin to show tooltips unlimited times for each term on a page.

    Here’s how to implement this change:

    1. Go to your WordPress admin panel and navigate to Plugins > Plugin File Editor.
    2. Select the www.remarpro.com Glossary plugin from the dropdown menu.
    3. Open the file includes/class-glossary_handler.php.
    4. Replace the entire content of the file with the following code:
    <?php
    /**
    * Handler for creating links to the glossary on the frontend.
    */
    class Glossary_Handler {
    private $glossary;
    private $processed;
    private $content;

    public function __construct() {
    $this->glossary = new Glossary();

    // Hooks
    // 20 to run after do_shortcode (12) and O2 filters (15)
    add_filter( 'the_content', array( $this, 'glossary_links' ), 20 );
    add_filter( 'comment_text', array( $this, 'glossary_links' ) );
    }

    /**
    * Create the link for the glossary item for the frontend.
    *
    * @param array $matches The matches coming from the regular expression.
    * @return string HTML fragment representing this glossary term.
    */
    public function glossary_item_hovercard( $matches ) {
    $found_text = $matches[1];

    $glossary_item = $this->glossary->get_active_item( $found_text );
    if ( ! $glossary_item ) {
    return $matches[0];
    }

    // These lines are commented out to allow multiple tooltips
    // if ( ! empty( $this->processed[ strtolower( $found_text ) ] ) ) {
    // return $matches[0];
    // }
    // $this->processed[ strtolower( $found_text ) ] = true;

    // TinyMCE wraps everything in p tags on save, so let's replace them with line breaks
    $desc_html = preg_replace( '/<p>/', '', $glossary_item->description );
    $desc_html = preg_replace( '/<\/p>/', '<br />', $desc_html );
    $desc_html = preg_replace( "/\n/", '<br />', $desc_html );
    $desc_html = preg_replace( '/(<br \/>)+/', '<br />', $desc_html );
    global $allowedtags;
    $desc_html = wp_kses( $desc_html, $allowedtags );

    // Add edit link.
    is_multisite() && switch_to_blog( $glossary_item->site );
    if ( current_user_can( 'edit_post', $glossary_item->id ) ) {
    $desc_html .= '<br><a href="' . get_edit_post_link( $glossary_item->id ) . '">' . _x( 'Edit Entry', 'wporg-glossary' ) . '</a>';
    }
    is_multisite() && restore_current_blog();

    $term_html = "<span class='glossary-item-header'>" . esc_html( $glossary_item->name ) . "</span> <span class='glossary-item-description'>$desc_html</span>";

    $replacement = sprintf(
    // NOTE: When altering this HTML, please update the relevant code in Glossary_Handler::glossary_links()
    "<span tabindex='0' class='glossary-item-container'>%s<span class='glossary-item-hidden-content'>%s</span></span>",
    esc_html( $found_text ),
    $term_html
    );

    return $replacement;
    }

    /**
    * Parses and links glossary item within a string. Run on the_content.
    *
    * @param string $content The content.
    * @return string The linked content.
    */
    public function glossary_links( $content ) {
    if ( is_feed() || is_embed() || ( is_admin() && ! ( isset( $_GET['action'] ) && 'o2_read' === $_GET['action'] ) ) ) {
    return $content;
    }

    $regex = $this->glossary->get_item_names_regex();
    if ( ! $regex ) {
    return $content;
    }

    // Used for creating a unique ID to keep track of replacements in a single post/comment
    $this->content = $content;
    $this->processed = array();
    $textarr = wp_html_split( $content );

    $ignore_elements = array( 'code', '/code', 'a', '/a', 'pre', '/pre', 'dt', '/dt', 'option', '/option' );
    $inside_block = array();
    foreach ( $textarr as &$element ) {
    if ( 0 === strpos( $element, '<' ) ) {
    $offset = 1;
    $is_end_tag = false;

    if ( 1 === strpos( $element, '/' ) ) {
    $offset = 2;
    $is_end_tag = true;
    }

    preg_match( '/^.+(\b|\n|$)/U', substr( $element, $offset ), $matches );
    if ( $matches && in_array( $matches[0], $ignore_elements, true ) ) {
    if ( ! $is_end_tag ) {
    array_unshift( $inside_block, $matches[0] );
    } elseif ( $inside_block && $matches[0] === $inside_block[0] ) {
    array_shift( $inside_block );
    }

    continue;
    }

    // Skip the Glossary item container span, for when the_content is run over the_content.
    if ( $matches && 'span' == $matches[0] && false !== strpos( $element, "class='glossary-item-container'" ) ) {
    if ( ! $is_end_tag ) {
    array_unshift( $inside_block, $matches[0] );
    } elseif ( $inside_block && $matches[0] === $inside_block[0] ) {
    array_shift( $inside_block );
    }

    continue;
    }
    }

    // Skip any links that will be auto-generated by make_clickable()
    // three strpos() are faster than one preg_match() here. If we need to check for more protocols, preg_match() would probably be better
    if ( strpos( $element, 'https://' ) !== false || strpos( $element, 'https://' ) !== false || strpos( $element, 'www.' ) !== false ) {
    continue;
    }

    if ( empty( $inside_block ) ) {
    $element = preg_replace_callback( $regex, array( $this, 'glossary_item_hovercard' ), $element );
    }
    }

    return join( $textarr );
    }
    }
    1. Click “Update File” to save your changes.

    The main change is in the glossary_item_hovercard method, where we’ve commented out the lines that were limiting tooltips to the first occurrence of each term.

    Important notes:

    • Always backup your site before making changes to plugin files.
    • This modification may be overwritten when the plugin updates. You might need to reapply these changes after each update.
    • Test the changes on a staging site first, if possible.

    I hope this helps others who want to enable unlimited tooltips for their glossary terms!

  • You must be logged in to reply to this topic.