تخصيص الدفع في ماجنتو 2: دليل خطوة بخطوة (2026)
عملية الدفع في ماجنتو 2 مبنية على تطبيق أحادي الصفحة Knockout.js — إنها قوية ولكن notoriously معقدة للتخصيص. يغطي هذا الدليل كل نهج رئيسي: تجاوزات layout XML، تمديدات مكونات Knockout، إضافة/إزالة الحقول، الخطوات المخصصة، تعديلات الشحن والدفع، وأفضل الممارسات للبقاء متوافقًا مع الترقيات. يمكنك أيضًا الاطلاع على خدمة تطوير ماجنتو 2 الكاملة إذا كنت بحاجة إلى تنفيذ كامل للدفع.
باختصار: يتكون دفع ماجنتو 2 من مكونات UI (Knockout.js)، ومعالجات layout (XML)، ومزودي PHP (مصادر بيانات). يمكنك تخصيصه عبر
layout/checkout_index_index.xmlوextend/overrideلمكونات Knockout و الـ plugins على فئات PHP.
جدول المحتويات
- فهم بنية الدفع
- الأدوات: Layout XML و Knockout ومزودو PHP
- إضافة حقل مخصص إلى عنوان الشحن
- إزالة حقل من الدفع
- تجاوز مكون Knockout.js
- إضافة خطوة دفع مخصصة
- تخصيص طرق الشحن
- تخصيص طرق الدفع
- إضافة قواعد التحقق
- تعديل ملخص الطلب (الشريط الجانبي)
- التوافق مع الإضافات الخارجية
- أفضل الممارسات وأمان الترقية
- الأسئلة الشائعة
فهم بنية الدفع
دفع ماجنتو 2 هو تطبيق Knockout.js أحادي الصفحة مع هذه الخطوات الأساسية:
| الخطوة | المكون | الغرض |
|---|---|---|
| الشحن | Magento_Checkout/js/view/shipping | نموذج عنوان الشحن + اختيار طريقة الشحن |
| الفوترة | Magento_Checkout/js/view/billing | نموذج عنوان الفوترة |
| الدفع | Magento_Checkout/js/view/payment | قائمة طرق الدفع |
| الملخص | Magento_Checkout/js/view/summary | الشريط الجانبي لمراجعة الطلب |
كل خطوة هي مكون UI يتكون من قالب .html ونموذج عرض .js وفئة PHP مزود توفر بيانات الخلفية. إذا كنت جديدًا في بناء وحدات ماجنتو 2
، ابدأ من هناك — تخصيص الدفع يبني على نفس بنية الوحدة.
الأدوات: Layout XML و Knockout ومزودو PHP
Layout XML
الملف checkout_index_index.xml يتحكم في أي المكونات يتم عرضها:
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="checkout.root">
<arguments>
<argument name="jsLayout" xsi:type="array">
<!-- components go here -->
</argument>
</arguments>
</referenceBlock>
</body>
</page>
تمديد مكون Knockout
استخدم extend لإضافة إلى مكون موجود:
define(['Magento_Checkout/js/view/shipping'], function (Component) {
'use strict';
return Component.extend({
// your custom logic
});
});
مزودو PHP
منطق الخلفية موجود في Magento\Checkout\Block\Checkout\LayoutProcessor أو Processors مخصصة تطبق LayoutProcessorInterface.
إضافة حقل مخصص إلى عنوان الشحن
الخطوة 1 — إنشاء layout XML
<!-- Vendor/Module/view/frontend/layout/checkout_index_index.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="checkout.root">
<arguments>
<argument name="jsLayout" xsi:type="array">
<item name="components" xsi:type="array">
<item name="checkout" xsi:type="array">
<item name="children" xsi:type="array">
<item name="steps" xsi:type="array">
<item name="children" xsi:type="array">
<item name="shipping-step" xsi:type="array">
<item name="children" xsi:type="array">
<item name="shippingAddress" xsi:type="array">
<item name="children" xsi:type="array">
<item name="shipping-address-fieldset" xsi:type="array">
<item name="children" xsi:type="array">
<item name="custom_field" xsi:type="array">
<item name="config" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
<item name="template" xsi:type="string">ui/form/field</item>
<item name="elementTmpl" xsi:type="string">ui/form/elements/input</item>
<item name="label" xsi:type="string">Custom Field</item>
<item name="dataScope" xsi:type="string">custom_field</item>
<item name="provider" xsi:type="string">checkoutProvider</item>
<item name="sortOrder" xsi:type="string">150</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
الخطوة 2 — حفظ الحقل عبر LayoutProcessor
namespace Vendor\Module\Block\Checkout;
use Magento\Checkout\Block\Checkout\LayoutProcessorInterface;
class CustomFieldProcessor implements LayoutProcessorInterface
{
public function process($jsLayout)
{
// Field was already added via XML; persist it to the quote
return $jsLayout;
}
}
الخطوة 3 — Plugin على ShippingInformationManagement
namespace Vendor\Module\Plugin;
use Magento\Checkout\Model\ShippingInformationManagement;
use Magento\Checkout\Model\Session;
use Magento\Quote\Api\Data\AddressExtensionFactory;
class SaveCustomField
{
private $checkoutSession;
private $addressExtensionFactory;
public function __construct(
Session $checkoutSession,
AddressExtensionFactory $addressExtensionFactory
) {
$this->checkoutSession = $checkoutSession;
$this->addressExtensionFactory = $addressExtensionFactory;
}
public function beforeSaveAddressInformation(
ShippingInformationManagement $subject,
$cartId,
\Magento\Checkout\Api\Data\ShippingInformationInterface $shippingInfo
) {
$extAttributes = $shippingInfo->getShippingAddress()->getExtensionAttributes();
if ($extAttributes === null) {
$extAttributes = $this->addressExtensionFactory->create();
}
$customField = $shippingInfo->getShippingAddress()->getCustomAttribute('custom_field');
$extAttributes->setCustomField($customField ? $customField->getValue() : '');
return [$cartId, $shippingInfo];
}
}
إزالة حقل من الدفع
استخدم LayoutProcessor لإزالة الحقول:
namespace Vendor\Module\Block\Checkout;
use Magento\Checkout\Block\Checkout\LayoutProcessorInterface;
class RemoveFieldProcessor implements LayoutProcessorInterface
{
public function process($jsLayout)
{
$fieldset = &$jsLayout['components']['checkout']['children']['steps']
['children']['shipping-step']['children']['shippingAddress']
['children']['shipping-address-fieldset']['children'];
unset($fieldset['company']); // remove company field
unset($fieldset['telephone']); // remove telephone field
return $jsLayout;
}
}
تجاوز مكون Knockout.js
لاستبدال مكون الشحن بمكونك الخاص:
// Vendor/Module/view/frontend/web/js/view/custom-shipping.js
define([
'Magento_Checkout/js/view/shipping',
'Magento_Checkout/js/model/quote',
'Magento_Customer/js/model/customer'
], function (Component, quote, customer) {
'use strict';
return Component.extend({
defaults: {
template: 'Vendor_Module/custom-shipping'
},
// Add a custom observable
initialize: function () {
this._super();
this.customMessage = ko.observable('');
return this;
},
// Override the shipping method selection
setShippingInformation: function () {
// custom logic before calling parent
return this._super();
}
});
});
سجله في checkout_index_index.xml:
<item name="shipping" xsi:type="array">
<item name="config" xsi:type="array">
<item name="component" xsi:type="string">Vendor_Module/js/view/custom-shipping</item>
</item>
</item>
إضافة خطوة دفع مخصصة
الخطوة 1 — إنشاء مكون الخطوة
// Vendor/Module/view/frontend/web/js/view/custom-step.js
define([
'uiComponent',
'Magento_Checkout/js/model/step-navigator',
'jquery',
'ko'
], function (Component, stepNavigator, $, ko) {
'use strict';
var uniqueId = 'custom-step';
return Component.extend({
defaults: {
template: 'Vendor_Module/custom-step'
},
isVisible: ko.observable(false),
stepCode: uniqueId,
stepTitle: 'Custom Step',
initialize: function () {
this._super();
stepNavigator.registerStep(
this.stepCode,
null,
this.stepTitle,
this.isVisible,
_.bind(this.navigate, this),
25 // sort order
);
return this;
},
navigate: function () {
this.isVisible(true);
},
navigateToNextStep: function () {
this.isVisible(false);
stepNavigator.next();
}
});
});
الخطوة 2 — التسجيل في layout XML
<item name="custom-step" xsi:type="array">
<item name="config" xsi:type="array">
<item name="component" xsi:type="string">Vendor_Module/js/view/custom-step</item>
</item>
</item>
تخصيص طرق الشحن
إخفاء طريقة شحن
namespace Vendor\Module\Plugin;
use Magento\Quote\Api\Data\ShippingMethodInterface;
use Magento\Quote\Model\Cart\ShippingMethodConverter;
class HideShippingMethod
{
public function afterModelToDataObject(
ShippingMethodConverter $subject,
ShippingMethodInterface $result
) {
$code = $result->getCarrierCode() . '_' . $result->getMethodCode();
if (in_array($code, ['flatrate_flatrate'])) {
return null;
}
return $result;
}
}
إضافة طريقة شحن مخصصة
أنشئ فئة Carrier تمتد \Magento\Shipping\Model\Carrier\AbstractCarrier ونفذ collectRates()، ثم سجلها عبر config.xml.
تخصيص طرق الدفع
إضافة طريقة دفع مخصصة
- أنشئ Model يطبق
Magento\Payment\Model\MethodInterface - عرّف
config.xmlمع تكوين الطريقة - أنشئ قوالب الواجهة الأمامية لنموذج الدفع
- سجل مكون Knockout لعرض الدفع
هل تحتاج إلى تكامل بوابة دفع مخصصة؟ راجع خدمة الوحدات المخصصة الخاصة بي لمعالجات الدفع المحلية (Konnect, Flouci, Paymee) وتدفقات الدفع الكاملة.
<!-- config.xml -->
<default>
<payment>
<custom_payment>
<model>Vendor\Module\Model\Payment\CustomPayment</model>
<title>Custom Payment</title>
<active>1</active>
<sort_order>10</sort_order>
<order_status>pending</order_status>
<allowspecific>0</allowspecific>
</custom_payment>
</payment>
</default>
إضافة قواعد التحقق
أضف قواعد تحقق Knockout مخصصة:
define(['jquery', 'jquery/validate'], function ($) {
'use strict';
$.validator.addMethod('custom-rule', function (value) {
return value && value.length >= 3;
}, $.mage.__('Value must be at least 3 characters'));
});
ثم ارجع إليها في layout XML الخاص بك:
<item name="validation" xsi:type="array">
<item name="custom-rule" xsi:type="boolean">true</item>
</item>
تعديل ملخص الطلب (الشريط الجانبي)
تجاوز مكون Knockout summary:
define([
'Magento_Checkout/js/view/summary/abstract-total',
'Magento_Checkout/js/model/quote'
], function (Component, quote) {
'use strict';
return Component.extend({
getCustomBlockHtml: function () {
return '<p class="custom-note">' +
$t('Your custom message here') + '</p>';
}
});
});
التوافق مع الإضافات الخارجية
| المشكلة | الحل |
|---|---|
| تعارضات الحقول | استخدم sortOrder للتحكم في موضع الحقل |
| ترتيب الخطوات معطل | سجل الخطوة بوزن ترتيب صحيح |
| أخطاء JS من التجاوزات | استخدم extend بدلاً من replace عندما يكون ذلك ممكنًا |
| بيانات المزود لا تستمر | أنشئ plugin على ShippingInformationManagement::saveAddressInformation |
| تضارب CSS | حدد النطاق باستخدام محددات فئة خاصة بالدفع |
أفضل الممارسات وأمان الترقية
- فضّل
extendعلى استبدال المكون بالكامل — يحافظ على عمل الكود عبر تحديثات الإصدارات. - استخدم
LayoutProcessorInterfaceلتعديلات الحقول بدلاً من تجاوز القوالب. - خزّن البيانات المخصصة في جداول
quote_extensionعبر سمات extension — يتجنب تعديل الجداول الأساسية. - اختبر عبر المتصفحات والأجهزة — يختلف سلوك JS للدفع.
- تجنب تعديل ملفات
Magento_Checkout/js/model/**مباشرة — قم بتمديدها. - قم دائمًا بمسح المحتوى الثابت بعد تغييرات JS:
php bin/magento setup:static-content:deploy -f. - نفّذ compilation كاملة (
php bin/magento setup:upgrade && php bin/magento setup:di:compile) بعد إضافة فئات PHP جديدة — راجع الدليل حول setup:upgrade vs di:compile للتفاصيل. - لضبط أداء أعمق، راجع خدمة تحسين الأداء الخاصة بي التي تغطي تدقيق FPC و Varnish و Core Web Vitals.
الأسئلة الشائعة
لماذا استخدام LayoutProcessor بدلاً من XML لتغييرات الحقول؟
LayoutProcessor أكثر مرونة للمنطق الشرطي (مثال: إظهار حقل فقط لطرق شحن معينة) ويتجنب XML المتداخل بعمق للتغييرات الديناميكية.
كيف أختبر تغييرات الدفع الخاصة بي في وضع المطور؟
php bin/magento deploy:mode:set developer
php bin/magento cache:flush
npm run watch # if theme uses Grunt
الحقل المخصص الخاص بي لا يُحفظ. ماذا يجب أن أتحقق؟
- تحقق من أن
dataScopeيطابق رمز السمة - plugin على
ShippingInformationManagement::saveAddressInformationمسجل - سمات extension مُعلنة بشكل صحيح في
extension_attributes.xml - تحقق من وحدة تحكم المتصفح لأخطاء JS
هل يمكنني إضافة خطوة بعد الدفع؟
نعم — سجل خطوتك بترتيب فرز أعلى من خطوة الدفع (الافتراضي: 30) ونفذ منطق التنقل وفقًا لذلك.
الخاتمة
يتطلب تخصيص دفع ماجنتو 2 فهمًا قويًا لبنية مكونات Knockout.js ونظام layout XML ومزودي PHP. باستخدام extend بدلاً من الاستبدال، و LayoutProcessor لتغييرات الحقول، و plugins لاستمرارية البيانات، يمكنك بناء تخصيصات دفع قوية وآمنة للترقية.
الخطوات التالية:
- بناء طريقة شحن مخصصة بأسعار ديناميكية
- تنفيذ دفع بخطوة واحدة باستخدام وحدات خارجية
- إنشاء خطوة رسالة هدية أو تعليق طلب
- إضافة التحقق من العنوان عبر Google Maps API