ארכיון פוסטים בטבלה נפרדת

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

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

אבל הי, אם תחליטו שאתם רוצים תנאי אחר אני נוותן אפשרות להשתחל לפילטר "archive_query_critearia". נניח, אם אני רוצה לארכב רק פוסטים שיש להם שדה מטא מסוים, אכניס שאילתא (לצערי בשלב זה מפורשת) שתתן לפחות מערך שיש בו עמודה ID. בכל הרצה של עמוד הסקריפט יבדוק אם יש מה לעדכן בארכיון ואם כן מיד ייקח, יעתיק, ויותיר את הטבלה נקיה.

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

את הקוד תוכלו לדגוםכאן.

 

[1] ואם כבר מדברים על חיפוש, החיפוש של וורדפרס הוא שאילתת LIKE. בטבלאות כבדות השאילתא תהיה איטית. כעת, השאילתא תהיה מהירה מאין כמוהה. אתם עשויים למצוא אתכם עם 50 פוסטים לכל היותר באתר שמתעדכן תדיר. לצערי, לא הצלחתי ולא ניסיתי גם לטפל בתמונות מספריית המדיה, ולכן התמונות עדיין עלולות להעמיס על הטבלה. עם זאת, מה רע לדלל את הטבלה?

wp_dependencies + minifier.org = extraordinaire

באמצעות תיקיית המיניפיי שלminifier.orgמימשתי מנגנון פשוט של קונקטניזציה ומיניפיקציה של סקריפטים. אצלי בקוד זה תלוי בהגדרה של options framework, אבל אתם יכולים לשנות את השורה למשהו בסגנון:

$this->option='cache'

ההפעלה פשוטה, על ידי:

new \minify\css();
new \minify\js();

כל אחת מהמחלקות האלה לוקחת את התור של וורדפרס, על פי הדפנדנסי שקבוע בתור, ובמקום לפלוט אותו במקומו, את ה-CSS בהדר ואת הסקריפטים בהדר או בפוטר, מרוקנת אותו לתוך באפר, ואת הבאפר מצמצמת לתוך קובץ שיימצא בתיקיית cache בתבנית. לאחר מכן טוענת את הקובץ המכווץ ממיקומו.

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

את הקוד תוכלו לדגוםכאן.

כלים לאופטימיזציה של תמונות

שאלה: אתר עם כ-1600 תמונות שעל כולן גוגל מקטר. איך עושים אופטימיזציות לכמות הזו?

תשובה קצרה: עושים responsive images. מוסיפים גדלים של תמונות לפי הצורך, ומשחקים מעט עם האטריביוט sizes במידה והתמונה היא לא על רוחב מלא של העמוד (כלומר 100vw)

תשובה ארוכה יותר, ולא תמיד צריך לעשות אותה, וגם ככה היא מורכבת, כי היא דורשת תכנות: להדבק לאקשן shutdown, לקחת את תוכן כל העמוד בבאפר, "לקצור" את כל התמונות, לבדוק כל תמונה אם יש לה אטריביוט width, ואז להחליף את התמונה לתמונה מתאימה ברוחב המתאים – בין אם זו תמונה מוכנה כבר מה- image sizes, ובין אם זו תמונה שמיוצרת on the fly. במידה ויש לכם קאש, אחרי הרצה אחת, pleloaded, האתר ישקול הרבה פחות והתמונות יהיו בגודל המדויק. אבל כאמור, פרוצדורה כזאת היא רק נשק יום הדין.

שלושת הפלאגינים האלה עוזרים מאוד בשני המקרים:

  1. Regenerate Thumbnails – אחרי ששיניתם את גדלי התמונות הרצויים, או הוספתם חדשים עם הפונקציה add_image_sizes, יצרו מחדש ו-וורדפרס ייצר בשבילכם את התמונה הרפסונסיבית הרצויה, כולל הגדלים החדשים שזה עתה יצרתם. שימו לב, יותר גדלי תמונות שיצרתם הם יותר תמונות שמורות בתיקיית uploads. באיזה שהוא שלב היא תתפוצץ. הוסיפו גדלים בחכמה.
  2. PNG to JPG – כדי לשמור על עמוד קל וקומפקטי רצוי מאוד לוותר כמה שניתן על שימוש ב-png לטובת תמונות מכווצות. פעולה כזאת תחסוך 90% בד"כ מכובד האתר
  3. Post Thumbnail Editor – אם החיתוך האוטומטי של וורדפרס לא עלה יפה, תוכלו לחתוך את התמונה מחדש

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

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

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

מטמון לשאילתות בדאטהבייס

