0

I am trying to create a country dropdown for a custom product attribute.

This is the error message:

Error: Call to undefined method Magento\Directory\Model\Config\Source\Country::setAttribute() in /var/www/html/vendor/magento/module-eav/Model/Entity/Attribute/AbstractAttribute.php:652

This is my install:

$eavSetup->addAttribute(
            \Magento\Catalog\Model\Product::ENTITY,
            'countries',
            [
                'group' => 'Countries',
                'type' => 'text',
                'frontend' => '',
                'label' => 'Countries',
                'input' => 'multiselect',
                'class' => '',
                'source' => 'Magento\Directory\Model\Config\Source\Country',
                'backend' => 'Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend',
                'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
                'visible' => true,
                'required' => false,
                'user_defined' => false,
                'default' => '',
                'searchable' => false,
                'filterable' => false,
                'comparable' => false,
                'visible_on_front' => false,
                'used_in_product_listing' => false,
                'unique' => false,
                'apply_to' => 'configurable',
            ]
        );

The issue is with the source:

'source' => 'Magento\Directory\Model\Config\Source\Country'

3 Answers 3

1

you can replace it with the following code using setup patch data create AddCountryDropdownAttribute.php file on below path Vendor\Module\Setup\Patch\Data

<?php
declare(strict_types=1);

namespace Vendor\Module\Setup\Patch\Data;

use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
use Magento\Catalog\Setup\CategorySetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class AddCountryDropdownAttribute implements DataPatchInterface
{

  /**
   * @var ModuleDataSetupInterface
   */
  private $moduleDataSetup;

  /**
   * @var CategorySetupFactory
   */
   private $categorySetupFactory;

  /**
   * AddCountryDropdownAttribute constructor.
   *
   * @param ModuleDataSetupInterface $moduleDataSetup
   * @param CategorySetupFactory $categorySetupFactory
   */
    public function __construct(
       ModuleDataSetupInterface $moduleDataSetup,
       CategorySetupFactory $categorySetupFactory
    ) {
      $this->moduleDataSetup = $moduleDataSetup;
      $this->categorySetupFactory = $categorySetupFactory;
    }

  /**
   * @inheritDoc
   */
   public function apply()
   { 
     $this->moduleDataSetup->startSetup();

     $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]);

     $attributeCode = 'country_of_origin';
     $attributeOptions = [
        'type' => 'int',
        'label' => 'Country of Origin',
        'input' => 'select',
        'source' => 'Magento\Directory\Model\Config\Source\Country',
        'required' => false,
        'sort_order' => 100,
        'global' => Attribute::SCOPE_GLOBAL,
        'user_defined' => true,
        'visible' => true,
        'searchable' => false,
        'filterable' => true,
        'comparable' => false,
        'visible_on_front' => false,
        'html_allowed_on_front' => false,
        'backend' => 'Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend',
    ];

    $categorySetup->addAttribute(Product::ENTITY, $attributeCode, $attributeOptions);

    $this->moduleDataSetup->endSetup();
}

  /**
   * @inheritDoc
   */
   public static function getDependencies()
   {
      return [];
   }

   /**
    * @inheritDoc
    */
   public function getAliases()
   {
     return [];
   }      
}
4
  • This answer using setup patch data is the best practice. But I think you can use Magento\Eav\Setup\EavSetupFactory directly instead of Magento\Catalog\Setup\CategorySetupFactory here, as we are not working on categories.
    – Cladiuss
    Commented Jul 3, 2023 at 15:10
  • Hi. i tried your solution. Nothing showed up on my product page. No error (so improvement there) but still nothing shows up Commented Jul 3, 2023 at 15:13
  • Check in the back office : "Stores > Attributes > Product", and search for the attribute. If it is there, this code worked. If you want to display it on your product page, you will need to add additional code in order to affect this newly created attribute to a product set.
    – Cladiuss
    Commented Jul 3, 2023 at 16:44
  • I could indeed find your code via "Stores > Attributes > Product" , however it does appear on the admin page. i.e the create new product page. also, when i added the code 'group' => 'Country of Origin',it still has this same message: Error: Call to undefined method setAttribute Commented Jul 4, 2023 at 4:52
1

Add Custom Product Attribute for Country Dropdown (using setup patch data) follow below steps:

  • Add AddCountryAttribute.php in the following file path : app\code\Vendor\Extention\Setup\Patch\Data

<?php
namespace Vendor\Extention\Setup\Patch\Data;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class AddCountryAttribute implements DataPatchInterface
{
    private $_moduleDataSetup;

    private $_eavSetupFactory;

    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        EavSetupFactory $eavSetupFactory
    ) {
        $this->_moduleDataSetup = $moduleDataSetup;
        $this->_eavSetupFactory = $eavSetupFactory;
    }

    public function apply()
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->_eavSetupFactory->create(['setup' => $this->_moduleDataSetup]);

        $eavSetup->addAttribute(\Magento\Catalog\Model\Product::ENTITY, 'country_options', [
            'label'                      => 'Available in Country',
            'input'                      => 'select',
            'type'                       => 'varchar',
            'backend'                    => '\Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend',
            'frontend'                   => null,
            'source'                     => '\Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture',
            'global'                     => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
            'required'                   => false,
            'user_defined'               => false,
            'class'                      => null,
            'unique'                     => false,
            'searchable'                 => false,
            'filterable'                 => false,
            'comparable'                 => false,
            'visible_on_front'           => false,
            'is_configurable'            => false,
            'visible'                    => true,
        ]);
    }

    public static function getDependencies()
    {
        return [];
    }

    public function getAliases()
    {
        return [];
    }

    public static function getVersion()
    {
        return '1.0.0';
    }
}

Screenshot

3
  • your answer indeed works, but you are using: Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture. This seems like the wrong file i.e . Countryofmanufacture is for manufacturing. i tried using Magento\Directory\Model\Config\Source\Country but it had the same error. Commented Jul 5, 2023 at 12:39
  • "Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture" does not appear to be incorrect; in fact, it is one of the correct methods.you are providing the class '\Magento\Directory\Model\ResourceModel\Country\Collection', which is causing the error because the method setAttribute() is not defined in this class. To fix the issue, you need to use a different class for the 'source' attribute, one that extends '\Magento\Eav\Model\Entity\Attribute\Source\AbstractSource'. You can create a custom source model to handle the options for the 'country_options' attribute. Commented Jul 6, 2023 at 4:45
  • Countryofmanufacture is also used '\Magento\Directory\Model\ResourceModel\Country\Collection' Commented Jul 6, 2023 at 8:41
0

Replace the source with the below code and check

'source' => \Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture::class

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.