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
    Jul 3 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 Jul 3 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
    Jul 3 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 Jul 4 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. Jul 5 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. Jul 6 at 4:45
  • Countryofmanufacture is also used '\Magento\Directory\Model\ResourceModel\Country\Collection' Jul 6 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 that you have read and understand our privacy policy and code of conduct.

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