WooCommerce

نسخه جاری 5.1.0

در این راهنما نحوه استفاده از نقشه Leaflet در افزونه فروشگاه ساز WooCommerce که برای WordPress ارائه شده، توضیح خواهد یافت.

اقدامات اولیه

در این راهنما نحوه ساخت افزونه‌ای با قابلیت داشتن نقشه برای WooCommerce آموزش می‌یابد. در بخش checkout یا پرداخت، بخشی برای انتخاب دقیق مکان کاربر از طریق جستجو (افزونه جستجوی آدرس) و یا کلیک بروی نقشه، اضافه می‌شود که کاربر از طریق آن می‌تواند مکان مورد نظر خود را انتخاب کند و داده ها پس از تغییر موقعیت، توسط فیلدهایی که در ادامه شرح داده می‌شوند، به سرور جهت ذخیره ارسال و نمایش خواهند یافت، این اطلاعات جغرافیایی در سفارش کاربر ذخیره و در بخش admin order data یا مدیریت و نمایش جزئیات مربوط به سفارش قرار می‌یابند، نقطه انتخابی کاربر به همراه نشانگر تعیین موقعیت انتخاب شده به همراه فیلدهای مربوط به موقعیت جغرافیایی نیز در همان بخش نیز نمایش خواهد یافت.

برای نوشتن افزونه لازم است که یک فایل PHP را ایجاد کنید، سپس این فایل را درون پوشه‌ای تحت همین نام قرار دهید. برای نمونه اگر فایل شما test.php است، این فایل را درون پوشه‌ای با نام test قرار داده و کدهای موجود در راهنمای زیر باید درون این فایل قرار یابند.

هر افزونه در ورد پرس دارای یک header است که این سربرگ شامل داده های اولیه‌ای است که وردپرس از طریق دستیابی به آنها قادر است که نام افزونه و سایر جزییات مربوط به آن را نمایش داده و به عبارت دیگر آنرا به عنوان یک افزونه در نظر بگیرد، در صورت وجود نداشتن این بخش طبیعتا فایل برای افزوده شدن به عنوان افزونه نامعتبر خواهد بود. کدهای زیر باید در ابتدایی ترین بخش فایل PHP و پس از عبارت <?php قرار یابد.

<?php
/**
 * Plugin Name: پارسی‌مپ برای ووکامرس
 * Plugin URI: https://docs.parsimap.ir/wordpress/woocommerce
 * Description: ابزاری برای افزودن نقشه و انتخابگر آدرس به فروشگاه ساز ووکامرس
 * Version: 1.0.0
 * License: GPL2
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: parsimap-wooccomerce
 * 
 * Requires at least: 5.5
 * Requires PHP: 7.0
 *
 * @package Parsimap
 */

ملاحظات امنیتی

در صورتیکه مایل هستید که افزونه ایجاد شده از طریق دسترسی مستقیم به فایل، قابل دستیابی نباشد. کد زیر را باید در ابتدای کدهای اصلی خود قرار دهید.

if (!defined('ABSPATH')) {
  exit;
}

بررسی فعال بودن افزونه

بهتر است قبل از نوشتن کدهای افزونه ابتدا از فعال بودن افزونه WooCommerce مطلع شد و سایر کدهای دیگر را درون بلوکه کد زیر قرار داده شود.

if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
  // Write code here
}

فراخوانی فایل‌های asset خارجی

کد زیر را به منظور افزودن فایل‌های خارجی JavaScript و CSS مربوط به نقشه، اضافه کنید. توسط اکشن‌های wp_head و admin_head فراخوانی فایل‌های خارجی، درون تگ head صفحات بخش کاربری و مدیریت انجام می‌شود.

add_action('wp_head', 'hook_external_assets_files');
add_action('admin_head', 'hook_external_assets_files');

function hook_external_assets_files()
{
  echo '
    <script src="https://cdn.parsimap.ir/third-party/leaflet/v1.7.1/leaflet.js"></script>
    <link href="https://cdn.parsimap.ir/third-party/leaflet/v1.7.1/leaflet.css" rel="stylesheet" />
    <script src="https://cdn.parsimap.ir/third-party/leaflet/plugins/parsimap-tile/v1.0.0/parsimap-tile.js"></script>
    <script src="https://cdn.parsimap.ir/third-party/leaflet/plugins/parsimap-geocoder/v1.0.0/parsimap-geocoder.js"></script>
    <link href="https://cdn.parsimap.ir/third-party/leaflet/plugins/parsimap-geocoder/v1.0.0/parsimap-geocoder.css" rel="stylesheet" />
  ';
}