מצ"ב מימוש לקלאס שנכנס להוקים הנכונים על מנת לשמור בתיקיה תחת uploads/cache/queries את השאילתות לדאטהבייס פר צירוף של query vars. דהיינו, לפני שניגש לבצע את השאילתא בודק אם נמצא הקובץ המתאים, במידה ונמצא מחזיר את תוכנו, ובמידה ולא נמצא מבצע את השאילתא ואז שומר את התוצאות באותו הקובץ. כל מה שצריך לעשות הוא רק לאתחל את הקלאס הזה ב- functions.php.

הקלאס מתביית על שלושה הוקים:

  1. posts_pre_query, המקום שבו ניתן להשחיל לשאילתא תוצאות ולמנוע מהתוכנית להזדקק לפניה לדאטהבייס על מנת להניב את התוצאות הללו. התוכנית לוקחת את המערך של משתני הקוורי, עושה לו סריאליזציה ואז האשינג, מאחר שכל מערך כזה הוא יחידאי, סריאלציה והאשינג שלו יהיה גם יחידאי, ולכן אין חשש, כשנצטרך לדלות מידע פר קוורי, נוכל. בהוק אנו בודקים אם קובץ מתאים לשאילתא אכן קיים ואם קיים מחזירים את תוכנה לאחר דה-סריאליציה.
  2. posts_results. במידה והקובץ אינו קיים או במידה ואני מבקש מפורשות לרמוס את התוצאות בעזרת פרמטר בשם override_cache, אנו יוצרים קובץ ושומרים לתוכו את תוכן הקוורי.
  3. save_post – בכל שמירה של פוסט הקאש יתרוקן כולו. למה לא לשמור את זה בעזרת מזהה על פי פוסט ואז למחוק רק את השאילתא של אותו הפוסט? בפשטות, זה בלתי אפשרי. אני רוצה לשלוט בכל שאילתא, ישנם אינספור סוגי שאילתות ואני לא יכול לצפות אותן. לכן אני לא יכול למחוק תוצאות שאילתא ספציפית ואני חייב למחוק את כולן. ברוב המקרים השאילתות גם ככה יהיו מאונדקסות כך שלא נרוויח עד כדי כך הרבה מהקאש, אבל במקרה של שאילתות לא מאונדקסות, כאלה שיקחו 0.3 שניות, אם נפנה לקובץ ונקח את התוצאות המחיר שזה יגבה מאיתנו הוא פחות מ-0.001 שניות וכך הרווחנו 0.3 שניות. הדבר מתבטא בעיקר בסקיילינג גבוה, אך גם באמצעות שאילתות מלאות ב"ג'וינים".
class db_cache {
	protected $folder;

	public function __construct() {
		add_filter( 'posts_pre_query', array( $this, 'posts_pre_query' ), 10, 2 );
		add_filter( 'posts_results', array( $this, 'posts_results' ), 10, 2 );
		add_action( 'save_post', array( $this, 'save_post' ), 10, 3 );

		$this->folder = WP_CONTENT_DIR . "/uploads/cache/queries/";
	}

	public function save_post( $id, $post, $bool ) {
		array_map('unlink', glob("{$this->folder}/*"));
	}

	public function posts_results( $posts, $query ) {
		$md5 = md5( serialize( $query->query_vars ) );
		if ( $md5 && ! is_admin() ) {
			$file      = $md5 . '.txt';
			$full_path = $this->folder . $file;
			if ( ! file_exists( $full_path ) || ( isset( $_GET['override_cache'] ) && $_GET['override_cache'] ) ) {
				$output = serialize( $posts );
				self::create_folders_up_to_path( $full_path );
				$write = file_put_contents( $full_path, $output );
			}
		}

		return $posts;
	}


	public function posts_pre_query( $something, $query ) {
		$md5 = md5( serialize( $query->query_vars ) );
		if ( $md5 ) {
			$file      = $md5 . '.txt';
			$full_path = $this->folder . $file;
			if ( file_exists( $full_path ) && $content = file_get_contents( $full_path ) ) {
				return unserialize( $content );
			}
		}

		return null;
	}

	static public function create_folders_up_to_path( $path ) {
		$pathinfo = pathinfo( $path );
		$unexists = array();
		$checked  = isset( $pathinfo['dirname'] ) ? $pathinfo['dirname'] : false;

		while ( $checked && ! file_exists( $checked ) ) {
			$unexists[] = substr( $checked, strrpos( $checked, '/' ), strlen( $checked ) );
			$checked    = substr( $checked, 0, strrpos( $checked, '/' ) );
		}

		$success = true;
		while ( count( $unexists ) ) {
			$checked = $checked . array_pop( $unexists );
			$success &= mkdir( $checked );
			$checked .= '/';
		}

		return $success;
	}
}