[docs] Add article/tutorial that outlines custom attribute addition to product entity including UI #5133
Replies: 9 comments 8 replies
-
On a sidenote, for now I would greatly appreciate on how it is actually possible to add that field to the UI so I can continue working with Medusa. Is it even possible? I found no "hook" for the form. |
Beta Was this translation helpful? Give feedback.
-
Thank you for submitting this issue @genox . If you mean add fields in the Medusa form in the admin, then I would suggest using our Admin Widgets. Widgets can be injected into different zones in the admin. In this case, you can inject it into the Please note that a lot of these features are newly introduced and we're constantly looking into not only documenting them, but also ensuring that we provide a good and clear learning experience. I think you provide a good suggestion, and would be something I'd discuss with the team. In the meantime, as I explained you can use admin widgets which are already documented. Please let me know if you're looking for something different instead. |
Beta Was this translation helpful? Give feedback.
-
Yes, this was my fall back. I would have assumed those fields magically showed up in the "Attributes" tab though. After all, it is there for "Attributes" ;-) Can you point me to an example of a plugin that persists data to a product entity? It is a lot of code to write for a simple attribute, so having at least a starter template of sorts that could be copy pasted for the most part would speed up things for newbies significantly. |
Beta Was this translation helpful? Give feedback.
-
You don't need to write that logic yourself (if I'm understanding you correctly). You can use the For example, if you're using it in an endpoint: router.post("/custom-endpoint", (req, res) => {
const productService = req.scope.resolve("productService")
productService.save({
// pass your custom data to the object
})
}) Make sure that in this case, if you're using TypeScript, you add a TypeScript declaration file as explained here to avoid errors. You can alternatively access the Note that services, repositories, and other resources can be accessed in endpoints, other services, etc... through dependency injection, which you can learn more about here. |
Beta Was this translation helpful? Give feedback.
-
Can we please convert this to a GitHub Discussion, as this is a feature request? Our Issues tracker is dedicated to bug reports. |
Beta Was this translation helpful? Give feedback.
-
Apologies. Sure, but how to convert? |
Beta Was this translation helpful? Give feedback.
-
Thank you, I will look into this. |
Beta Was this translation helpful? Give feedback.
-
@shahednasser Sorry for pinging you here, but I am starting to get a little bit desperate. I hope you can help me with an issue that is blocking me. I managed to hook up a modal and a form to the product view and it seems to work fine, however, now I can't update the entity and get I know this must have something to do with loaders - but I can't figure out what is going on. I followed the guides in your documentation closely but I must be missing some detail. Here is how I implemented the custom attributes on the product entity: src/models/product.ts import { Column, Entity } from 'typeorm';
import { Product as MedusaProduct } from '@medusajs/medusa';
@Entity()
export class Product extends MedusaProduct {
@Column({ default: '' })
brand: string;
@Column({ default: '' })
bodypart: string;
} Migration: export class ProductExtend1695044457400 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "product" ADD COLUMN "brand" text`);
await queryRunner.query(`ALTER TABLE "product" ADD COLUMN "bodypart" text`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "brand"`);
await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "bodypart"`);
}
} src/loaders/product-extended-field.ts export default async function () {
const imports = (await import('@medusajs/medusa/dist/api/routes/store/products/index')) as any;
imports.allowedStoreProductsFields = [...imports.allowedStoreProductsFields, 'brand', 'bodypart'];
imports.defaultStoreProductsFields = [...imports.defaultStoreProductsFields, 'brand', 'bodypart'];
} src/types/index.d.ts export declare module "@medusajs/medusa/dist/models/product" {
declare interface Product {
brand: string;
bodypart: string;
}
} src/api/index.ts export class AdminPostProductsReq extends MedusaAdminPostProductsReq {
@IsOptional()
@IsString()
brand?: string;
@IsOptional()
@IsString()
bodypart?: string;
}
// Extends the Products Class with custom fields
registerOverriddenValidators(AdminPostProductsReq); I was not able to save a new product without using TS optional indicator and @isOptional(), which is also peculiar. When I create a new product now and open it I the detail view, the custom attribute fields are not part of the raw product json dump at the bottom. I am using the latest available versions. I tried to follow the solutions of others that have mentioned this issue here but to no avail. |
Beta Was this translation helpful? Give feedback.
-
@shahednasser I know I'm late to the discussion, but I'm still struggling with something and haven't found a solution despite extensive searching. This discussion seems the most relevant, so I thought it would be the best place to ask. Based on the main issue discussed here and the replies, let's say I've successfully extended the product entity, extended the API validator. Everything is working fine so far—I can see the custom field in the database, retrieve it via both the store and admin APIs, and even use it in the "Create Product" API endpoint through Postman. The product, along with the custom field, is added successfully when using Postman. However, when I try to add a new product via the "Add Product" modal in the admin dashboard UI, I receive an error message stating "custom-field is required." This makes sense since I set it as required. My questions are: how do I pass the newly added custom field to the payload/request body from the "Add Product" modal in the admin dashboard? how do I add admin widget to "Add Product" modal in order to pass the custom field in the add-product-process? I also considered selecting the "Publish Product" button using the DOM, setting its display property to "none" or disabling it, and then adding a new button aslo through the DOM to manually dispatch the product creation using Medusa React hooks. This way, I could add the new property to the request body before sending the POST request, but I don't think this is a reliable workaround if I can apply it in the first place. |
Beta Was this translation helpful? Give feedback.
-
Preliminary Checks
Issue Summary
One of the first things someone is going to want to do is to add an additional attribute to a product. I just started using MedusaJS, read the docs up and down and searched discord, gh issues and discussions to figure out how to add a text input field to the product create/edit form - I couldn't figure it out.
I was able to add attributes to the entity and all fragments required to have the field show up in the model including migrations but there is nothing in the docs on how to add this field to the product create/edit form.
Up until now, I wasn't able to figure it out. And according to a search on discord, I am not the only one struggling with this. :)
In my humble newbie opinion, this is the perfect entry level tutorial that shows the "full stack" in action and should therefore be created as such. A tutorial that ties together all the small detail parts including the admin UI.
How can this issue be resolved?
Basically, an article that outlines all the required steps to add an input field or maybe even a select dropdown to the product information form by extending the product entity. From start to finish. Along the way, people learn all the minimum basics to work with Medusa and touched every part once.
Are you interested in working on this issue?
Beta Was this translation helpful? Give feedback.
All reactions