اکشن‌های بخش پرداخت

wp-checkout

با پیاده‌سازی اکشن های موجود در این بخش یک نقشه به همراه سه فیلد در بخش پرداخت نمایش می‌یابد که با کلیک بروی نقشه و یا جستجوی آدرس در کادر متنی، هنگام کلیک بروی دیگر اجزای صفحه و ثبت سفارش جزئیات جغرافیایی در فیلدهای مربوطه نمایش خواهد یافت و اطلاعات نیز به سمت سرور جهت ذخیره شدن در دیتابیس ارسال خواهد شد.

افزودن انتخابگر موقعیت جغرافیایی

کد زیر را برای نمایش نقشه و توضیحات مربوط به آن، اضافه کنید. توسط اکشن woocommerce_after_checkout_billing_form کدهای جاوااسکریپت و HTML مربوط به ایجاد نقشه در بخش پرداخت اجرا می‌شوند و موقعیت نقشه پس از فیلدهای اطلاعات کاربر خواهد بود.

add_action('woocommerce_after_checkout_billing_form', 'hook_mapview_after_checkout_billing_form');

function hook_mapview_after_checkout_billing_form()
{
  echo '
  <h2>آدرس جغرافیایی</h2>
  <label style="text-align: justify;">
    با کلیک بروی نقشه و یا جستجو
    در کادر مربوطه آدرس دقیق خود را انتخاب کنید.
  </label>
  <div id="map" style="height: 400px; width: 100%;"></div>

  <script>
    /** See https://docs.parsimap.ir/javascript/leaflet#add-map-to-website */
    const map = new L.Map("map", {
      center: [35.75, 51.41],
      zoom: 6,
      zoomControl: false
    })

    L.parsimapTileLayer("parsimap-streets-v11-raster", {
      key: "PMI_MAP_TOKEN",
      service: true,
    }).addTo(map)

    const control = new ParsimapGeocoder()
    map.addControl(control)

    map.on("blur", function() {
      const latitudeInput = document.querySelector("#pmi_latitude")
      const longitudeInput = document.querySelector("#pmi_longitude")
      const addressInput = document.querySelector("#pmi_address")

      /** See https://docs.parsimap.ir/plugins/geocode/parsimap-geocoder#user-manual */
      control.reverseLocation().then((reverse) => {
        const lngLat = reverse.lngLat
        const address = reverse.address

        latitudeInput.value = lngLat.lat
        longitudeInput.value = lngLat.lng
        addressInput.value = address
      })
    })
  </script>
';
}

افزودن فیلدهای جغرافیایی

با اضافه کردن کد زیر پس انتخاب یک مکان بروی نقشه و یا جستجوی آدرس هنگامی که بروی جایی غیر از نقشه کلیک شود اطلاعات مربوط به نقطه انتخاب شده در این فیلدها نمایش می‌یابد. توسط اکشن woocommerce_after_checkout_billing_form فیلدهای جغرافیایی دقیقاً پایین تر از نقشه در بخش پرداخت نمایش خواهند یافت.

add_action('woocommerce_after_checkout_billing_form', 'hook_geolocation_fields_after_checkout_billing_form');

function hook_geolocation_fields_after_checkout_billing_form($checkout)
{
  echo '<div class="woocommerce-billing-fields__field-wrapper">';

  woocommerce_form_field('pmi_latitude', array(
    'type'          => 'text',
    'class'         => array('form-row-wide'),
    'label'         => __('Latitude'),
  ), $checkout->get_value('pmi_latitude'));

  woocommerce_form_field('pmi_longitude', array(
    'type'          => 'text',
    'class'         => array('form-row-wide'),
    'label'         => __('Longitude'),
  ), $checkout->get_value('pmi_longitude'));

  woocommerce_form_field('pmi_address', array(
    'type'          => 'text',
    'class'         => array('form-row-wide'),
    'label'         => __('Position'),
  ), $checkout->get_value('pmi_address'));

  echo '</div>';
}

شما می‌توانید فیلدهای حاوی اطلاعات جغرافیایی را به صورت مخفی در بخش پرداخت قرار دهید که برای این منظور خصوصیت type مربوط به هر فیلد باید بجای text با عبارت hidden جایگزین شود. در کد بالا فیلدها تنها برای نمایش اطلاعات جغرافیایی به صورت فیلد متنی قرار یافته اند وبهتر مقادیر این فیلدها به صورت خودکار توسط کد جاوااسریپت تعیین شود و به صورت readonly قرار در بخش پرداخت قرار یافته یا hidden باشند.

 woocommerce_form_field('pmi_longitude', array(
  'type'          => 'hidden',
  'class'         => array('form-row-wide'),
  'label'         => __('Longitude'),
), $checkout->get_value('pmi_longitude'));

بروزرسانی فیلدهای ارسالی به سرور

با اضافه کردن کد زیر اطلاعات مربوط به طول و عرض و آدرس جغرافیایی به همراه سایر اطلاعات دیگر سفارش به سمت سرور برای ذخیره شدن در پایگاه داده، اضافه می‌گردد و به عبارتی دیگر اطلاعات مربوط به فرم سفارش با داده‌های جغرافیایی بروز می‌شود. با بکارگیری اکشن woocommerce_checkout_update_order_meta می‌توان قبل ارسال نهایی داده ها اطلاعات مربوط به درخواست که با متد POST ارسال می‌گردد را بروز رسانی کرده و یا تغییر داد. برای اجتناب از ارسال مقادیر تهی یا null در ابتدا می‌توان بررسی نمود که مقادیر وجود دارند سپس آن را به بدنه درخواست اضافه نمود در این قسمت همچنین می‌توان عملیات مربوط به اعتبارسنجی مقادیر را نیز به انجام رساند.

add_action('woocommerce_checkout_update_order_meta', 'hook_checkout_update_order_meta_with_geolocation');

function hook_checkout_update_order_meta_with_geolocation($order_id)
{
  if (!empty($_POST['pmi_latitude'])) {
    update_post_meta($order_id, 'pmi_latitude', sanitize_text_field($_POST['pmi_latitude']));
  }

  if (!empty($_POST['pmi_longitude'])) {
    update_post_meta($order_id, 'pmi_longitude', sanitize_text_field($_POST['pmi_longitude']));
  }

  if (!empty($_POST['pmi_address'])) {
    update_post_meta($order_id, 'pmi_address', sanitize_text_field($_POST['pmi_address']));
  }
}

اکشن‌های جزئیات سفارش

wp-admin-order-data

از طریق اضافه کردن اکشن‌های زیر می‌توان اطلاعات جغرافیایی مربوط سفارش را از طریق نقشه به همراه نشانگر و اطلاعات متنی طول، عرض و آدرس را در بخش جزییات سفارش که در admin واقع است، مشاهده نمود.

نمایش اطلاعات موقعیت جغرافیایی

برای نمایش جزئیات جغرافیایی وارد شده در بخش سفارش که توسط نقشه تعیین شدند کد زیر را اضافه می‌کنیم. توسط اکشن woocommerce_admin_order_data_after_billing_address جزییات جغرافیایی اعم از طول، عرض و آدرس جغرافیایی را به بخش جزییات سفارش و در انتهای آدرس کاربر می‌توان اضافه نمود.

add_action('woocommerce_admin_order_data_after_billing_address', 'hook_geolocation_data_after_billing_address');

function hook_geolocation_data_after_billing_address($order)
{
  echo '<p>';
  echo '<strong>' . __('Latitude') . ':</strong>';
  echo get_post_meta($order->id, 'pmi_latitude', true);
  echo '</p>';
  echo '<p>';
  echo '<strong>' . __('Longitude') . '</strong>';
  echo get_post_meta($order->id, 'pmi_longitude', true);
  echo '</p>';
  echo '<p>';
  echo '<strong>' . __('Position') . '</strong>';
  echo get_post_meta($order->id, 'pmi_address', true);
  echo '</p>';
}

نمایش موقعیت جغرافیایی انتخاب شده

کد زیر را برای نمایش نقشه در بخش جزییات مربوط به سفارش که حاوی نشانگر موقعیت انتخاب شده است، اضافه می‌کنیم. توسط اکشن woocommerce_admin_order_data_after_billing_address کدهای جاوااسکریپت و HTML مربوط به ایجاد نقشه در بخش جزییات مربوط به سفارش اجرا می‌شوند و موقعیت انتخاب شده در سفارش به همراه یک نشانگر بروی نقشه قابل مشاهده است.

add_action('woocommerce_admin_order_data_after_billing_address', 'hook_mapview_after_billing_address');

function hook_mapview_after_billing_address($order)
{
  echo '
   <div id="map" style="height: 200px; width: 100%;"></div>
   <script>
     const center = ['
    . get_post_meta($order->id, 'pmi_latitude', true) . ','
    . get_post_meta($order->id, 'pmi_longitude', true) .
    ']

     /** See https://docs.parsimap.ir/javascript/leaflet#add-map-to-website */
     const map = new L.Map("map", {
       center,
       zoom: 16,
       zoomControl: false
     })

     L.parsimapTileLayer("parsimap-streets-v11-raster", {
       key: "PMI_MAP_TOKEN",
       service: true,
     }).addTo(map)

     const icon = L.icon({
       iconSize: [42, 42],
       iconAnchor: [42 / 2, 42],
       iconUrl: "data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 24 24\' fill=\'%23cc3433\'%3E%3Cpath d=\'M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z\'%3E%3C/path%3E%3C/svg%3E",
     })

     L.marker(center, {
       icon
     }).addTo(map)
   </script>
   ';
}

بررسی نهایی کد

در کد زیر تمامی کدهای شرح داده شده در این راهنما قرار یافته است. تنها تفاوت کدهای این بخش با کدهای شرح داده شده در نحوه استفاده از دستور echo است. در کدهای زیر برای خوانایی بیشتر کدهای PHPو HTML از شکل ساده شده یا shorthand استفاده شده است. برای نمونه ?><?php این قابلیت که از نسخه 5.4 به PHP اضافه شده به شما این امکان را می‌دهد که در هر کجای کد از سمت سرور خارج شده و کدهای HTML یا سمت کلاینت را مستقیم نوشت از این رو از لحاظ مشخص شدن syntax مربوط به بخش کلاینت و خطا یابی کدهای جاوااسکریپت، این کار می‌تواند مفید باشد.

<?php
/**
 * Plugin Name: پارسی‌مپ برای ووکامرس
 * Plugin URI: https://docs.parsimap.ir/wordpress/woocommerce
 * Description: ابزاری برای افزودن نقشه و انتخابگر آدرس به فروشگاه ساز ووکامرس
 * Version: 1.0.0
 * License: GPL2
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: parsimap-wooccomerce
 * 
 * Requires at least: 5.5
 * Requires PHP: 7.0
 *
 * @package Parsimap
 */

if (!defined('ABSPATH')) {
  exit;
}

if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
  add_action('wp_head', 'hook_external_assets_files');
  add_action('admin_head', 'hook_external_assets_files');

  function hook_external_assets_files()
  {
?>
    <script src="https://cdn.parsimap.ir/third-party/leaflet/v1.7.1/leaflet.js"></script>
    <link href="https://cdn.parsimap.ir/third-party/leaflet/v1.7.1/leaflet.css" rel="stylesheet" />
    <script src="https://cdn.parsimap.ir/third-party/leaflet/plugins/parsimap-tile/v1.0.0/parsimap-tile.js"></script>
    <script src="https://cdn.parsimap.ir/third-party/leaflet/plugins/parsimap-geocoder/v1.0.0/parsimap-geocoder.js"></script>
    <link href="https://cdn.parsimap.ir/third-party/leaflet/plugins/parsimap-geocoder/v1.0.0/parsimap-geocoder.css" rel="stylesheet" />
  <?php
  }

  add_action('woocommerce_after_checkout_billing_form', 'hook_mapview_after_checkout_billing_form');

  function hook_mapview_after_checkout_billing_form()
  {
  ?>
    <h3>آدرس جغرافیایی</h3>
    <label style="text-align: justify;">
      با کلیک بروی نقشه و یا جستجو
      در کادر مربوطه آدرس دقیق خود را انتخاب کنید.
    </label>
    <div id="map" style="height: 400px; width: 100%;"></div>

    <script>
      /** See https://docs.parsimap.ir/javascript/leaflet#add-map-to-website */
      const map = new L.Map('map', {
        center: [35.75, 51.41],
        zoom: 6,
        zoomControl: false
      })

      L.parsimapTileLayer('parsimap-streets-v11-raster', {
        key: 'PMI_MAP_TOKEN',
        service: true,
      }).addTo(map)

      const control = new ParsimapGeocoder()
      map.addControl(control)

      map.on('blur', function() {
        const latitudeInput = document.querySelector('#pmi_latitude')
        const longitudeInput = document.querySelector('#pmi_longitude')
        const addressInput = document.querySelector('#pmi_address')

        /** See https://docs.parsimap.ir/plugins/geocode/parsimap-geocoder#user-manual */
        control.reverseLocation().then((reverse) => {
          const lngLat = reverse.lngLat
          const address = reverse.address

          latitudeInput.value = lngLat.lat
          longitudeInput.value = lngLat.lng
          addressInput.value = address
        })
      })
    </script>
  <?php
  }

  add_action('woocommerce_after_checkout_billing_form', 'hook_geolocation_fields_after_checkout_billing_form');

  function hook_geolocation_fields_after_checkout_billing_form($checkout)
  {
  ?>
    <div class="woocommerce-billing-fields__field-wrapper">
      <?php
      woocommerce_form_field('pmi_latitude', array(
        'type'          => 'text',
        'class'         => array('form-row-wide'),
        'label'         => __('Latitude'),
      ), $checkout->get_value('pmi_latitude'));

      woocommerce_form_field('pmi_longitude', array(
        'type'          => 'text',
        'class'         => array('form-row-wide'),
        'label'         => __('Longitude'),
      ), $checkout->get_value('pmi_longitude'));

      woocommerce_form_field('pmi_address', array(
        'type'          => 'text',
        'class'         => array('form-row-wide'),
        'label'         => __('Position'),
      ), $checkout->get_value('pmi_address'));
      ?>
    </div>
  <?php
  }

  add_action('woocommerce_checkout_update_order_meta', 'hook_checkout_update_order_meta_with_geolocation');

  function hook_checkout_update_order_meta_with_geolocation($order_id)
  {
    if (!empty($_POST['pmi_latitude'])) {
      update_post_meta($order_id, 'pmi_latitude', sanitize_text_field($_POST['pmi_latitude']));
    }

    if (!empty($_POST['pmi_longitude'])) {
      update_post_meta($order_id, 'pmi_longitude', sanitize_text_field($_POST['pmi_longitude']));
    }

    if (!empty($_POST['pmi_address'])) {
      update_post_meta($order_id, 'pmi_address', sanitize_text_field($_POST['pmi_address']));
    }
  }

  add_action('woocommerce_admin_order_data_after_billing_address', 'hook_geolocation_data_after_billing_address');

  function hook_geolocation_data_after_billing_address($order)
  {
  ?>
    <p>
      <strong><?= __('Latitude') ?>:</strong>
      <?= get_post_meta($order->id, 'pmi_latitude', true) ?>
    </p>
    <p>
      <strong><?= __('Longitude') ?>:</strong>
      <?= get_post_meta($order->id, 'pmi_longitude', true) ?>
    </p>
    <p>
      <strong><?= __('Position') ?>:</strong>
      <?= get_post_meta($order->id, 'pmi_address', true) ?>
    </p>
  <?php
  }

  add_action('woocommerce_admin_order_data_after_billing_address', 'hook_mapview_after_billing_address');

  function hook_mapview_after_billing_address($order)
  {
  ?>
    <div id="map" style="height: 200px; width: 100%;"></div>
    <script>
      const center = [
        <?= get_post_meta($order->id, 'pmi_latitude', true) ?>,
        <?= get_post_meta($order->id, 'pmi_longitude', true) ?>
      ]

      /** See https://docs.parsimap.ir/javascript/leaflet#add-map-to-website */
      const map = new L.Map('map', {
        center,
        zoom: 16,
        zoomControl: false
      })

      L.parsimapTileLayer('parsimap-streets-v11-raster', {
        key: 'PMI_MAP_TOKEN',
        service: true,
      }).addTo(map)

      const icon = L.icon({
        iconSize: [42, 42],
        iconAnchor: [42 / 2, 42],
        iconUrl: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23cc3433'%3E%3Cpath d='M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z'%3E%3C/path%3E%3C/svg%3E",
      })

      L.marker(center, {
        icon
      }).addTo(map)
    </script>
<?php
  }
}

افزودن افزونه ایجاد شده

شما می‌توانید افزونه نوشته شده را در یک فایل PHP ذخیره کنید. توجه داشته باشید که این فایل را در پوشه‌ای تحت همین نام قرار داده و آنرا به صورت zip فشرده کنید. برای نمونه اگر فایل شما test.phpاست، این فایل را درون پوشه‌ای با نام test قرار داده و پوشه را به صورت یک فایل zip فشرده سازید. همچنین می‌توانید افزونه پارسی‌مپ برای ووکامرس را دانلود کنید. این افزونه به صورت فایل zip تعبیه شده است.

برای استفاده از افزونه ابتدا وارد پنل admin می‌شویم و سپس در قسمت افزونه‌ها، گزینه افزودن را می‌زنیم؛ بروی دکمه بارگزاری افزونه کلیک می‌کنیم و در کادر ظاهر شده فایل zip مربوط به افزونه را انتخاب کرده سپس، دکمه نصب را کلیک می‌کنیم.

پس از نصب افزونه، دکمه فعال کردن افزون راکلیک می‌کنیم. با اینک کار افزونه ایجاد شده در کنار سایر پلاگین‌های نصب شده دیگر قابل مشاهده خواهد بود.

wp-plugin-list