(91) 350-9520 support@omarine.org M-F: 7 AM - 7 PM; Weekends: 9 AM - 5 PM

Lập trình Web: PHP: WordPress: Viết post tùy biến

Post tùy biến có các mục soạn thảo khác với bài viết thông thường, cung cấp các tính năng đặc biệt cho một mục tiêu cụ thể như giới thiệu sản phẩm với một bộ thuộc tính. Khi người sử dụng viết một bài cho sản phẩm, công cụ soạn thảo bổ sung một hộp meta như sau:


Chúng ta xây dựng một plugin cung cấp một kiểu post như thế. Thư mục plugin là plugins/my-product/. Tệp chương trình chính trong thư mục plugin là my-product.php. Tệp my-product.php bắt đầu với một tiêu đề như sau:

<?php
/*
Plugin Name: My Products
Plugin URI: https://developer.wordpress.org/plugins/the-basics/
Description: Provides a custom post.
Version: 20180101
Author: my team
Author URI: https://developer.wordpress.org/
Text Domain: myproduct
Domain Path: /languages
License: GPLv2

*/

textdomain “myproduct” được tải để dịch các xâu kí tự trong plugin. Biến $mylang giữ kết quả tải textdomain:

$mylang = false;
function my_product_load_plugin_textdomain() {

    $domain = 'myproduct';

    $GLOBALS['mylang'] = load_plugin_textdomain( $domain, false, basename( dirname( __FILE__ ) ) . '/languages' );
}
add_action( 'init', 'my_product_load_plugin_textdomain' );

Một plugin cần có hàm kích hoạt và ngừng kích hoạt plugin:

function myplugins_install() {

    my_product_custom_post_type(); 
    flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'myplugins_install' );

function myplugins_deactivation() {

    unregister_post_type( 'my_product' );
    flush_rewrite_rules();
}
register_deactivation_hook( __FILE__, 'myplugins_deactivation' );

Hàm my_product_custom_post_type() thực hiện đăng ký kiểu post:

function my_product_custom_post_type()
{
    register_post_type('my_product',
        [
            'labels' => [
                'name' => __('My Products', 'myproduct'),
                'singular_name' => __('My Product', 'myproduct'),
            ],
            'public' => true,
            'has_archive' => true,
            'rewrite' => ['slug' => 'my_product'],
            'show_in_menu' => true,
            'menu_position' => 11 
        ]
    );
}
add_action('init', 'my_product_custom_post_type');

Trong cuộc gọi tới hàm đăng ký, chúng ta định nghĩa một qui tắc viết lại, các bài viết sản phẩm có slug là my_product.
Chúng ta trình bày hai loại post trên trang đầu, bao gồm các bài viết thông thường và bài viết sản phẩm:

function my_product_add_custom_post_types($query)
{
    if (is_home() && $query->is_main_query()) {
        $query->set('post_type', ['post', 'my_product']);
    }
    return $query;
}
add_action('pre_get_posts', 'my_product_add_custom_post_types');

Nếu muốn chỉ trình bày các bài viết sản phẩm, bạn bỏ 'post' ra khỏi danh sách.
Bây giờ thêm hộp meta cho kiểu post sản phẩm:

function my_product_custom_meta() {
    if ($GLOBALS['mylang'])
        add_meta_box( 'my_product_meta', __( 'Product data', 'myproduct' ), 'my_product_meta_callback', 'my_product' );
    else
        add_meta_box( 'my_product_meta', __( 'Product data - false', 'myproduct' ), 'my_product_meta_callback', 'my_product' );
}
add_action( 'add_meta_boxes', 'my_product_custom_meta' );

Hàm callback mà trình bày hộp meta như dưới đây, mã hơi dài nhưng kết quả của nó chỉ là một hộp meta với các mục nhập như hình bên trên:

