באתרים אשר מכילים עומדים ארוכים עם הרבה תוכן וכותרות, מומלץ להכניס תוכן עניינים אשר יאפשר לגולש לקפוץ בין חלקים שונים של המאמר. הוספה של תוכן עניינים יכול להקל על הגולש ולשפר את חווית המשתמש שלו באתר שלכם.

את הקוד במאמר הבא אנחנו נעטוף כתוסף אשר נוכל להתקין בכל אתר בקלות ובמהירות. בנוסף, התוסף הזה יודע לבנות את תוכן העניינים של העמוד לפי כותרות ה-<h2> אשר נמצאות בתוכן.

שלב ראשון – יצירת בסיס תוסף

בתור התחלה, ניצור תיקייה חדשה תחת סביבת הפיתוח שלנו בתוך תיקיית plugins של וורדפרס בשם table-of-contetns.

לאחר מכן ניצור קובץ חדש בשם table-of-contents.php תחת התיקייה שיצרנו ונכניס את הקוד הבא:

<?php
/**
 * Plugin Name: Page Table of Contents
 * Plugin URI: https://www.dorzki.io
 * Description: Add automatically a dynamic table of contents to your page or post.
 * Version: 1.0.0
 * Author: dorzki
 * Author URI: https://www.dorzki.io
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain: wp-toc
 *
 * @package    dorzki\TableOfContents
 * @subpackage Plugin
 * @version    1.0.0
 */

namespace dorzki\TableOfContents;

// Block if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// Plugin constants.
define( 'TOC_PATH', plugin_dir_path( __FILE__ ) );
define( 'TOC_URL', plugin_dir_url( __FILE__ ) );


/**
 * Class Plugin
 *
 * @package dorzki\TableOfContents
 */
class Plugin {

	/**
	 * Total headings counter.
	 *
	 * @var int
	 */
	private $counter = 0;

	/**
	 * Article headings.
	 *
	 * @var array
	 */
	private $headings = [];


	/* ------------------------------------------ */


	/**
	 * Plugin constructor.
	 */
	public function __construct() {

		add_action( 'init', [ $this, 'register_textdomain' ] );
		add_action( 'wp_enqueue_scripts', [ $this, 'load_assets' ] );

		add_filter( 'the_content', [ $this, 'build_toc' ] );

		add_shortcode( 'disable_toc', '__return_false' );

	}


	/* ------------------------------------------ */


	/**
	 * Register the plugin's text domain.
	 */
	public function register_textdomain() {

		load_plugin_textdomain( 'wp-toc', false, TOC_PATH . 'languages' );

	}


	/**
	 * Load plugin CSS and JS
	 */
	public function load_assets() {

		wp_enqueue_style( 'toc_styles', TOC_URL . 'assets/styles.css' );

		wp_enqueue_script( 'toc_scripts', TOC_URL . 'assets/scripts.js', [ 'jquery' ], false, true );

	}


	/* ------------------------------------------ */


	/**
	 * Extracts and builds TOC.
	 *
	 * @param string $content the post content.
	 *
	 * @return string
	 */
	public function build_toc( $content ) {

		if ( ! $this->is_disabled( $content ) ) {

			$content = preg_replace_callback( '/<(h2)>(.*?)<\/h2>/i', [ $this, 'extract_headings' ], $content );

			$toc = $this->generate_toc();

			$content = $toc . $content;

		}

		return $content;

	}


	/* ------------------------------------------ */


	/**
	 * Adds title id number and saves the heading.
	 *
	 * @param array $match regex match array.
	 *
	 * @return string
	 */
	public function extract_headings( $match ) {

		$tag = sprintf( '<%1$s id="title_%2$s">%3$s</%1$s>', $match[1], $this->counter, $match[2] );

		$this->counter ++;
		$this->headings[] = $match[2];

		return $tag;

	}


	/**
	 * Generates a table of contents from the headings.
	 *
	 * @return string|boolean
	 */
	public function generate_toc() {

		if ( empty( $this->headings ) ) {
			return false;
		}

		$html = '';

		$html .= '<div class="post_toc">';
		$html .= '  <strong>' . esc_html__( 'Table of Contents', 'wp-toc' ) . '</strong>';
		$html .= '  <ol>';

		foreach ( $this->headings as $id => $text ) {

			$html .= "<li><a href='#title_{$id}'>{$text}</a></li>";

		}

		$html .= '  </ol>';
		$html .= '</div>';

		return $html;

	}


	/* ------------------------------------------ */


	/**
	 * Check if the user don't want TOC on this page.
	 *
	 * @param string $content the post content.
	 *
	 * @return boolean
	 */
	private function is_disabled( $content ) {

		return ( false !== strpos( $content, '[disable_toc]' ) );

	}

}

// Initiate the class.
new Plugin();

הסבר

אני לא אסביר את כל הקוד, אך אתייחס לקוד העיקרי של התוסף. בתור התחלה אנו משתמשים בפילטר של וורדפרס the_content על מנת לקבל את התוכן של המאמר לפני שהוא מודפס, ואז אנחנו מחילים עליו חיפוש אחר כותרות <h2> ע״י שימוש בביטוי רגולרי.

כאשר הקוד מוצא כותרת הוא קורא לפונקציה extract_headings אשר שומרת את הכותרת עצמה במשתנה מסוג מערך בזיכרון ונותנת לכל כותרת מזהה רציף (לדוגמא: title_0, title_1 וכד׳) ואז מתבצעת החלפת בתוכן שהכותרת הישנה מתחלפת בחדשה עם המזהה החדש.

לבסוף לאחר שמצאנו את כל הכותרות ונתנו להם מזהה רציף, הקוד קורא לפונקציה generate_toc אשר תפקידה לקחת את הכותרות ששמרנו בזיכרון, ולבנות תוכן עניינים אשר יוצג לפני התוכן.

שלב שני – הוספת CSS

בשלב זה אנחנו ניצור תיקייה בשם assets ובתוכה ניצור קובץ בשם styles.css ונדביק את הקוד הבא:

.post_toc {
	display: inline-block;
	padding: 15px;
	border: 1px solid #ebebeb;
	background-color: #f8f8f8;
	float: right;
	margin: 0 0 15px 30px;
}

.post_toc ol {
	padding-right: 0;
	list-style-position: inside;
	margin: 15px 0 0;
}

שלב שלישי – הוספת JavaScript

בשלב האחרון אנחנו ניצור קובץ בשם scripts.js תחת התיקייה assets ונדביק את הקוד הבא:

( function ( $ ) {

	$( '.post_toc li a' )
		.on( 'click', function ( e ) {
			e.preventDefault();

			$( 'html, body' ).animate( {
				scrollTop : $( $( this ).attr( 'href' ) ).offset().top
			} );

		} );

} )( jQuery );

שלב רביעי – ביטול תוכן עניינים בעמוד מסויים (אופציונלי)

במידה ואתם מעוניינים שלא יוצג תוכן עניינים בעמוד מסויים, נוסיף לתוכן העמוד את השוטקוד הבא [disable_toc] והתוסף ידע אוטומטית לא לעבד את התוכן ולהציג את תוכן העניינים.

סיכום להורדת הקוד המלא

בעזרת הקוד הנ״ל תוכלו לקחת לבנות את תוכן עניינים של העמוד שלכם בצורה דינאמית, זהו בהחלט כלי עזר חשוב במידה והעמוד שלכם כולל הרבה תוכן.

    כתיבת תגובה

    1. לאה כהן

      רעיון מדליק!
      אהבתי את ההתמודדות עם נתינת id לכותרות כדי שאפשר יהיה לקשר אליהן.

      הגב
      1. דור צוברי

        היי לאה,
        תודה רבה על התגובה, וכן בהחלט פיתרון מגניב 🙂 זה רעיון שעלה לי באחד הפרוייקטים שעשיתי ללקוח שלי.

    2. טל יערי

      תודה רבה, עזר לי המון!

      הגב
      1. דור צוברי

        היי טל,
        שמח לשמוע! תודה רבה על התגובה 🙂

    3. רועי יוסף

      זה אחלה רעיון ואחלה תוסף חביבי!

      הגב
      1. דור צוברי

        היי רועי!
        תודה רבה! בהחלט משהו שימושי ודי קליל לביצוע 🙂

    4. יוני

      היי אחלה פוסט, מזכיר את התוכן עיניינים בויקיפדיה.

      האם יש דרך לעשות שכברירת מחדל התוכן עיניינים לא יוצג. ואם יוצג, אז רק איפה שנוסיף את סורט-קוד?

      הגב
      1. דור צוברי

        היי יוני,
        זה הכיוון 🙂

        לגבי השאלה שלך, עם טיפה ידע ב-PHP אני בטוח שתסתדר.
        אם תרצה מוזמן ליצור קשר לקבלת הצעת מחיר 🙂

    אפשר להציע לך עוגיות? יש גם קפה! השימוש בקוקיז עוזר לשפר את הביקור שלך באתר. המשך גלישה אומר שהסכמת למדיניות הפרטיות שלי, וגם לקפה.

    שתפו