การส่งค่าจาก PHP ไปหา JavaScript ใน WordPress | WP63

การส่งค่าจาก PHP ไปหา JavaScript ใน WordPress

เวลาเราทำเว็บด้วย 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 ก็จะเจอคีย์ใหม่ที่เราเพิ่มเข้ามา


Posted

in

by

Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.