function my_product_meta_callback( $post ) {
    wp_nonce_field( basename( __FILE__ ), 'my_product_nonce' );

    $my_product_stored_meta = get_post_meta( $post->ID );
    ?>

    <p>
        <label for="price" class="my_product-row-title"><?php _e( 'Price', 'myproduct' )?></label>
        <input type="text" name="price" id="price" value="<?php
            if ( isset ( $my_product_stored_meta['price'] ) )
                echo $my_product_stored_meta['price'][0]; ?>" />
        <?php
        $options = get_option( 'my_product_setting_options' );
        $currency = $options['my_product_setting_field_currency'];
        switch ( $currency ) {
            case 'usd':
                echo 'usd';
                break;
            case 'vnd':
                echo 'đ';
                break;
        }

        ?>

    </p>
    <p>
        <label for="shipping" class="my_product-row-title"><?php _e( 'Shipping', 'myproduct' )?></label>
        <input type="text" name="shipping" id="shipping" value="<?php
            if ( isset ( $my_product_stored_meta['shipping'] ) )
                echo $my_product_stored_meta['shipping'][0]; ?>" />
    </p>

    <p>
        <span class="my_product-row-title"><?php _e( 'Options', 'myproduct' )?></span>
        <div class="my_product-row-content">
            <label for="stock-checkbox">
                <input type="checkbox" name="stock-checkbox" id="stock-checkbox" value="yes" <?php if ( isset ( $my_product_stored_meta['stock-checkbox'] ) ) checked( $my_product_stored_meta['stock-checkbox'][0], 'yes' ); ?> />
                <?php _e( 'Enable stock management', 'myproduct' )?>
            </label>
            <label for="reviews-checkbox">
                <input type="checkbox" name="reviews-checkbox" id="reviews-checkbox" value="yes" <?php if ( isset ( $my_product_stored_meta['reviews-checkbox'] ) ) checked( $my_product_stored_meta['reviews-checkbox'][0], 'yes' ); ?> />
                <?php _e( 'Enable reviews', 'myproduct' )?>
            </label>
        </div>
    </p>

    <p>
        <span class="my_product-row-title"><?php _e( 'Size', 'myproduct' )?></span>
        <div class="my_product-row-content">
            <label for="big-radio">
                <input type="radio" name="size-radio" id="big-radio" value="big-radio" <?php if ( isset ( $my_product_stored_meta['size-radio'] ) ) checked( $my_product_stored_meta['size-radio'][0], 'big-radio' ); ?>>
                <?php _e( 'Big', 'myproduct' )?>
            </label>
            <label for="small-radio">
                 <input type="radio" name="size-radio" id="small-radio" value="small-radio" <?php if ( isset ( $my_product_stored_meta['size-radio'] ) ) checked( $my_product_stored_meta['size-radio'][0], 'small-radio' ); ?>>
                 <?php _e( 'Small', 'myproduct' )?>
            </label>
        </div>
    </p>

    <p>
        <label for="product-type" class="my_product-row-title"><?php _e( 'Product type', 'myproduct' )?></label>
        <select name="product-type" id="product-type">
            <option value="downloadable" <?php if ( isset ( $my_product_stored_meta['product-type'] ) ) selected( $my_product_stored_meta['product-type'][0], 'downloadable' ); ?>><?php _e( 'Downloadable', 'myproduct' )?></option>';
            <option value="physical-inventory" <?php if ( isset ( $my_product_stored_meta['product-type'] ) ) selected( $my_product_stored_meta['product-type'][0], 'physical-inventory' ); ?>><?php _e( 'Physical inventory', 'myproduct' )?></option>';
        </select>
    </p>

    <p>
        <label for="product-description" class="my_product-row-title"><?php _e( 'Product description', 'myproduct' )?></label>
        <textarea name="product-description" id="product-description"><?php if ( isset ( $my_product_stored_meta['product-description'] ) ) echo $my_product_stored_meta['product-description'][0]; ?></textarea>
    </p>

    <p>
        <label for="meta-color" class="my_product-row-title"><?php _e( 'Color Picker', 'myproduct' )?></label>
        <input name="meta-color" type="text" value="<?php if ( isset ( $my_product_stored_meta['meta-color'] ) ) echo $my_product_stored_meta['meta-color'][0]; ?>" class="meta-color" />
    </p>

    <p>
        <label for="meta-image" class="my_product-row-title"><?php _e( 'File Upload', 'myproduct' )?></label>
        <input type="text" name="meta-image" id="meta-image" value="<?php if ( isset ( $my_product_stored_meta['meta-image'] ) ) echo $my_product_stored_meta['meta-image'][0]; ?>" />
        <input type="button" id="meta-image-button" class="button" value="<?php _e( 'Choose or Upload an Image', 'myproduct' )?>" />
    </p>

    <?php

}

Trường nonce là một trường ẩn trên form nhập, dùng để xác nhận đầu vào để đảm bảo trong hầu hết các trường hợp, nội dung form đến từ site hiện hành. Mọi nội dung trên form đều rõ ràng, ngoại trừ biến $currency lấy kiểu tiền tệ từ trang lựa chọn mà chúng ta sẽ xây dựng trong bài sau.
Chúng ta định nghĩa một hàm giữ kết quả hộp meta cho bài viết khi người sử dụng ấn “Cập nhật”. Đây là chỗ mà trường nonce được kiểm tra:

