เวลาเราทำเว็บด้วย WordPress และมีการต้องมาเกี่ยวข้องกับการเขียน JavaScript ในหลายครั้งจะต้องมีการเรียกใช้ค่าจากฝั่ง PHP
เนื่องด้วย PHP และ JavaScript นั้นทำงานคนละที่กัน (PHP ทำงานบนเซิร์ฟเวอร์ และ JavaScript ทำงานฝั่งเบราเซอร์) ทำให้เราจะส่งค่าจาก PHP ไปให้ JavaScript โดยตรงไม่ได้ ทางออกที่เจอกันบ่อยๆ คือให้ PHP ทำการ echo
ค่านั้นๆ ออกมาแล้ว JavaScript จึงนำเอาไปใช้
ทีนี้ปัญหาอยู่ที่ในไฟล์ .js นั้นเราไม่สามารถแทรกคำสั่ง PHP ลงไปได้ ดังนั้นท่าที่เราเจอบ่อยที่สุดท่าหนึ่งก็คือการเขียน JS แทรกลงไปในไฟล์เท็มเพลต และ echo
ค่าจาก PHP ลงไปตรงนั้น วิธีนี้แม้จะทำให้ได้ผลลัพธ์ที่ต้องการได้ แต่ก็ทำให้โค้ดรก และต้องเอาโค้ด JS มาปะปนอยู่ในไฟล์เท็มเพลตด้วย
รู้จักกับ wp_localize_script()
ทาง WordPress เองก็ทราบถึงปัญหานี้ดี จึงได้เตรียมฟังก์ชัน wp_localize_script()
เอาไว้ให้ใช้งาน ฟังก์ชันนี้จะมีหน้าที่ส่งค่าจากฝั่ง PHP ไปให้กับ JavaScript โดยจะแปะเอาไว้เป็นพร็อพเพอร์ตี้ตัวหนึ่งของออพเจ็กท์ window
ทำให้ JS ในทุกๆ ที่ของเว็บเราสามารถเข้าถึงค่าจากตรงนี้ได้
wp_localize_script( string $handle, string $object_name, array $variables );
ฟังก์ชันนี้รับพารามิเตอร์ 3 ตัวดังนี้
$handle
ชื่อ JavaScript ที่จะแปะตัวแปรก้อนนี้ไปด้วย (พารามิเตอร์แรกในwp_enqueue_script()
)$object_name
ชื่อออพเจ็กท์ที่ต้องการ$variables
ระบุเป็น associative array (key => value) ชุดข้อมูลที่ต้องการส่งไป
อาจจะงงกับคำอธิบาย (ตอนใช้ทีแรกผมก็งงเหมือนกัน) เอาเป็นว่ามาดูตัวอย่างการใช้งานกัน
<?php add_action('wp_enqueue_scripts', function() { wp_enqueue_script( 'main-js', get_stylesheet_directory_uri() . '/js/custom_script.js', ['jquery'], null, true ); $js_vars = [ 'ajax_url' => admin_url( 'admin-ajax.php' ), 'logo_path' => get_stylesheet_directory_uri() . '/images/logo.svg' ]; wp_localize_script( 'main-js', 'wp63', $js_vars ); });
การทำงานของโค้ดตัวอย่างจะเริ่มต้นที่ wp_enqueue_script()
ที่เมื่อคำสั่งนี้ทำงาน มันจะไปตรวจสอบว่ามีการ localize ค่าผ่านฟังก์ชัน wp_localize_script()
ที่ผูกอยู่กับ handle ตัวนี้หรือเปล่า (ในที่นี่เราต้องชื่อ handle เอาไว้ว่า main-js
) ถ้าตรวจเจอก็จะทำการคืนค่ากลับออกไป (ค่าจาก $js_vars
ใน wp_localize_script()
) โดยค่าแต่ละตัวจะถูกแปะเอาไว้เป็นพร็อพเพอร์ตี้หนึ่งของออพเจ็กท์ window.<object_name>
ในฝั่ง JavaScript เราก็สามารถเรียกใช้ค่าที่เรา localize มาแล้วได้ผ่านออพเจ็กท์ window.<object_name>.<array_key>
จากโค้ดข้างบนถ้าเราต้องการเรียกค่า $js_vars['logo_path']
เราก็เรียกค่านี้ผ่านออพเจ็กท์ window.wp63
ได้ เช่น window.wp63.logo_path

