WordPress / woocommerce: добавить выпадающий список (где вы нас нашли?) При оформлении заказа + создать панель управления с Chart.js - PullRequest
1 голос
/ 20 ноября 2019

Я новичок в PHP / JS, и мне нравится больше узнавать о кодировании. Сегодня мне нужна ваша помощь (довольно, пожалуйста!)

В настоящее время я пытаюсь добавить опцию выпадающего меню на кассе Woocommerce, чтобы посетители могли сказать, где они нас нашли. Поэтому я использовал фрагмент, который программист уже написал, и немного его подправил. Единственное, что сильно отличало мой веб-сайт от его, было то, что он использовал Polylang, а я - нет (одноязычный веб-сайт).

Все работает, за исключением того, что на панели администратора не отображается нужная информация: https://i.imgur.com/JYLmTaz.png

В моих заказах я ожидаю только одну запись (1x "Bouche à oreille"). Не то.

Вот что я сделал, чтобы получить такой результат:

FUNCTIONS.PHP

    /**

add_action('admin_enqueue_scripts', 'kantaloup_admin_enqueue');
function kantaloup_admin_enqueue()
{
    //wp_enqueue_style('kantaloup', get_template_directory_uri() . '/style.css');
    wp_enqueue_script('chart', get_stylesheet_directory_uri() . '/js/Chart.bundle.min.js');

}

 function get_order_references_fields($return = '')
{
    if($return == 'keys'){
        return array(
            ('Bouche à oreille'),
            ('Médias sociaux'),
            ('Moteurs de recherche (Google, Bing...)'),
            ('Livre/Magazine'),
            ('Partenaire'),
            ('Autre'),
        );
    }

    return array(
        ('Bouche à oreille') => 'Bouche à oreille',
        ('Médias sociaux') => 'Médias sociaux',
        ('Moteurs de recherche (Google, Bing...)') => 'Moteurs de recherche (Google, Bing...)',
        ('Livre/Magazine') => 'Livre/Magazine',
        ('Partenaire') => 'Partenaire',
        ('Autre') => 'Autre',
    );
}


/*
 * Checkout fields: Add
 */
add_action('woocommerce_checkout_fields', 'custom_fields_at_checkout');
function custom_fields_at_checkout($fields)
{

    $fields['billing']['referred_by'] = array(
        'label'     => __('Où nous avez-vous entendu parler de nous?'),
        'placeholder'   => '',
        'required'  => true,
        'class'     => array('referred-by-checkout-field-input form-row-wide'),
        'clear'     => true,
        'type' => 'select',
        'options' => get_order_references_fields()
    );

    return $fields;

}

/*
 * Checkout fields: Validate
 */
/*
add_action('woocommerce_checkout_process', 'custom_fields_at_checkout_validate');
function custom_fields_at_checkout_validate()
{
    if(! $_POST['referred-by']){
        wc_add_notice(__('Veuillez remplir le champ «Où nous avez-vous entendu parler de nous?»'), 'error');
    }
}
*/

/*
 * Checkout fields: Add to order meta
 */
add_action('woocommerce_checkout_update_order_meta', 'custom_fields_at_checkout_add_to_order_meta');
function custom_fields_at_checkout_add_to_order_meta($order_id)
{
    if(! empty($_POST['referred_by']) )
    {
        update_post_meta($order_id, 'referred_by', sanitize_text_field($_POST['referred_by']) );
    }
}

/*
 * Checkout fields: Add to order admin page
 */
add_action('woocommerce_admin_order_data_after_billing_address', 'custom_fields_at_checkout_add_to_order_admin_page', 10, 1);
function custom_fields_at_checkout_add_to_order_admin_page($order)
{
    echo '<p><strong>' . __('Où nous avez-vous entendu parler de nous?') . ' :</strong><br>' . get_post_meta($order->id, 'refered_by', true) . '</p>';
}

/*
 * Add admin page for support tab
 */

