Product Typesالستة وأكتر.
كل نوع منتج في Magento — إزاي بيشتغل من جوّه، امتى تستخدمه، وإزاي بيتصرّف في السلة والتسعير والمخزون. وفي الآخر، إزاي تعمل نوع مخصّص بنفسك.
Magento 2 فيه ستة أنواع منتجات: Simple منتج واحد بسعر ومخزون، Configurable أب بيبيع أبناءه الـ simple حسب اختيار العميل، Bundle العميل بيركّبه من مجموعات اختيار، Grouped عرض لمنتجات مستقلة مع بعض، Virtual من غير شحن، و Downloadable بملفات بتتحمّل بعد الشراء. النوع بيحدد التسعير والمخزون وشكل السلة، وتغييره بعد البيع صعب.
الصورة الكاملة
الستة أنواع في نظرة واحدة.
فكّر فيهم كـ 3 مجموعات: منتج واحد (simple, virtual, downloadable)، ومنتج مركّب من منتجات تانية (configurable, bundle)، ومنتج بيعرض منتجات تانية بس (grouped).
Simple
الأساس — وأكتر نوع هتستخدمه.
منتج مادي واحد له SKU واحد وسعر واحد ومخزون واحد. مفيش اختيارات ولا تركيبات.
سعر مباشر. ممكن يكون عليه special_price (سعر خاص) أو tier prices (أسعار بالكمية).
كمية مباشرة. بتتخصم عند الشراء بشكل مباشر.
سطر واحد. الكمية × السعر. أبسط حالة ممكنة.
- المنتج مالوش أي اختيارات — كتاب، علبة، قطعة.
- أو كـ ابن داخل configurable (وده الاستخدام الأكتر شيوعاً فعلياً).
Configurable
أهم نوع بعد الـ simple — وأكتر واحد بيلخبط.
منتج أب بيعرض اختيارات (مقاس، لون)، وكل تركيبة بتشاور على منتج simple حقيقي. العميل بيختار، والـ simple المناسب هو اللي بيتحط في السلة فعلياً.
الخصائص اللي بتفرّق بين الأبناء (المقاس واللون) لازم تكون:
- نوعها select (قائمة منسدلة).
- الـ scope بتاعها Global.
- apply_to شاملة الـ simple والـ configurable.
السعر المعروض بيجي من الأبناء مش من الأب. Magento بيعرض أقل سعر أو نطاق ("من 100 لـ 150"). لما العميل يختار، السعر بيتحدّث للابن المختار.
المخزون على الأبناء. الأب بيبقى متاح طالما ابن واحد على الأقل متاح. لو كل الأبناء خلصوا، الأب بيختفي.
بيتحط سطرين جوّه Magento — الأب (المعروض) والابن (الفعلي). العميل بيشوف سطر واحد، بس الكود بيشوف الاتنين.
- المنتج له تنويعات محددة ولكل تنويعة مخزون منفصل.
- عايز التنويعات تظهر في الفلاتر (فلتر باللون مثلاً).
- كل تنويعة ليها SKU خاص للتتبّع في المخزن.
Bundle
العميل بيركّب منتجه بنفسه.
منتج بيتكوّن من مجموعات اختيارات، وكل مجموعة فيها منتجات. العميل بيختار من كل مجموعة، والناتج منتج مركّب واحد.
Dynamic
السعر = مجموع المختارات. بيتغيّر مع كل اختيار.
Fixed
سعر ثابت للحزمة، والاختيارات ممكن تضيف فرق سعر.
بيتخصم من كل منتج مكوّن على حدة. والحزمة بتبقى متاحة طالما كل الخيارات الإلزامية متاحة.
سطر واحد ظاهر للعميل (الحزمة)، وجوّاه أسطر للمكوّنات. نفس منطق الأب والأبناء.
- العميل بيركّب المنتج من خيارات محددة.
- عايز تبيع مجموعة بسعر مجمّع.
- المكوّنات ليها مخزون منفصل بتتابعه.
Grouped
أبسط الأنواع المركّبة — وأقلها استخداماً.
مجرد عرض لمنتجات منفصلة في صفحة واحدة. كل منتج بيفضل مستقل تماماً — بسعره ومخزونه — والعميل بيحدد كمية لكل واحد.
في الـ grouped، لما العميل يشتري، بيتحط في السلة أسطر منفصلة لكل منتج — كأنه اشتراهم واحد واحد. مفيش كيان مركّب.
Grouped
3 منتجات = 3 أسطر منفصلة في السلة. مفيش سعر للمجموعة.
Bundle
3 مكوّنات = سطر واحد بسعر مجمّع.
مفيش سعر للمجموعة نفسها. كل منتج بسعره ومخزونه المستقل.
- منتجات مرتبطة بيشتريها العميل مع بعض عادة.
- عايز تسهّل شراءهم من صفحة واحدة.
- مش محتاج سعر مجمّع ولا كيان مركّب.
Virtual و Downloadable
المنتجات غير المادية.
منتج مالوش وجود مادي، فمالوش شحن ولا وزن. خدمة، اشتراك، ضمان ممتد، رسوم تركيب.
لو السلة كلها منتجات virtual، Magento بيتخطى خطوة الشحن تماماً — مفيش عنوان شحن ولا اختيار شركة شحن.
- خدمات: تركيب، صيانة، استشارة.
- ضمانات ممتدة.
- اشتراكات وعضويات.
- رسوم إضافية بتتباع كمنتج.
زي الـ virtual، بس بيرفق ملفات العميل بيحمّلها بعد الشراء.
بيتحدد بإعداد: عند الطلب أو عند الفاتورة (يعني بعد تأكيد الدفع). الافتراضي والأأمن هو بعد الفاتورة.
المقارنة الشاملة
كل نوع في كل بُعد.
إزاي أختار
شجرة قرار عملية.
- المنتج بيتشحن؟ لأ → virtual، أو downloadable لو فيه ملف.
- له تنويعات (مقاس/لون)؟ لأ → simple وخلاص.
- كل تنويعة ليها مخزون و SKU منفصل؟ أيوة → configurable.
- لأ، التنويعات بسيطة؟ → simple + Custom Options.
- العميل بيركّب من مجموعات اختيار؟ → bundle.
- عايز تعرض منتجات مستقلة مع بعض بس؟ → grouped (أو related products).
Custom Options
أبسط بكتير. منتج واحد. بس مفيش مخزون منفصل ومش بيظهر في الفلاتر.
Configurable
منتج لكل تركيبة. مخزون منفصل وفلاتر شغّالة — بس إدارة أتقل.
التعامل معهم في الكود
الأنماط اللي هتحتاجها.
use Magento\Catalog\Model\Product\Type; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; // الثوابت الجاهزة Type::TYPE_SIMPLE // 'simple' Type::TYPE_VIRTUAL // 'virtual' Type::TYPE_BUNDLE // 'bundle' Configurable::TYPE_CODE // 'configurable' // الفحص if ($product->getTypeId() === Configurable::TYPE_CODE) { // منطق خاص بالـ configurable } // فحوصات جاهزة مفيدة $product->isVirtual(); // مالوش شحن؟ $product->isComposite(); // مركّب من منتجات تانية؟ $product->isSalable(); // متاح للبيع؟
// الوصول لمنطق النوع $typeInstance = $product->getTypeInstance(); // كل الأبناء (المنتجات الفعلية) $children = $typeInstance->getUsedProducts($product); foreach ($children as $child) { printf( "%s — %s\n", $child->getSku(), $child->getPrice() ); } // الخصائص اللي بيتكوّن منها (المقاس، اللون) $attributes = $typeInstance ->getConfigurableAttributes($product); // العكس: من ابن للأب $parentIds = $typeInstance ->getParentIdsByChild($childId);
// للعرض والعد — الآباء بس foreach ($quote->getAllVisibleItems() as $item) { // ده اللي العميل شايفه printf("%s x%d\n", $item->getName(), $item->getQty()); } // للمخزون والشحن — المنتجات الفعلية foreach ($quote->getAllItems() as $item) { // تخطّى الآباء عشان متحسبش مرتين if ($item->getHasChildren()) { continue; } // ده المنتج اللي هيتشحن فعلاً }
عمل نوع مخصّص
لما الأنواع الموجودة ماتكفيش.
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <type name="subscription" label="Subscription Product" modelInstance="Vendor\Module\Model\Product\Type\Subscription" indexPriority="40" sortOrder="50"> <!-- نموذج حساب السعر --> <priceModel instance="Vendor\Module\Model\Product\Price\Subscription"/> <!-- منتج مالوش شحن --> <customAttributes> <attribute name="is_real_product" value="false"/> </customAttributes> </type> </config>
- name — كود النوع، وده اللي بيتخزّن في type_id.
- modelInstance — الكلاس اللي فيه منطق النوع.
- priceModel — كلاس حساب السعر (اختياري).
- is_real_product — false يعني مالوش شحن (زي virtual).
- indexPriority — ترتيب المعالجة في الفهرسة.
namespace Vendor\Module\Model\Product\Type; use Magento\Catalog\Model\Product\Type\AbstractType; use Magento\Catalog\Model\Product; use Magento\Framework\DataObject; class Subscription extends AbstractType { public const TYPE_CODE = 'subscription'; // هل المنتج ده بيتشحن؟ public function isVirtual($product = null): bool { return true; } // هل محتاج وزن؟ public function hasWeight(): bool { return false; } // التحقق قبل الإضافة للسلة public function _prepareProduct( DataObject $buyRequest, $product, $processMode ) { $result = parent::_prepareProduct( $buyRequest, $product, $processMode ); // تحقق من مدة الاشتراك $months = (int) $buyRequest->getData('months'); if ($months < 1) { // نص الخطأ بيرجع للعميل return __('Please choose a subscription period.'); } // خزّن المدة مع الصنف $product->addCustomOption('months', $months); return $result; } }
الفخاخ الشائعة
اقرا دي حتى لو مش هتقرا حاجة تانية.
- عد أصناف السلة بـ getAllItems مع configurable — حساب مضاعف. استخدم getAllVisibleItems للعرض.
- خاصية مش Global في الـ configurable — مش هتظهر في قائمة الاختيارات، والسبب مش واضح.
- افتراض وجود عنوان شحن دايماً — بيقع مع السلة الافتراضية. شيّك بـ isVirtual().
- حساب المخزون على الأب في الـ configurable — المخزون على الأبناء، والأب مالوش كمية.
- bundles كتير في صفحة قسم — بتبطّئها بشكل ملحوظ.
- تغيير نوع منتج بعد ما اتباع — بيكسر ارتباط الأوردرات القديمة.
- configurable بدل custom options لتنويعات مالهاش مخزون منفصل — تعقيد بلا فايدة.
- downloadable متاح "عند الطلب" مع دفع عند الاستلام — تحميل بدون دفع.
- نوع مخصّص من غير داعي — شغل كتير في التسعير والمخزون والفهرسة كان ممكن يتوفّر.
أسئلة الإنترفيو
الأسئلة المتكررة.
Product Types ✓
دلوقتي فاهم الستة أنواع: إزاي كل واحد بيشتغل، امتى تستخدمه، وإزاي بيتصرّف في السعر والمخزون والسلة. وإزاي تعمل نوع مخصّص لو احتجت.
الخلاصة: الـ simple هو أساس كل حاجة، والـ configurable بيبيع أبناءه، والنوع قرار صعب التراجع عنه بعد أول بيعة.
خلّصت الدرس؟علّمه عشان تتابع تقدّمك في الكورس.
أسئلة شائعة
إيه الفرق بين Configurable و Bundle و Grouped في Magento 2؟
الـ Configurable منتج أب بيخلّي العميل يختار تنويعة واحدة زي المقاس واللون، والـ simple المناسب هو اللي بيتباع فعلًا. الـ Bundle بيخلّي العميل يركّب منتج من مجموعات اختيار بسعر مجمّع أو ثابت، وبيتحط سطر واحد في السلة. الـ Grouped مجرد عرض لمنتجات مستقلة في صفحة واحدة، وكل منتج بيتحط سطر منفصل بسعره ومخزونه.
فين المخزون في الـ Configurable Product؟
على الأبناء الـ simple، مش على الأب. الأب بيفضل متاح للبيع طالما ابن واحد على الأقل متاح، ولو كل الأبناء خلصوا الأب بيبقى out of stock. عشان كده لو بتحسب مخزون أو وزن شحن في الكود، لفّ على getAllItems() وتخطّى الأصناف اللي ليها أبناء، لأن الأب نفسه مالوش كمية حقيقية.
امتى أستخدم Custom Options بدل Configurable Product؟
لما التنويعات مالهاش مخزون منفصل ومش محتاجة تظهر في الفلاتر. الـ Custom Options حقول على منتج simple واحد بتأثر على السعر من غير ما تعمل عشرات المنتجات. لو محتاج تتابع مخزون كل تنويعة أو ليها SKU خاص أو العميل هيفلتر بيها في الـ layered navigation، خد Configurable.
ليه الـ Configurable بيحط سطرين في السلة؟
سطر للأب اللي العميل شايفه وسطر للابن اللي هيتشحن ويتخصم من المخزون. العميل بيشوف سطر واحد، بس الكود بيشوف الاتنين. عشان كده getAllVisibleItems() بترجّع الآباء بس للعرض والعدّ، وgetAllItems() بترجّع الاتنين. لو حسبت إجمالي على getAllItems من غير ما تتخطّى الأب هتحسب السعر مرتين.
إيه الخصائص اللي ينفع أعمل بيها Configurable Product؟
الخاصية لازم تكون نوعها Dropdown أو Swatch، والـ scope بتاعها Global، ومنطبقة على أنواع المنتجات المستخدمة من apply_to. لو شرط منهم ناقص مش هتظهر في قائمة الخصائص وإنت بتعمل الـ Configurable من غير أي رسالة توضّح السبب، ودي أشهر حيرة مع النوع ده.
إيه اللي بيحصل لو السلة كلها منتجات Virtual؟
Magento بيتخطى خطوة الشحن كلها في الـ checkout: مفيش عنوان شحن ولا اختيار شركة شحن. عشان كده $quote->isVirtual() مهمة، وأي كود بيقرا عنوان الشحن لازم يشيّك عليها الأول وإلا هيقع مع السلة الافتراضية. الـ Downloadable نفس الفكرة مع ملفات بتتاح للتحميل، والافتراضي إنها تتاح بعد الفاتورة مش بعد الطلب.
إزاي أعمل نوع منتج مخصّص في Magento 2؟
عرّفه في etc/product_types.xml بـ name و label و modelInstance، وكلاس بيورّث من Magento\Catalog\Model\Product\Type\AbstractType وتعدّل فيه isVirtual() و _prepareProduct() وغيرهم. بس النوع الجديد بيحتاج شغل في التسعير والمخزون والسلة والفهرسة، ففي معظم الحالات نوع موجود مع custom options أو خصائص إضافية بيكفي بجهد أقل بكتير.