สวัสดีครับผม วันนี้ผมนำเรื่องราวเกี่ยวกับวงจรชีวิตของโปรแกรมเมอร์มาเล่าสู่กันฟังอีกนะครับ ซึ่งเนื้อหาบล็อกนี้อาจจะดูหนักๆหน่อยสำหรับคนที่ไม่รู้เรื่อง Programming Language ฮ่าๆ เพราะเนื้อหาวันนี้เป็นเรื่องที่ผมอยากจะเขียนบันทึกไว้อ่านเองด้วย และเผื่อใครที่มีกรณีที่จะทำงานลักษณะเดียวกัน เจอปัญหาแบบเดียวกัน จะได้ลองนำไปปรับใช้ดูกับโปรเจ็คตัวเองได้
แน่นอนว่าทุกเรื่องราวที่ผมเขียนล้วนมีที่มาที่ไปครับ ครั้งนี้ก็มาจากที่ผมรับทำโปรเจ็คให้กับมหาวิทยาลัยแห่งหนึ่ง ซึ่งเป็นโครงการการทำวารสารครับ มีการจัดเรียงเนื้อหาวารสารโดยแบ่งออกเป็นปีๆ ผมก็รับโปรเจ็คมาแล้วก็มาพัฒนาต่อด้วย WordPress นี่แหละครับ แต่ใช้ร่วมกับ Woocommerce ครับ
และเนื่องจากโครงการนี้ไม่จำเป็นต้องมีระบบสั่งซื้อผมก็ปรับให้เป็นแบบ Cataglogue โหมดไปซะเลย เหตุผลที่ผมเลือกใช้ Woocommerce ในโปรเจ็คนี้เพราะผมว่ามันมีระบบที่ดีมากเลยคับ แบ่งสินค้าเป็นหมวดหมู่ ดูแลง่ายด้วย แม้จะไม่ต้องใช้ระบบสั่งซื้อก็ตาม
ทีนี้ครับในหน้าเว็บ เราก็ต้องการให้ผู้เข้าชมเว็บสามารถเลือกได้ว่าอยากจะดูวารสารปีไหน? ซึ่งในเว็บมีตั้งแต่มี 2512 เป็นต้นมาเลย
หลักการง่ายๆก็ใช้ Widgets ที่มีมาของ Woocommerce คือเจ้าตัว Product Category ครับ
แต่ปัญหามันเป็นตรงนี้ครับ คือถ้าเราเลือก Order by Name เนี่ย มันจะเรียงลำดับแบบจากน้อยไปมากคือ ก็จะเป็น 2512 . 2513 2514 ไปเรื่อยๆ แต่ในความจริงคือเราต้องการให้เรียงปีล่าสุดมาก่อนครับ ดังนั้นจึงเป็นหน้าที่ที่เราจะต้องปรับแต่งกันนิดหน่อยครับ เลยนี่แหละครับที่เป็นที่มาของการเขียนบล็อกตอนนี้
ผมใช้วิธีการแก้ไฟล์ใหม่ โดยไม่ให้ไปยุ่งกับไฟล์เดิมของ Widgets ตัวนี้ครับผม เพราะว่าถ้าผมไปแก้ในไฟล์เดิมเลยเนี่ย พอ Woocommerce มันอัพเดทเวอร์ชั่น ไฟล์ที่ผมแก้ก็จะถูกเขียนทับด้วยไฟล์ใหม่ไปด้วย ดังนั้นผมจึงทำแยกออกมา เรียกว่าการ Override ครับ
มาดูวิธีการกันนะครับ
อย่างแรก ผมยกตัวอย่างไฟล์ที่ผมทำงานละกันเนาะ ไฟล์นี้มีชื่อว่า class-wc-widget-product-categories.php ครับ ซึ่งอยู่ในตำแหน่ง plugins/woocommerce/includes/widgets/class-wc-widget-product-categories.php
ผมก็สร้างไฟล์ใหม่ขึ้นมาก่อนในธีมของผมครับ ตั้งชื่อว่า my-class-wc-widget-product-categories.php ผมเขียนเอาไว้ในโฟลเดอร์ใหม่ที่สร้างขึ้นมาในธีมชื่อว่า widgets คับ (จะตั้งชื่อโฟลเดอร์อะไรก็ได้นะคับ ตามใจเลย) ซึ่งตำแหน่งไฟล์ใหม่ก็คือ wp-content/themes/ธีมของผม/widgets/my-class-wc-widget-product-categories.php
ต่อมาเป็นไฟล์ functions.php ของธีมเราขึ้นมาครับ แล้วเขียนคำสั่งนี้ลงไปเพื่อบอกให้ธีมเราใช้งานไฟล์ตัวใหม่
add_action( 'widgets_init', 'override_woocommerce_widgets', 15 ); function override_woocommerce_widgets() { // Ensure our parent class exists to avoid fatal error if ( class_exists( WC_Widget_Product_Categories ) ) { unregister_widget( WC_Widget_Product_Categories ); include_once( 'widgets/my-class-wc-widget-product-categories.php' ); register_widget( MY_WC_Widget_Product_Categories ); } }
คำสั่งด้านบนมีตัวที่ต้องสั่งเกตคือตรง class_exits นะคับ สำหรับชื่อคลาสนี้นี้ เราไปเปิดดูที่ไฟล์ class-wc-widget-product-categories.php ได้เลย เค้าจะมีเขียนไว้ครับ มันเป็นการบอกว่า เนี่ยเช็คดูหน่อยซิว่าเจ้าตัวนี้มันมีอยู่หรือเปล่า ถ้ามีนะก็ให้ Unregister ไป แล้วหันมาใช้ไฟล์ใหม่ที่เราสร้างแทนกันดีกว่านะ ซึ่งไฟล์ใหม่ที่เราจะใช้แทนก็อยู่ตรงบรรทัด include_once นั่นเองครับผม ก็ใส่ตำแหน่งไฟล์และชื่อไฟล์เข้าไปได้เลย
ทีนี้เราก็เอาคำสั่งนี้ไปใส่ในไฟล์ my-class-wc-widget-product-categories.php
class MY_WC_Widget_Product_Categories extends WC_Widget_Product_Categories { function widget( $args, $instance ) { //ตรงนี้ก็ Copy ฟังก์ชั่นจากไฟล์ต้นฉบับ คือไฟล์ class-wc-widget-product-categories.php มาใส่ }
เห็นตรงที่ผมคอมเมนต์บอกไหมครับ ว่าตรงนั้นให้ copy ฟังก์ชั่นจากไฟลต้นฉบับมาใส่ ทีนี้จะดูอย่างไรว่าฟังก์ชั่นที่ว่าดูอย่างไร ให้ดูภาพนี้ประกอบนะครับ
จากภาพจะเห็นที่ผมวงกลมๆ สีชมพูไว้ใช่ไหมคับ นั่นแหละคับ มันก็จะคล้ายๆกับโค้ดด้านบนที่ผมเขียน ซึ่งมันเป็น function ของ widget ตัวนี้ หน้าที่ของเราก็คือ copy บรรทัดที่ผมชี้ นั่นเลยคับ คือตั้งแต่ global อะไรนั่นลงมาให้หมดคับ ที่อยู่ภายใต้ { } ของฟังก์ชั่นนี้ เอามาใส่ในไฟล์ตัวใหม่ของเราเลย
ซึ่ง final ก็จะได้ไฟล์แบบนี้นั่นเอง
<?php class TU_WC_Widget_Product_Categories extends WC_Widget_Product_Categories { function widget( $args, $instance ) { // copy the widget function from woocommerce/widgets/widget-best_seller.php global $wp_query, $post; $count = isset( $instance['count'] ) ? $instance['count'] : $this->settings['count']['std']; $hierarchical = isset( $instance['hierarchical'] ) ? $instance['hierarchical'] : $this->settings['hierarchical']['std']; $show_children_only = isset( $instance['show_children_only'] ) ? $instance['show_children_only'] : $this->settings['show_children_only']['std']; $dropdown = isset( $instance['dropdown'] ) ? $instance['dropdown'] : $this->settings['dropdown']['std']; $orderby = isset( $instance['orderby'] ) ? $instance['orderby'] : $this->settings['orderby']['std']; $hide_empty = isset( $instance['hide_empty'] ) ? $instance['hide_empty'] : $this->settings['hide_empty']['std']; $dropdown_args = array( 'hide_empty' => $hide_empty, ); $list_args = array( 'show_count' => $count, 'hierarchical' => $hierarchical, 'taxonomy' => 'product_cat', 'hide_empty' => $hide_empty, ); $max_depth = absint( isset( $instance['max_depth'] ) ? $instance['max_depth'] : $this->settings['max_depth']['std'] ); $list_args['menu_order'] = false; $dropdown_args['depth'] = $max_depth; $list_args['depth'] = $max_depth; if ( 'order' === $orderby ) { $list_args['menu_order'] = 'asc'; } else { $list_args['orderby'] = 'title'; } $this->current_cat = false; $this->cat_ancestors = array(); if ( is_tax( 'product_cat' ) ) { $this->current_cat = $wp_query->queried_object; $this->cat_ancestors = get_ancestors( $this->current_cat->term_id, 'product_cat' ); } elseif ( is_singular( 'product' ) ) { $product_category = wc_get_product_terms( $post->ID, 'product_cat', apply_filters( 'woocommerce_product_categories_widget_product_terms_args', array( 'orderby' => 'parent', ) ) ); if ( ! empty( $product_category ) ) { $this->current_cat = end( $product_category ); $this->cat_ancestors = get_ancestors( $this->current_cat->term_id, 'product_cat' ); } } // Show Siblings and Children Only. if ( $show_children_only && $this->current_cat ) { if ( $hierarchical ) { $include = array_merge( $this->cat_ancestors, array( $this->current_cat->term_id ), get_terms( 'product_cat', array( 'fields' => 'ids', 'parent' => 0, 'hierarchical' => true, 'hide_empty' => false, ) ), get_terms( 'product_cat', array( 'fields' => 'ids', 'parent' => $this->current_cat->term_id, 'hierarchical' => true, 'hide_empty' => false, ) ) ); // Gather siblings of ancestors. if ( $this->cat_ancestors ) { foreach ( $this->cat_ancestors as $ancestor ) { $include = array_merge( $include, get_terms( 'product_cat', array( 'fields' => 'ids', 'parent' => $ancestor, 'hierarchical' => false, 'hide_empty' => false, ) ) ); } } } else { // Direct children. $include = get_terms( 'product_cat', array( 'fields' => 'ids', 'parent' => $this->current_cat->term_id, 'hierarchical' => true, 'hide_empty' => false, ) ); } // End if(). $list_args['include'] = implode( ',', $include ); $dropdown_args['include'] = $list_args['include']; if ( empty( $include ) ) { return; } } elseif ( $show_children_only ) { $dropdown_args['depth'] = 1; $dropdown_args['child_of'] = 0; $dropdown_args['hierarchical'] = 1; $list_args['depth'] = 1; $list_args['child_of'] = 0; $list_args['hierarchical'] = 1; } // End if(). $this->widget_start( $args, $instance ); if ( $dropdown ) { wc_product_dropdown_categories( apply_filters( 'woocommerce_product_categories_widget_dropdown_args', wp_parse_args( $dropdown_args, array( 'show_count' => $count, 'hierarchical' => $hierarchical, 'show_uncategorized' => 0, 'orderby' => $orderby, 'order' => 'desc', //ผมเพิ่มตรงนี้เพื่อเปลี่ยนรูปแบบการจัดเรียงข้อมูลเป็นมากไปหาน้อย 'selected' => $this->current_cat ? $this->current_cat->slug : '', ) ) ) ); wc_enqueue_js( " jQuery( '.dropdown_product_cat' ).change( function() { if ( jQuery(this).val() != '' ) { var this_page = ''; var home_url = '" . esc_js( home_url( '/' ) ) . "'; if ( home_url.indexOf( '?' ) > 0 ) { this_page = home_url + '&product_cat=' + jQuery(this).val(); } else { this_page = home_url + '?product_cat=' + jQuery(this).val(); } location.href = this_page; } }); " ); } else { include_once( WC()->plugin_path() . '/includes/walkers/class-product-cat-list-walker.php' ); $list_args['walker'] = new WC_Product_Cat_List_Walker; $list_args['title_li'] = ''; $list_args['pad_counts'] = 1; $list_args['show_option_none'] = __( 'No product categories exist.', 'woocommerce' ); $list_args['current_category'] = ( $this->current_cat ) ? $this->current_cat->term_id : ''; $list_args['current_category_ancestors'] = $this->cat_ancestors; $list_args['max_depth'] = $max_depth; echo '<ul class="product-categories">'; wp_list_categories( apply_filters( 'woocommerce_product_categories_widget_args', $list_args ) ); echo '</ul>'; } // End if(). $this->widget_end( $args ); } } ?>
ซึ่งโค้ดด้านบนนั้น ผมก็ปรับแต่งไปเรียบร้อยแล้วครับ โดยเพิ่มคำสั่ง
'order' => 'desc',
เข้าไปในนั้น เพื่อเปลี่ยนแปลงรูปแบบการทำงานครับ
และนี่แหละครับ คือเทคนิคการ Override ไฟล์ Widget ของ Woocommerce ครับ อาจจะดูยาวหน่อยนะครับ แต่ผมว่าก็น่าจะช่วยให้ใครที่กำลังมองหาแนวทางการแก้ไขไฟล์ widgets ต่างๆ ได้บ้าง
หรือหากใครมีเทคนิคอื่นๆ ก็นำมาเล่าสู่กันฟังได้นะครับ ขอบคุณมากครับ