<p>With this kind of setup:</p>
<pre class="lang-php prettyprint-override"><code>function random()
{
    return array_reduce(range(0, 9), fn ($x) =&gt; $x . range('a', 'z')[rand(0, 25)], '');
}

$salt = random();

$result = Craft::$app-&gt;getFields()-&gt;saveField($field = new craft\fields\Number([
    'handle' =&gt; $salt,
    'name' =&gt; $salt,
]));
assert($result === true);
</code></pre>
<p>I can add this field to a <code>User</code>:</p>
<pre class="lang-php prettyprint-override"><code>$result = Craft::$app-&gt;getFields()-&gt;saveLayout(new craft\models\FieldLayout([
    'fields' =&gt; [$field],
    'type' =&gt; craft\elements\User::class,
]));
assert($result === true);

$result = Craft::$app-&gt;getElements()-&gt;saveElement($user = new craft\elements\User([
    'email' =&gt; &quot;$salt@domain.com&quot;,
    'username' =&gt; $salt,
    $salt =&gt; 42,
]));
assert($result === true);
assert($user-&gt;{$salt} === 42);
assert(Craft::$app-&gt;getElements()-&gt;getElementById($user-&gt;id, craft\elements\User::class)-&gt;{$salt} === 42);
</code></pre>
<p>and to an <code>Order</code>:</p>
<pre class="lang-php prettyprint-override"><code>$result = Craft::$app-&gt;getFields()-&gt;saveLayout(new craft\models\FieldLayout([
    'fields' =&gt; [$field],
    'type' =&gt; craft\commerce\elements\Order::class,
]));
assert($result === true);

$result = Craft::$app-&gt;getElements()-&gt;saveElement($order = new craft\commerce\elements\Order([
    $salt =&gt; 42,
]));
assert($result);
assert($order-&gt;{$salt} === 42);
assert(Craft::$app-&gt;getElements()-&gt;getElementById($order-&gt;id, craft\commerce\elements\Order::class)-&gt;{$salt} === 42);
</code></pre>
<p>but I cannot do the same with a <code>Product</code>:</p>
<pre class="lang-php prettyprint-override"><code>$result = Craft::$app-&gt;getFields()-&gt;saveLayout(new craft\models\FieldLayout([
    'fields' =&gt; [$field],
    'type' =&gt; craft\commerce\elements\Product::class,
]));
assert($result === true);

$result = craft\commerce\Plugin::getInstance()-&gt;getProductTypes()-&gt;saveProductType($productType = new craft\commerce\models\ProductType([
    'handle' =&gt; $salt,
    'hasDimensions' =&gt; false,
    'hasVariants' =&gt; false,
    'name' =&gt; $salt,
    'siteSettings' =&gt; [
        Craft::$app-&gt;getSites()-&gt;getCurrentSite()-&gt;id =&gt; new craft\commerce\models\ProductTypeSite(),
    ],
]));
assert($result === true);

$result = Craft::$app-&gt;getElements()-&gt;saveElement($product = new craft\commerce\elements\Product([
    'slug' =&gt; $salt,
    'title' =&gt; $salt,
    'typeId' =&gt; $productType-&gt;id,
    'variants' =&gt; [
        [
            'hasUnlimitedStock' =&gt; false,
            'price' =&gt; 0,
            'maxQty' =&gt; 0,
            'minQty' =&gt; 0,
        ],
    ],
    $salt =&gt; 42,
]));
assert($result === true);
assert($product-&gt;{$salt} === 42);
assert(Craft::$app-&gt;getElements()-&gt;getElementById($product-&gt;id, craft\commerce\elements\Product::class)-&gt;{$salt} === 42);
</code></pre>
<p>Both assertions fail (though the <code>Product</code> is saved without errors), so I'm assuming I am missing some additional piece of ceremony in the creation. What could that be?</p>

CC BY-SA 4.0
2023-08-07T12:52:00.827Z
Whats the result of `Plugin::getInstance()->getProductTypes()->saveProductType`?
Luke Holder
CC BY-SA 4.0
2023-08-07T14:20:22.727Z
@LukeHolder a fair question. I've added assertions on the results of each call; they all return `true`. In preparing the test case, I also checked the errors (`assert(!$x->hasErrors());`) for each created item, they also passed.
msbit
<plugin-craftcommerce>
Commerce 3: How to programmatically create a custom field and assign it to a Product
# Commerce 3: How to programmatically create a custom field and assign it to a Product

(Asked by: username_0 on 2023-08-07)

With this kind of setup:
function random()
{
    return array_reduce(range(0, 9), fn ($x) => $x . range('a', 'z')[rand(0, 25)], '');
}

$salt = random();

$result = Craft::$app->getFields()->saveField($field = new craft\fields\Number([
    'handle' => $salt,
    'name' => $salt,
]));
assert($result === true);

I can add this field to a User:
$result = Craft::$app->getFields()->saveLayout(new craft\models\FieldLayout([
    'fields' => [$field],
    'type' => craft\elements\User::class,
]));
assert($result === true);

$result = Craft::$app->getElements()->saveElement($user = new craft\elements\User([
    'email' => "$salt@domain.com",
    'username' => $salt,
    $salt => 42,
]));
assert($result === true);
assert($user->{$salt} === 42);
assert(Craft::$app->getElements()->getElementById($user->id, craft\elements\User::class)->{$salt} === 42);

and to an Order:
$result = Craft::$app->getFields()->saveLayout(new craft\models\FieldLayout([
    'fields' => [$field],
    'type' => craft\commerce\elements\Order::class,
]));
assert($result === true);

$result = Craft::$app->getElements()->saveElement($order = new craft\commerce\elements\Order([
    $salt => 42,
]));
assert($result);
assert($order->{$salt} === 42);
assert(Craft::$app->getElements()->getElementById($order->id, craft\commerce\elements\Order::class)->{$salt} === 42);

but I cannot do the same with a Product:
$result = Craft::$app->getFields()->saveLayout(new craft\models\FieldLayout([
    'fields' => [$field],
    'type' => craft\commerce\elements\Product::class,
]));
assert($result === true);

$result = craft\commerce\Plugin::getInstance()->getProductTypes()->saveProductType($productType = new craft\commerce\models\ProductType([
    'handle' => $salt,
    'hasDimensions' => false,
    'hasVariants' => false,
    'name' => $salt,
    'siteSettings' => [
        Craft::$app->getSites()->getCurrentSite()->id => new craft\commerce\models\ProductTypeSite(),
    ],
]));
assert($result === true);

$result = Craft::$app->getElements()->saveElement($product = new craft\commerce\elements\Product([
    'slug' => $salt,
    'title' => $salt,
    'typeId' => $productType->id,
    'variants' => [
        [
            'hasUnlimitedStock' => false,
            'price' => 0,
            'maxQty' => 0,
            'minQty' => 0,
        ],
    ],
    $salt => 42,
]));
assert($result === true);
assert($product->{$salt} === 42);
assert(Craft::$app->getElements()->getElementById($product->id, craft\commerce\elements\Product::class)->{$salt} === 42);

Both assertions fail (though the Product is saved without errors), so I'm assuming I am missing some additional piece of ceremony in the creation. What could that be?

**Tags:** plugin-craftcommerce
> **Comments:**
> **username_1**: Whats the result of `Plugin::getInstance()->getProductTypes()->saveProductType`?  
> **username_0**: @LukeHolder a fair question. I've added assertions on the results of each call; they all return `true`. In preparing the test case, I also checked the errors (`assert(!$x->hasErrors());`) for each created item, they also passed.  

---

## 0 answers

