7
Mar

วิธี Override ไฟล์ Widgets ของ Woocommerce

Category: Blog / 68 views

สวัสดีครับผม วันนี้ผมนำเรื่องราวเกี่ยวกับวงจรชีวิตของโปรแกรมเมอร์มาเล่าสู่กันฟังอีกนะครับ ซึ่งเนื้อหาบล็อกนี้อาจจะดูหนักๆหน่อยสำหรับคนที่ไม่รู้เรื่อง 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 ต่างๆ ได้บ้าง

หรือหากใครมีเทคนิคอื่นๆ ก็นำมาเล่าสู่กันฟังได้นะครับ ขอบคุณมากครับ

Tags:


Phraisohn Siripool is a Graphic Designer and Website Developer. Contact Buksohn for Your Business Endeavours