add_action('admin_menu', 'create_order_report_admin_menu');
function create_order_report_admin_menu()
{
    $title = "Rapport de références";
    add_menu_page($title, $title, 'manage_options', 'sales-type-report', 'sales_type_report', '', '3.1');

    function sales_type_report()
    {
        include(get_stylesheet_directory() . '/includes/admin/sales-report.php');
    }
}

/*
 * Get order references and return json object
 */
function get_order_references_json()
{
    $references = get_order_references_fields();

    /*
     * Build the labels
     */
    $the_labels = [];
    foreach($references as $slug => $label)
    {
        $the_labels[] = $label;
    }

    /*
     * Build the datasets
     */
    $the_datasets = [];
    $this_dataset = new stdClass();

    $this_dataset->label = ['Nombre de commandes'];
    $this_dataset->backgroundColor = ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686', '#0B486B', '#1B6995', '#1E81B9', '#88AABD'];
    $this_dataset->borderColor = ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686', '#0B486B', '#1B6995', '#1E81B9', '#88AABD'];
    $this_dataset->borderWidth = 2;

    $orders = get_posts(
        array(
            'post_type' => 'shop_order',
            'posts_per_page' => -1,
            'post_status' => 'closed, wc-on-hold'
        )
    );

    if( empty($orders) ) return;

    $the_datasets_bars = [];
    foreach($orders as $order){
        $reference_meta = get_post_meta($post->ID, 'referred_by', true);

        if(! empty($reference_meta) ){

            foreach($references as $slug => $label)
            {
                if($slug == $reference_meta){
                    $the_datasets_bars[$slug] = ! isset($the_datasets_bars[$slug]) ? 0 : ++$the_datasets_bars[$slug];
                }
            }
        }
    }

    $correct_order = get_order_references_fields('keys');
    $correctly_ordered_dataset_bars = array_merge(array_flip($correct_order), $the_datasets_bars);

    $this_dataset->data = array_values($correctly_ordered_dataset_bars);

    $the_datasets[] = $this_dataset;

    /*
     * Build the final array
     */
    $data = array(
        'labels' => $the_labels,
        'datasets' => $the_datasets
    );

    return json_encode($data);
}

В включает / admin /sales-report.php:

<style>
    .sep{
        margin:40px 0;
    }
    .excerpt:after {
        content: "";
        display: table;
        clear: both;
    }
    .excerpt img{
        display:block;
        margin: 30px 0;
        max-width: 1024px;
        width: auto;
        border: 1px solid #ddd;
        padding: 10px;
        background: #fff;
    }
    .top{
        float:right;
    }
    ol ol{
        margin-top: 10px;
    }
</style>

<script>
    (function($){
        $(document).ready(function () {

            var ctx = $('#the-sales-references-table');
            var myChart = new Chart(ctx, {
                type: 'bar',
                data: <?= get_order_references_json(); ?>,
                options: {
                    scales: {
                        yAxes: [{
                            ticks: {
                                beginAtZero: true
                            }
                        }]
                    }
                }
            });
        });
    }(jQuery));
</script>

<div class="wrap">
    <h1>Rapport des références sur les commandes</h1>

    <div class="wrap">
        <canvas id="the-sales-references-table"></canvas>
    </div>

    <? get_order_references_json(); ?>
</div>

Я также добавил chart.js в дочернюю тему (эта часть работает). Большое спасибо за вашу помощь

1 Ответ

2 голосов
/ 21 ноября 2019

После проверки и тестирования вашего кода, вот несколько моментов, которые привели к проблеме, которую вы идентифицируете на скриншоте.

  1. Массив данных, переданных в диаграмму, был пуст, чтопочему у вас есть этот «лестничный» узор. Похоже, что ChartJS.org отображает данные, когда они пустые (возможно, по умолчанию используются некоторые внутренние данные).

  2. Данные были пустыми, потому что невозможно напрямую передать функцию PHPв JavaScript (data: <?= get_order_references_json(); ?>). При тестировании в браузере переменная data была пустой и вызвала ошибку. Вместо этого я использовал WordPress wp_localize_script, чтобы заранее запустить функцию в PHP, а затем передать данные json_encoded как переменную JS. Используя этот подход, можно затем JSON.parse переменную JS непосредственно в переменной data. Если бы в игре было больше данных, было бы лучше использовать AJAX-запросы к выделенным функциям PHP.

  3. Даже если бы данные не были пустыми, вы все равно получили бы «лестничную» формушаблон, потому что, если бы присутствовало только несколько «ссылок», остальные были бы пустыми и, следовательно, вызывали бы «лестничную» модель. Чтобы исправить это, я предварительно заполняю массив нулями (0) во всех слотах перед их назначением. $the_datasets_bars = array_fill_keys(array_keys($references), 0); Это работает.

  4. Было исправлено несколько мелких проблем, которые мешали запуску кода в моей тестовой среде WP.

Вот модифицированный код с комментариями во ВСЕХ КОПИЯХ:

functions.php

<?php
/**
 * Plugin Name: My Plugin
 * Description: Custom features.
 * Version: 2019.1.0.0
 */

 /*
 * kantaloup enqueue
 */
add_action('admin_enqueue_scripts', 'kantaloup_admin_enqueue');
function kantaloup_admin_enqueue()
{
    //wp_enqueue_style('kantaloup', get_template_directory_uri() . '/style.css');
    wp_enqueue_script('chart', plugin_dir_url(__FILE__) . 'js/Chart.bundle.min.js');

    // FIX: need to pass the data to the client-side so they can be accessible via JS
    wp_localize_script('chart', 'test', array(
        'data' => get_order_references_json()
    ));
}

function get_order_references_fields($return = '')
{
    if($return == 'keys'){
        return array(
            ('Bouche à oreille'),
            ('Médias sociaux'),
            ('Moteurs de recherche (Google, Bing...)'),
            ('Livre/Magazine'),
            ('Partenaire'),
            ('Autre'),
        );
    }

    return array(
        ('Bouche à oreille') => 'Bouche à oreille',
        ('Médias sociaux') => 'Médias sociaux',
        ('Moteurs de recherche (Google, Bing...)') => 'Moteurs de recherche (Google, Bing...)',
        ('Livre/Magazine') => 'Livre/Magazine',
        ('Partenaire') => 'Partenaire',
        ('Autre') => 'Autre',
    );
}


/*
 * Checkout fields: Add
 */
add_action('woocommerce_checkout_fields', 'custom_fields_at_checkout');
function custom_fields_at_checkout($fields)
{

    $fields['billing']['referred_by'] = array(
        'label'     => __('Où nous avez-vous entendu parler de nous?'),
        'placeholder'   => '',
        'required'  => true,
        'class'     => array('referred-by-checkout-field-input form-row-wide'),
        'clear'     => true,
        'type' => 'select',
        'options' => get_order_references_fields()
    );

    return $fields;

}

/*
 * Checkout fields: Validate
 */
/*
add_action('woocommerce_checkout_process', 'custom_fields_at_checkout_validate');
function custom_fields_at_checkout_validate()
{
    if(! $_POST['referred-by']){
        wc_add_notice(__('Veuillez remplir le champ «Où nous avez-vous entendu parler de nous?»'), 'error');
    }
}
*/

/*
 * Checkout fields: Add to order meta
 */
add_action('woocommerce_checkout_update_order_meta', 'custom_fields_at_checkout_add_to_order_meta');
function custom_fields_at_checkout_add_to_order_meta($order_id)
{
    if(! empty($_POST['referred_by']) )
    {
        update_post_meta($order_id, 'referred_by', sanitize_text_field($_POST['referred_by']) );
    }
}

/*
 * Checkout fields: Add to order admin page
 */
add_action('woocommerce_admin_order_data_after_billing_address', 'custom_fields_at_checkout_add_to_order_admin_page', 10, 1);
function custom_fields_at_checkout_add_to_order_admin_page($order)
{
    // FIX: there was an error accessing $order->id; need to use the get_id() 
    echo '<p><strong>' . __('Où nous avez-vous entendu parler de nous?') . ' :</strong><br>' . get_post_meta($order->get_id(), 'referred_by', true) . '</p>';
}

/*
 * Add admin page for support tab
 */

add_action('admin_menu', 'create_order_report_admin_menu');
function create_order_report_admin_menu()
{
    $title = "Rapport de références";
    add_menu_page($title, $title, 'manage_options', 'sales-type-report', 'sales_type_report', '', '3.1');
}
// FIX: separated the function to be outside of the above function
function sales_type_report()
{
    include('includes/admin/sales-report.php');
}

/*
 * Get order references and return json object
 */
function get_order_references_json()
{
    $references = get_order_references_fields();

    /*
     * Build the labels
     */
    $the_labels = [];
    foreach($references as $slug => $label)
    {
        $the_labels[] = $label;
    }

    /*
     * Build the datasets
     */
    $the_datasets = [];
    $this_dataset = new stdClass();

    $this_dataset->label = ['Nombre de commandes'];
    $this_dataset->backgroundColor = ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686', '#0B486B', '#1B6995', '#1E81B9', '#88AABD'];
    $this_dataset->borderColor = ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686', '#0B486B', '#1B6995', '#1E81B9', '#88AABD'];
    $this_dataset->borderWidth = 2;

    $orders = get_posts(
        array(
            'post_type' => 'shop_order',
            'posts_per_page' => -1, // required to allow >5 results
            'post_status' => array_keys( wc_get_order_statuses() )
        )
    );

    // print_r($orders);

    if( empty($orders) ) return;

    // FIX: (fill in all keys; otherwise, we get the stair effect)
    $the_datasets_bars = array_fill_keys(array_keys($references), 0);

    foreach($orders as $order){
        // FIX: MUST be $order->ID (Post->ID), not 'id'
        $reference_meta = get_post_meta($order->ID, 'referred_by', true);
        echo $reference_meta . "\n";

        if(! empty($reference_meta) ){

            foreach($references as $slug => $label)
            {
                if($slug == $reference_meta){
                    $the_datasets_bars[$slug] = ! isset($the_datasets_bars[$slug]) ? 0 : ++$the_datasets_bars[$slug];
                }
            }
        }
    }

    // FIX: some debug logs
    echo "THE_DATASETS_BARS\n";
    print_r($the_datasets_bars);
    echo "\n";

    $correct_order = get_order_references_fields('keys');
    $correctly_ordered_dataset_bars = array_merge(array_flip($correct_order), $the_datasets_bars);

    $this_dataset->data = array_values($correctly_ordered_dataset_bars);

    $the_datasets[] = $this_dataset;

    /*
     * Build the final array
     */
    $data = array(
        'labels' => $the_labels,
        'datasets' => $the_datasets
    );

    // FIX: added JSON_UNESCAPED_UNICODE; otherwise, French accents are mishandled
    return json_encode($data, JSON_UNESCAPED_UNICODE);
}

включает/admin/sales-report.php

<style>
    .sep{
        margin:40px 0;
    }
    .excerpt:after {
        content: "";
        display: table;
        clear: both;
    }
    .excerpt img{
        display:block;
        margin: 30px 0;
        max-width: 1024px;
        width: auto;
        border: 1px solid #ddd;
        padding: 10px;
        background: #fff;
    }
    .top{
        float:right;
    }
    ol ol{
        margin-top: 10px;
    }
</style>

<script>
    let $ = jQuery
    // FIX: the way this method was launched caused problems when loading in browser;
    // there were nested 'document.ready' functions
    $(function() {
        console.warn("data", test);

        var ctx = $('#the-sales-references-table');
        console.info(ctx);
        var myChart = new Chart(ctx[0].getContext('2d'), {
            type: 'bar',
            // FIX: parse data from the PHP-generated JS data variable
            data: JSON.parse(test.data),
            options: {
                scales: {
                    yAxes: [{
                        ticks: {
                            beginAtZero: true
                        }
                    }]
                }
            }
        });
    })
</script>

<div class="wrap">
    <h1>Rapport des références sur les commandes</h1>

    <div class="wrap">
        <canvas id="the-sales-references-table"></canvas>
    </div>

    <!-- FIX (remove the PHP function) -->
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...