בניית מבנה קישורים מותאם באמצעות ה- Rewrite API של וורדפרס

אחד ה- API החשובים והפחות מוכרים בוורדפרס הוא ה- Rewrite API. אותו API מספק את האפשרות והפונקציונליות ליצירת מבנה קישורים מותאמים אישית.

בחלקו הראשון של פוסט זה נלמד כיצד להשתמש במשתני השאילתה (Query Vars) הדיפולטיביים שוורדפרס מספקת ונראה כיצד להוסיף משתנים מותאמים אישית משלנו.

בחלקו השני של הפוסט נראה אילו כלים וורדפרס מספקת לנו בכדי לשכתב קישור ממבנה של שאילתה למבנה של קישור קבוע (Permalink) באמצעות ממשק ה- Rewrite API.

הקדמה: המבנה של כתובת URL

כתובות URL משמשות לשליחת בקשות HTTP GET דרך האינטרנט. שיטת GET שולחת זוגות של מפתח = ערך בתוך כתובת URL בכדי לקבל תגובה משרת מסויים.

קחו לדוגמה את כתובת האתר הבאה ושימו לב לחלק האחרון בכתובת URL זו:

http://example.com/?p=123

סימן השאלה (?) מחלק את כתובת האתר הזו לשני חלקים. החלק הראשון הוא שם הדומיין, והחלק השני הוא מחרוזת השאילתה (Query String).

אמנם וורדפרס יודעת כי עליה להביא לנו את הפוסט בעל ה- ID שמספרו 123, אך לבני אדם אין זה סמנטי וקריא, כלומר הכתובת לא מרמזת לנו דבר על התוכן שלה.

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

באמצעות אותו שכתוב למשל ניתן לתרגם את כתובת האתר הקודמת שהצגנו לכתובת במבנה הבא:

http://example.com/category/post-title/

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

ניתן להוסיף את הכתובת לסימניות, לשתף ולשמור אותו במספר דרכים ואין היא אמורה להשתנות בטווח הארוך.

זו הסיבה שאנו מכנים אותם קישורים קבועים כ- Permalinks. (קישורים קבועים, Permanent , קבוע).

אך לפני שנראה כיצד לשכתב קישור בצורה של שאילתה, לקישור במבנה קבוע (Permalink), בואו נלמד יותר על אותם Query Strings ועל אותם Query Vars.

חלק א׳: מהם Query Vars ו- Query Strings?

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

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

Public Query Vars לעומת Private Query Vars

Query Vars הם המפתחות המגדירים כל שאילתה שוורדפרס מריצה בשביל לקבל מידע ממסד הנתונים. משתנים אלה מתחלקים לשתי קטגוריות:

  • Public Query Vars – משתנים בכתובת ה URL המיועדים לשימוש כשאילתה.
  • Private Query Vars – משתנים המיועדים לשימוש אך רק באמצעות קוד.

ניקח לדוגמה את הכתובת הבאה:

example.com/?author_name=moshe

ה – Query Var בדוגמה זו הוא author_name, וזה מציין לוורדפרס לספק לנו את כל הפוסטים שנכתבו ע"י המשתמש ששמו moshe. זה המקום לציין כי ניתן אף להוסיף מספר משתנים ע״י הסימן &. לדוגמה:

example.com/?author_name=moshe&tag=news

במקרה זה וורדפרס תספק לנו את כל הפוסטים של moshe המתויגים עם התגית news.

בדוגמה הבאה נראה שאילתה לסוג תוכן מותאם אישית (Custom Post Type) בשם food, עם טקסונומיה משלו (Custom taxonomy) בשם food-family, כשהמונח של הטקסונומיה (term) הוא greens:

example.com/?post_type=food&food-family=greens

שלא כמו משתנים מסוג Public Query Vars, ניתן להשתמש ב Private Query Vars אך רק בתוך שאילתה ב PHP. בפוסט זה לא נלמד עליהם, אך בקישור הבא תמצאו אותם Query Vars משני הסוגים.

כעת בואו נראה את כל המשתנים המובנים (מהסוג של Public Query Vars), שוורדפרס מספקת לנו:

<?php
$keys = array(
	'error', 
	'm', 
	'p', 
	'post_parent', 
	'subpost', 
	'subpost_id', 
	'attachment', 
	'attachment_id', 
	'name', 
	'static', 
	'pagename', 
	'page_id', 
	'second', 
	'minute', 
	'hour', 
	'day', 
	'monthnum', 
	'year', 
	'w', 
	'category_name', 
	'tag', 
	'cat', 
	'author', 
	'author_name', 
	'feed', 
	'tb', 
	'paged', 
	'comments_popup',
	'preview', 
	's', 
	'sentence', 
	'title', 
	'fields', 
	'menu_order'
);

אנו יכולים לאחזר פוסטים לפי סוג תוכן, לפי מחבר, קטגוריה, תגית, טקסונומיה, שנה, חודש, יום וכן הלאה. וורדפרס מספקת לנו משתנים עבור כמעט כל סוג של שאילתה כפי שציינו, עם זאת, מה שחסר ברשימה זו היא האפשרות לבנות שאילתות על בסיס שדות מותאמים אישית (Custom Fields).

למעשה, וורדפרס מספקת לנו משתנים בשם meta-key ו – meta-value, אך אילו אינם מסוג Public המתאימים לשאילתות ב- URL. אלו משתנים מסוג Private היכולים לעבוד אך ורק בתוך קוד, כלומר באמצעות WP_Query, ולא כחלק משאילתת URL. בואו נראה כיצד ליצור Query Vars חדשים…

יצירת Custom Query Vars

לאחר שנוסיף משתנים משלנו אלו יוכלו להתקיים בתוך שאילתה בדיוק כמו כל ה- Query Vars המובנים של וורדפרס. אז נניח שיש לנו סוג תוכן מותאם של ספרים בשם book, לו הוספנו שדה מותאם אישית (Custom Field) בשם author_surname המציין את מחבר הספר.

אם נרצה ליצור שאילתה שתמצא ספרים לפי אותו author_surname, יהיה עלינו ליצור Query Var חדש. הפונקציה שלפנינו מציגה כיצד ניתן להוסיף Custom Query Vars חדשים לרשימה של וורדפרס, במקרה שלנו נוסיף Query Var בשם book-author. הנה כיצד:

<?php
/**
 * Register custom query vars
 *
 * @param array $vars The array of available query variables
 *
 * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/query_vars
 */
function myplugin_register_query_vars( $vars ) {
	$vars[] = 'book-author';
	return $vars;
}
add_filter( 'query_vars', 'myplugin_register_query_vars' );

בשלב הבא עלינו לציין לוורדפרס כי עליה לקבל את הערך של אותו Query Var בזמן שהיא מבצעת את השאילתה. זאת נעשה באמצעות הפונקציה של וורדפרס שנקראת get_query_var.

בכדי לעשות זאת ניצור פונקציה משלנו ונצמיד זו להוק (hook) בשם pre_get_posts המתבצע בדיוק לפני השלב בו וורדפרס ״מביאה״ לנו את הפוסטים. הפונקציה המדוברת נראית כך:

<?php
/**
 * Build a custom query
 *
 * @param $query obj The WP_Query instance (passed by reference)
 *
 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts
 */
function myplugin_pre_get_posts( $query ) {
	// check if the user is requesting an admin page 
	// or current query is not the main query
	if ( is_admin() || ! $query->is_main_query() ){
		return;
	}

	// edit the query only when post type is 'book'
	// if it isn't, return
	if ( !is_post_type_archive( 'book' ) ){
		return;
	}

	$meta_query = array();

	// add meta_query elements
	if( !empty( get_query_var( 'book-author' ) ) ){
		$meta_query[] = array( 'key' => 'author_surname', 'value' => get_query_var( 'book-author' ), 'compare' => 'LIKE' );
	}

	if( count( $meta_query ) > 1 ){
		$meta_query['relation'] = 'AND';
	}

	if( count( $meta_query ) > 0 ){
		$query->set( 'meta_query', $meta_query );
	}
}
add_action( 'pre_get_posts', 'myplugin_pre_get_posts', 1 ); 

בחלקה הראשון של הפונקציה אנו בודקים אם אנו נמצאים בממשק ניהול (admin) – אם כן, אז הפונקציה תיעצר ולא תחזיר לנו כלום. כנ״ל לגבי סיטואציה בה אנו לא נמצאים בלולאה הראשית של וורדפרס, וזאת בכדי למנוע בעיות עם לולאות אחרות.

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

לאחר בדיקות אלו ניצור meta query שיביא לנו רק את הפוסטים בעלי השדה author_surname (זהו ה- key), והוא בעל ערך (value) השווה לערך אותו המשתמש הזין ל- query var שנקרא book-author.

לאחר מכן, נבדוק אם יש יותר מפריט אחד במערך (זאת אומרת שיש עוד פרמטר חוץ מהמשתנה שלנו), ובמידה ויש כזה אז נוסיף למערך relation של AND.

שלב אחרון יהיה להכניס את המערך $meta_query לתוך האובייקט query, ואת זה נעשה באמצעות המתודה set() של הקלאס WP_Query. אנו בעצם לוקחים את הערך של המשתנה מכתובת ה- URL, ואז יוצרים שאילתה רגילה של WP-Query עם אותו הערך.

כעת, לאחר שנזין את הכתובת הבאה וורדפרס תספק לנו את כל הפוסטים מסוג התוכן book אשר להם שדה בשם author_surname השווה ל- Moshe:

http://example.com/?post_type=book&book-author=Moshe

נראה מעולה, אך נשאר דבר נוסף לבצע. אנו רוצים כי במקום שכתובת ה- URL תהיה במבנה של שאילתה, היא תהיה במבנה הבא:

http://example.com/book/book-author/Moshe/

לטובת העניין עלינו לומר לוורדפרס כי עליה לתרגם (לשכתב) את כתובת ה- URL הקודמת (במבנה של שאילתה) לכתובת הנראית כקישור קבוע (permalink), וכאו נכנס השימוש ב- Rewrite API של וורדפרס.

חלק ב׳: שכתוב קישורים – Rewrite API

לפני שנראה איך כיצד לבצע את השכתוב בעזרת ה Rewrite API ניתן מבט קצר על מבנה הקישורים, אותו Permalink Structure הקיים בוורדפרס.

מבנה הקישורים של וורדפרס

וורדפרס מאפשרת לנו לבחור מספר סוגים שונים של מבנה קישורים כברירת מחדל, אך באפשרותינו גם ליצור מבנה קישורים מותאם אישית משלנו באמצעות מספר תגים שוורדפרס מגיעה איתם כברירת מחדל. למשל שנה (%year%), מזהה פוסט (%post_id%), מחבר הפוסט (%author%), ועוד.

אך מעבר לכך אנו יכולים להוסיף תגים חדשים משלנו וכאן נכנס לפעולה תהליך השכתוב (Rewrite) המתחלק לשתי פעולות.

Rewrite Tags & Rewrite Rules

הפעולה הראשונה היא הוספת תג (Rewrite tag) עבור כתובת ה-URL. והשנייה היא הוספת כלל שכתוב (Rewrite rule) המקשר בין התג לבין משתנה השאילתה (Query Vars). במקרה שלנו נוסיף תג עבור אותו Query Var בשם book-author שיצרנו, ונעשה זאת באמצעות הפונקציה add_rewrite_tag.

<?php
/**
 * Add rewrite tags
 *
 * @link https://codex.wordpress.org/Rewrite_API/add_rewrite_tag
 */
function myplugin_rewrite_tag() {
	add_rewrite_tag( '%book-author%', '([^&]+)' );
}
add_action('init', 'myplugin_rewrite_tag', 10, 0);

כעת כל שנשאר לנו לעשות זה לומר לוורדפרס לקשר את אותו התג המותאם שהוספנו, ל- Query Var שיצרנו הנקרא book-author. זאת נעשה באמצעות הפונקציה של וורדפרס ליצירת כללי שכתוב הנקראת add_rewrite_rule.

<?php
/**
 * Add rewrite rules
 *
 * @link https://codex.wordpress.org/Rewrite_API/add_rewrite_rule
 */