function my_product_meta_save( $post_id ) {

    // Checks save status
    $is_autosave = wp_is_post_autosave( $post_id );
    $is_revision = wp_is_post_revision( $post_id );
    $is_valid_nonce = ( isset( $_POST[ 'my_product_nonce' ] ) && wp_verify_nonce( $_POST[ 'my_product_nonce' ], basename( __FILE__ ) ) ) ? 'true' : 'false';

    // Exits script depending on save status
    if ( $is_autosave || $is_revision || !$is_valid_nonce ) {
        return;
    }

    // Checks for input and sanitizes/saves if needed
    if( isset( $_POST[ 'price' ] ) ) {
        update_post_meta( $post_id, 'price', sanitize_text_field( $_POST[ 'price' ] ) );
    }

    if( isset( $_POST[ 'shipping' ] ) ) {
        update_post_meta( $post_id, 'shipping', sanitize_text_field( $_POST[ 'shipping' ] ) );
    }

    if( isset( $_POST[ 'stock-checkbox' ] ) ) {
        update_post_meta( $post_id, 'stock-checkbox', 'yes' );
    } else {
        update_post_meta( $post_id, 'stock-checkbox', '' );
    }

    if( isset( $_POST[ 'reviews-checkbox' ] ) ) {
        update_post_meta( $post_id, 'reviews-checkbox', 'yes' );
    } else {
        update_post_meta( $post_id, 'reviews-checkbox', '' );
    }

    if( isset( $_POST[ 'size-radio' ] ) ) {
        update_post_meta( $post_id, 'size-radio', $_POST[ 'size-radio' ] );
    }

    if( isset( $_POST[ 'product-type' ] ) ) {
        update_post_meta( $post_id, 'product-type', $_POST[ 'product-type' ] );
    }

    if( isset( $_POST[ 'product-description' ] ) ) {
        update_post_meta( $post_id, 'product-description', $_POST[ 'product-description' ] );
    }

    if( isset( $_POST[ 'meta-color' ] ) ) {
        update_post_meta( $post_id, 'meta-color', $_POST[ 'meta-color' ] );
    }

    if( isset( $_POST[ 'meta-image' ] ) ) {
        update_post_meta( $post_id, 'meta-image', $_POST[ 'meta-image' ] );
    }

}
add_action( 'save_post', 'my_product_meta_save' );

Hộp meta sử dụng stylesheet, chúng ta thêm stylesheet cho nó:

function my_product_admin_styles(){
    global $typenow;
    if( $typenow == 'my_product' ) {
        wp_enqueue_style( 'my_product_styles', plugin_dir_url( __FILE__ ) . 'my_product-styles.css' );
    }
}
add_action( 'admin_print_styles', 'my_product_admin_styles' );

Ngoài ra, tải hai kịch bản javascript để chọn màu và quản lý ảnh trong hộp meta:

function my_product_color_enqueue() {
    global $typenow;
    if( $typenow == 'my_product' ) {
        wp_enqueue_style( 'wp-color-picker' );
        wp_enqueue_script( 'my_product-color-js', plugin_dir_url( __FILE__ ) . 'my_product-color.js', array( 'wp-color-picker' ) );
    }
}
add_action( 'admin_enqueue_scripts', 'my_product_color_enqueue' );

function my_product_image_enqueue() {
    global $typenow;
    if( $typenow == 'my_product' ) {
        wp_enqueue_media();

        // Registers and enqueues the required javascript.
        wp_register_script( 'my_product-image', plugin_dir_url( __FILE__ ) . 'my_product-image.js', array( 'jquery' ) );
        wp_localize_script( 'my_product-image', 'meta_image',
            array(
                'title' => __( 'Choose or Upload an Image', 'myproduct' ),
                'button' => __( 'Use this image', 'myproduct' ),
            )
        );
        wp_enqueue_script( 'my_product-image' );
    }
}
add_action( 'admin_enqueue_scripts', 'my_product_image_enqueue' );

Các tệp stylesheet và kịch bản javascript trong thư mục plugin lần lượt có nội dung như sau:

my_product-styles.css

.my_product-row-title{
    display: block;
    float: left;
    width: 200px;
}

.my_product-row-content{
    float: left;
    padding-bottom: 1em;
}

.my_product-row-content label{
    display: block;
    line-height: 1.75em;
}

my_product-color.js

jQuery(document).ready(function($){
    $('.meta-color').wpColorPicker();
});

my_product-image.js

jQuery(document).ready(function($){

    // Instantiates the variable that holds the media library frame.
    var meta_image_frame;

    // Runs when the image button is clicked.
    $('#meta-image-button').click(function(e){

        // Prevents the default action from occuring.
        e.preventDefault();

        // If the frame already exists, re-open it.
        if ( meta_image_frame ) {
            meta_image_frame.open();
            return;
        }

        // Sets up the media library frame
        meta_image_frame = wp.media.frames.meta_image_frame = wp.media({
            title: meta_image.title,
            button: { text: meta_image.button },
            library: { type: 'image' }
        });

        // Runs when an image is selected.
        meta_image_frame.on('select', function(){

            // Grabs the attachment selection and creates a JSON representation of the model.
            var media_attachment = meta_image_frame.state().get('selection').first().toJSON();

            // Sends the attachment URL to our custom image input field.
            $('#meta-image').val(media_attachment.url);
        });

        // Opens the media library frame.
        meta_image_frame.open();
    });
});

Khi người sử dụng ấn “Chọn màu”, hộp chọn màu sẽ được trình bày


Khi người sử dụng ấn “Chọn hay tải lên một ảnh”, cửa sổ chọn ảnh xuất hiện. URL của ảnh được chọn được lưu vào hộp văn bản bên trái để phục vụ trình bày ảnh của sản phẩm sau đó trong khuôn mẫu của trang sản phẩm đơn.

Advertisements

Gửi phản hồi

Website này sử dụng Akismet để hạn chế spam. Tìm hiểu bình luận của bạn được duyệt như thế nào.

%d bloggers like this: