แก้ปัญหา WordPress Block Editor โหลดไม่ขึ้น
ส่วนใหญ่แล้ว Block Editor ของ WordPress ที่โหลดไม่ขึ้นเกิดจาก JavaScript error — สคริปต์ที่พังจากปลั๊กอิน wordpress หรือธีมเพียงตัวเดียวก็ทำให้ React app ทั้งตัวหยุดทำงาน
เผยแพร่แล้ว
ส่วนใหญ่แล้ว Block Editor ของ WordPress ที่โหลดไม่ขึ้นเกิดจาก JavaScript error — สคริปต์ที่พังจากปลั๊กอิน wordpress หรือธีมเพียงตัวเดียวก็ทำให้ React app ทั้งตัวหยุดทำงาน แล้วตัว editor ก็จะเรนเดอร์ไม่เสร็จ ให้เปิด developer console ของเบราว์เซอร์ (กด F12 หรือ Cmd+Option+I บน Mac) แล้วรีโหลดหน้าแก้ไข จากนั้นอ่านข้อความ error สีแดง มันมักจะบอกชื่อไฟล์ที่โยน error ออกมาเสมอ บรรทัดเดียวนั้นบอกคุณได้ว่าต้องปิดปลั๊กอินตัวไหน และปกติแล้วคุณจะกลับมาเขียนบทความต่อได้ภายในไม่ถึงห้านาที การติดตั้ง WordPress ใหม่ การเพิ่ม PHP memory limit และการเปลี่ยนไปใช้ Classic Editor คือสามคำแนะนำที่พบบ่อยที่สุดบนอินเทอร์เน็ต และทั้งสามอย่างมักเป็นทางเลือกที่ผิด
ทำไม editor ถึงพังในแบบที่มันเป็น
Block Editor (Gutenberg) คือ single-page React application ที่ทำงานอยู่ภายใน wp-admin/post.php และ post-new.php WordPress จะ enqueue ชุดของ script package หลายตัว — wp-blocks, wp-element, wp-editor, wp-edit-post — แล้ว app ก็บูตขึ้นมาผ่าน wp.domReady() แต่ JavaScript จะหยุดทำงานทันทีที่เจอ uncaught exception ตัวแรก ดังนั้นถ้ามีสคริปต์ที่ถูก enqueue ตัวใดตัวหนึ่งโยน error ออกมาระหว่างที่ editor กำลัง initialize ทุกอย่างที่อยู่หลังจากนั้นก็ตายตามไปด้วย พื้นที่เขียนบทความที่คุณตั้งใจทำมาอย่างดีก็จะยุบลงเหลือแค่หน้าจอสีขาวว่างเปล่า หรือขึ้นข้อความว่า “The editor has encountered an unexpected error.”
โดยดีฟอลต์ WordPress ยังรวม (concatenate) สคริปต์ฝั่ง admin เข้าด้วยกันเพื่อลดจำนวน request นั่นหมายความว่า JS ที่พังของปลั๊กอินตัวหนึ่งสามารถลากสคริปต์อื่นที่ไม่เกี่ยวข้องซึ่งโหลดอยู่ใน bundle เดียวกันให้พังตามไปด้วย นี่คือเหตุผลว่าทำไมตัวการที่แท้จริงถึงไม่ได้ชัดเจนจากพฤติกรรมเพียงอย่างเดียวเสมอไป แต่ console บอกได้
รูปแบบความล้มเหลวแบบที่สองจะดูต่างออกไป editor โหลดขึ้นมาได้ แต่เวลาบันทึกกลับโยน “Updating failed. The response is not a valid JSON response.” ออกมา นั่นไม่ใช่ปัญหาของ JavaScript ตัว editor สื่อสารกับ REST API ที่ /wp-json/wp/v2/ และมันคาดหวังว่าจะได้ JSON ที่สะอาดกลับมา ถ้าปลั๊กอินหรือ functions.php ของธีมคุณพ่น PHP notice, warning หรือ fatal ออกมา ก่อน ตัว JSON — หรือปลั๊กอินด้านความปลอดภัยบล็อก REST route หรือปลั๊กอิน redirect เขียน URL ใหม่ — response ก็จะถูกปนเปื้อน และ editor ก็จะ parse มันไม่ได้
วิธีแก้ เรียงจากเร็วที่สุดก่อน
1. อ่าน console ทำให้ error เกิดขึ้นซ้ำโดยเปิด DevTools ไว้ error อย่างเช่น Uncaught TypeError ... some-plugin/build/index.js จะชี้ตรงไปยังปลั๊กอินตัวที่มีปัญหา ขั้นตอนเดียวนี้แก้ปัญหาได้ในกรณีส่วนใหญ่ และช่วยให้คุณไม่ต้องมานั่งไล่ปิดทีละตัวแบบเดาสุ่ม
2. ตัดปัญหาที่เบราว์เซอร์ออกไปก่อน ลอง hard-refresh (Cmd/Ctrl+Shift+R) แล้วลองเปิดหน้าต่างแบบ incognito โดยปิด extension ทั้งหมด บางครั้ง ad blocker และ privacy extension ก็ไปตัดสคริปต์ฝั่ง admin ออก ถ้ามันทำงานได้ใน incognito ปัญหาก็อยู่ที่ extension ของเบราว์เซอร์หรือแคชเก่า ไม่ใช่ที่เว็บของคุณ
3. เช็ค REST API โดยตรง ถ้าคุณเห็นข้อความ “not a valid JSON” ให้เข้าไปที่ https://yoursite.com/wp-json/ ในเบราว์เซอร์ คุณควรจะได้ JSON เต็มหน้าจอ ถ้าคุณได้ HTML, error 500 หรือถูก redirect ไปหน้า login นั่นแหละคือบั๊กของคุณ — มีปลั๊กอินตัวหนึ่งกำลังทำให้ REST response พัง ไม่ใช่ตัว editor เอง
4. ไล่ปิดปลั๊กอินทีละครึ่ง (bisect) ปิดใช้งานทั้งหมดก่อน ยืนยันว่า editor โหลดได้ แล้วค่อยเปิดกลับมาทีละตัวจนกว่ามันจะพังอีกครั้ง ถ้าคุณเข้า wp-admin ไม่ได้เลย ให้ทำผ่าน SFTP โดยการเปลี่ยนชื่อโฟลเดอร์
mv wp-content/plugins wp-content/plugins_off
WordPress จะปิดใช้งานทุกอย่างเมื่อโฟลเดอร์นั้นหายไป จากนั้นเปลี่ยนชื่อกลับ แล้วค่อยย้ายปลั๊กอินเข้าออกทีละตัว
5. ทดสอบธีม สลับไปใช้ Twenty Twenty-Four ธีมที่ enqueue JS ของ editor ที่พัง หรือโยน PHP ใน functions.php ก็ทำให้เกิดอาการแบบเดียวกันได้
6. เปิด log แล้วอ่าน error ตัวจริง โดยเฉพาะสำหรับความล้มเหลวแบบ REST/JSON ให้เปิด debugging ใน wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
ตัว fatal จะถูกเขียนลงไปใน wp-content/debug.log พร้อมชื่อไฟล์และเลขบรรทัดที่แน่นอน ถ้า stack trace นั้นดูซับซ้อน — ชื่อคลาสที่มี namespace, สาย require ต่อกันเป็นทอด ๆ, fatal ที่ฝังอยู่ใต้ trace สิบบรรทัด — ให้เอาไปวางใน เครื่องมือถอดรหัส WordPress error log ของเรา เพื่อดูแบบเข้าใจง่ายว่าจริง ๆ แล้วปลั๊กอินตัวไหนและบรรทัดไหนเป็นตัวที่ทำให้เกิดปัญหา นั่นคือความต่างระหว่าง “มีบางอย่างพัง” กับ “บรรทัด 214 ของปลั๊กอินตัวนี้พัง”
ถ้าคุณสงสัยว่าการรวมสคริปต์ (concatenation) กำลังบดบังตัวการที่แท้จริง ให้บังคับให้แต่ละสคริปต์โหลดแยกกัน เพื่อให้ error ใน console ชี้ไปที่ไฟล์เดียวเป๊ะ ๆ
define( 'SCRIPT_DEBUG', true );
define( 'CONCATENATE_SCRIPTS', false );
สิ่งที่ไม่ควรทำ
อย่าติดตั้งปลั๊กอิน Classic Editor แล้วคิดว่าแก้ปัญหาได้แล้ว มันไม่ได้แก้อะไรเลย — มันแค่ซ่อน Block Editor ไว้เพื่อให้คุณเลิกเห็น error เท่านั้น JavaScript ที่พังหรือ REST response ที่พังยังคงอยู่ที่เดิม และมันจะกลับมาเล่นงานคุณอีกในหน้า site editor, ในส่วน widget หรือครั้งถัดไปที่คุณอัปเดต ให้วินิจฉัยปัญหาก่อน แล้วค่อยถอยไปใช้ Classic ก็ต่อเมื่อคุณตัดสินใจอย่างจงใจแล้วว่าจะเลิกใช้ block
อย่าเพิ่ม PHP memory limit ด้วยความเคยชิน มันคือวิธีแก้แบบ copy-paste ที่อินเทอร์เน็ตชอบที่สุด แต่ editor ที่ขึ้นหน้าขาวนั้นแทบไม่เคยเกิดจาก memory หมด การที่ memory หมดจริง ๆ จะโยน fatal ที่เฉพาะเจาะจงออกมา — “Allowed memory size of N bytes exhausted” — ซึ่งคุณจะเห็นได้ใน debug.log ถ้าไม่มีบรรทัดนั้น การเพิ่ม memory ก็ไม่ได้เปลี่ยนอะไรเลย
อย่าติดตั้ง WordPress core ใหม่ ไฟล์ core นั้นเหมือนกันทุก byte ในทุกการติดตั้ง ถ้า core เป็นปัญหาจริง เว็บ WordPress ทุกเว็บบนโลกก็คงมี editor พังกันหมดในตอนนี้ ความผิดพลาดแทบทั้งหมดอยู่ที่ปลั๊กอินหรือธีมของคุณ และการติดตั้ง core ใหม่ยังเสี่ยงที่จะเขียนทับของบางอย่าง ในขณะที่ไม่ได้แก้อะไรเลย
อย่าเคลียร์หรือปิดปลั๊กอินแคชแบบมั่ว ๆ เป็นขั้นตอนแรก การ minify และ concatenate JS แบบดุดัน สามารถ ทำให้ editor พังได้ ดังนั้นก็คุ้มที่จะลองทดสอบ — แต่ให้เช็ค console ก่อนที่คุณจะไปไล่ล้างแคชแบบสุ่ม ๆ การเดาคือสาเหตุที่ทำให้การแก้ปัญหาห้านาทีกลายเป็นการนั่งทำทั้งบ่าย
ยังแก้ไม่ได้อยู่ดี?
ถ้า console สะอาดดี, REST API คืน JSON ที่ถูกต้อง และการไล่ปิดปลั๊กอินกับธีมจนครบแล้วก็ยังทำให้ editor ตายอยู่ คำตอบมักจะนั่งรออยู่ใน debug.log เสมอ ให้เปิด WP_DEBUG_LOG ทำให้ปัญหาเกิดขึ้นซ้ำหนึ่งครั้ง แล้วเอา fatal ที่ได้ไปรันผ่าน error log decoder ตัว stack trace จะบอกชื่อไฟล์ให้ — เริ่มจากตรงนั้น