function myplugin_rewrite_rule() {
	add_rewrite_rule( '^book/book-author/([^/]*)/?', 'index.php?post_type=book&book-author=$matches[1]','top' );
}
add_action('init', 'myplugin_rewrite_rule', 10, 0);

כעת, הכתובת הזו:

http://example.com/?post_type=book&book-author=Moshe/

תהיה תיאורטית זהה ותספק בדיוק את אותה התוצאה שהכתובת הבאה תספק:

http://example.com/book/book-author/Moshe/

וורדפרס מתרגמת (משכתבת) את הכתובת הזו לכתובת הקודמת ואז מבצעת את השאילתה המדוברת.

חשוב מאד לציין כי לאחר הוספת Rewrite Tags או Rewrite Rules חדשים, אנו חייבים להיכנס לממשק הניהול של וורדפרס > הגדרות > מבנה קישורים ולשמור את שינויים, אחרת השינוים לא יעבדו.

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

<?php
/*
Plugin Name: Custom Query Vars
*/

// Our custom post type function
function create_posttype_book()
{

    register_post_type('book',
        // CPT Options
        array(
            'labels' => array(
                'name' => __('Books'),
                'singular_name' => __('Book')
            ),
            'public' => true,
            'has_archive' => true,
            'rewrite' => array('slug' => 'book'),
            'show_in_rest' => true,
            'supports' => array('title', 'editor', 'author', 'thumbnail', 'custom-fields')

        )
    );
}

// Hooking up our function to theme setup
add_action('init', 'create_posttype_book');


/**
 * Register custom query vars
 *
 * @param array $vars The array of available query variables
 *
 * @link https://codex.wordpress.org/Plugin_API/Filter_Reference/query_vars
 */
function myplugin_register_query_vars($vars)
{
    $vars[] = 'book-author';
    return $vars;
}

add_filter('query_vars', 'myplugin_register_query_vars');


/**
 * Build a custom query
 *
 * @param $query obj The WP_Query instance (passed by reference)
 *
 * @link https://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts
 */
function myplugin_pre_get_posts($query)
{
    // check if the user is requesting an admin page
    // or current query is not the main query
    if (is_admin() || !$query->is_main_query()) {
        return;
    }

    // edit the query only when post type is 'food'
    // if it isn't, return
    if (!is_post_type_archive('book')) {
        return;
    }

    $meta_query = array();

    // add meta_query elements
    if (!empty(get_query_var('book-author'))) {
        $meta_query[] = array(
            'key' => 'author_surname',
            'value' => get_query_var('book-author'),
            'compare' => 'LIKE'
        );
    }

    if (count($meta_query) > 1) {
        $meta_query['relation'] = 'AND';
    }

    if (count($meta_query) > 0) {
        $query->set('meta_query', $meta_query);
    }
}

add_action('pre_get_posts', 'myplugin_pre_get_posts', 1);


/**
 * Add rewrite tags
 *
 * @link https://codex.wordpress.org/Rewrite_API/add_rewrite_tag
 */
function myplugin_rewrite_tag()
{
    add_rewrite_tag('%book-author%', '([^&]+)');
}

add_action('init', 'myplugin_rewrite_tag', 10, 0);


/**
 * Add rewrite rules
 *
 * @link https://codex.wordpress.org/Rewrite_API/add_rewrite_rule
 */
function myplugin_rewrite_rule()
{
    add_rewrite_rule('^book/book-author/([^/]*)/?', 'index.php?post_type=book&book-author=$matches[1]', 'top');
}

add_action('init', 'myplugin_rewrite_rule', 10, 0);

Thanks to premium.wpmudev.org for the original article.

עדיאל בן משה
עדיאל בן משה

מפתח אתרים ותבניות על בסיס וורדפרס, ומתמחה בעיקר בווקומרס וב - ACF. ליצירת קשר עם עדיאל...

  • רועי יוסף 4 בפברואר 2021, 0:38

    פוסט ממש מעניין עדיאל! Rewrite API הוא נושא מאד חשוב שלא היה מידע עליו עדיין בסאבי בלוג. תודה רבה על ההשקעה 🙂

    • עדיאל 4 בפברואר 2021, 8:21

      תודה רועי

השאירו תגובה

 

פעימות
Up!
לבלוג