ปัญหาของ wp_localize_script()
ฟังก์ชัน wp_localize_script()
ยังมีปัญหาอยู่อย่างหนึ่งคือเราไม่สามารถทำการ localize ลง $object_name
ซ้ำหลายครั้งได้ ถ้าสมมุติเราเอามา localize ซ้ำ ค่าที่ WordPress ส่งออกมาจะมีแต่ค่าจากที่เราทำการ localize ครั้งล่าสุดเท่านั้น
ตัวอย่างเช่นในโค้ดนี้ เราจะส่งค่าออกไปที่ wp63
ซ้ำสองครั้ง
wp_localize_script('main-js', 'wp63', ['ajax_url' => admin_url( 'admin-ajax.php' )]); wp_localize_script('main-js', 'wp63', ['logo_path' => get_stylesheet_directory_uri() . '/images/logo.svg']);
ถ้าเรามาเรียกดูออพเจ็กท์ window.wp63
เราจะพบว่าค่ามีเพียงแค่ window.wp63.logo_path
ที่เราส่งทีหลังเท่านั้น ส่วนค่าของ ajax_url
ที่เราส่งมาก่อนจะหายไป

ดังนั้นแล้วถ้าโค้ดของเราอยู่หลายไฟล์ เราก็จำเป็นที่จะต้อง localize ตัวแปรเหล่านั้นลงในหลายๆ $object_name
ซึ่งก็จะทำให้ออพเจ็กท์ window
มีพร็อพเพอร์ตี้จำนวนมหาศาล และอาจจะไปคอนฟลิกท์กับพร็อพเพอร์ตี้จาก library ตัวอื่นที่เราใช้งานด้วยก็ได้
แก้ปัญหา localize ที่ไหนก็ได้ด้วย filter
ใน WordPress จะมีสิ่งที่เรียกว่า “ฮุค (Hook)” อยู่ ซึ่งฮุคเหล่าจะเปิดให้เราสามารถเข้าไปแทรกการทำงาน (เรียกว่า action hook) หรือแก้ไขค่าตัวแปรต่างๆ ได้ (เรียกว่า filter hook) ดังนั้นด้วยหลักการนี้ เราก็จะครอบตัวแปรที่เราจะ localize ด้วยฟิลเตอร์ เพื่อเปิดให้โค้ดส่วนอื่นๆ ในเว็บของเราเข้ามาแก้ไขค่าในตัวแปรที่เราจะทำการ localize ได้
จากโค้ด enqueue ด้านบน เราก็จะมาแก้ไขให้เป็นลักษณะนี้
<?php add_action('wp_enqueue_scripts', function() { wp_enqueue_script( 'main-js', get_stylesheet_directory_uri() . '/js/custom_script.js', ['jquery'], null, true ); $initial_values = [ 'ajax_url' => admin_url( 'admin-ajax.php' ), 'logo_path' => get_stylesheet_directory_uri() . '/images/logo.svg' ]; $js_vars = apply_filters( 'wp63_js_vars', $initial_values ); wp_localize_script( 'main-js', 'wp63', $js_vars ); });
จากโค้ดด้านบน เราจะกำหนดค่าเริ่มต้นที่จะ localize เอาไว้ก่อนในตัวแปร $initial_values
จากนั้นในตัวแปร $js_vars
เราจะทำการ apply_filters()
(สั่งให้ฟิลเตอร์ฮุคทำงาน) และใช้ค่าจาก $initial_values
เป็นค่าเริ่มต้น
การจะเพิ่มค่าใดๆ เข้าไปในตัวแปร $js_vars
ณ จุดนี้เราสามารถทำได้ด้วยการฮุคเข้าไปในฟิลเตอร์ดังกล่าวได้ทันที
<?php add_filter( 'wp63_js_vars', function( $js_vars ){ $js_vars['new_key'] = 'Hello World'; return $js_vars; });
คำสั่ง add_filter()
นั้นจะเป็นการฮุคเข้าไปในฟิลเตอร์ที่กำหนด (พารามิเตอร์แรกใน apply_filters()
) รับค่าที่ฟิลเตอร์ส่งเข้ามา แก้ไขค่า และส่งค่ากลับออกไป ในขั้นตอนนี้เมื่อเราสั่ง add_filter()
แล้ว ก็ให้เพิ่มค่าใหม่ลงในตัวแปรให้เรียบร้อย (หรือจะแก้ไขค่าเดิมก็ได้) จากนั้นก็ return
ค่ากลับออกไป เป็นอันเสร็จ
ในฝั่งหน้าเว็บ เมื่อเราเรียกดูค่าของออพเจ็กท์ window.wp63
ก็จะเจอคีย์ใหม่ที่เราเพิ่มเข้ามา

Leave a Reply