Laravel 11 E-Commerce - Admin Create New Product

Welcome back to the Laravel E-Commerce Project Tutorial! In this video, we are going to learn about creating a new product page.

Creating a New Function in AdminController

So, let's see how we can create a new product. Go to the Admin Controller and create a function:


public function add_product()
{
$categories = Category::Select('id','name')->orderBy('name')->get();
$brands = Brand::Select('id','name')->orderBy('name')->get();
return view("admin.product-add",compact('categories','brands'));
}

Creating the Route

Now, let's create the route for this add_product function. So, go to the web.php file and inside the admin route group, add a new route:


Route::get('/admin/product/add',[AdminController::class,'add_product'])->name('admin.product.add');

Creating the View

Now, go to the resources directory and create a new view, Product.add.blade.php. Now, go to the template directory and let's open product-add.html in a text editor. And let's copy the main-content div. Okay, here is the main-content div; now, let's copy this content from here and paste it inside the product.add.blade.php.

Now, add the dashboard route and products route link. Also, after each input field, add a validation message, and for keeping the old value, add the old function with the input control as follows:



@extends('layouts.admin')

@section('content')
<!-- main-content-wrap -->
<div class="main-content-inner">
<!-- main-content-wrap -->
<div class="main-content-wrap">
<div class="flex items-center flex-wrap justify-between gap20 mb-27">
<h3>Add Product</h3>
<ul class="breadcrumbs flex items-center flex-wrap justify-start gap10">
<li>
<a href="index.html"><div class="text-tiny">Dashboard</div></a>
</li>
<li>
<i class="icon-chevron-right"></i>
</li>
<li>
<a href="all-product.html"><div class="text-tiny">Products</div></a>
</li>
<li>
<i class="icon-chevron-right"></i>
</li>
<li>
<div class="text-tiny">Add product</div>
</li>
</ul>
</div>
<!-- form-add-product -->
<form class="tf-section-2 form-add-product" method="POST" enctype="multipart/form-data" action="{{route('admin.product.store')}}" >
@csrf
<div class="wg-box">
<fieldset class="name">
<div class="body-title mb-10">Product name <span class="tf-color-1">*</span></div>
<input class="mb-10" type="text" placeholder="Enter product name" name="name" tabindex="0" value="" aria-required="true">
<div class="text-tiny">Do not exceed 100 characters when entering the product name.</div>
</fieldset>
@error("name") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<fieldset class="name">
<div class="body-title mb-10">Slug <span class="tf-color-1">*</span></div>
<input class="mb-10" type="text" placeholder="Enter product slug" name="slug" tabindex="0" value="" aria-required="true">
<div class="text-tiny">Do not exceed 100 characters when entering the product name.</div>
</fieldset>
@error("slug") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<div class="gap22 cols">
<fieldset class="category">
<div class="body-title mb-10">Category <span class="tf-color-1">*</span></div>
<div class="select">
<select class="" name="category_id">
<option value="">Choose category</option>
@foreach ($categories as $category)
<option value="{{$category->id}}">{{$category->name}}</option>
@endforeach
</select>
</div>
</fieldset>
@error("category_id") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<fieldset class="brand">
<div class="body-title mb-10">Brand <span class="tf-color-1">*</span></div>
<div class="select">
<select class="" name="brand_id">
<option value="">Choose Brand</option>
@foreach ($brands as $brand)
<option value="{{$brand->id}}">{{$brand->name}}</option>
@endforeach
</select>
</div>
</fieldset>
@error("brand_id") <span class="alert alert-danger text-center">{{$message}}</span> @enderror
</div>

<fieldset class="shortdescription">
<div class="body-title mb-10">Short Description <span class="tf-color-1">*</span></div>
<textarea class="mb-10 ht-150" name="short_description" placeholder="Short Description" tabindex="0" aria-required="true"></textarea>
<div class="text-tiny">Do not exceed 100 characters when entering the product name.</div>
</fieldset>
@error("short_description") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<fieldset class="description">
<div class="body-title mb-10">Description <span class="tf-color-1">*</span></div>
<textarea class="mb-10" name="description" placeholder="Description" tabindex="0" aria-required="true"></textarea>
<div class="text-tiny">Do not exceed 100 characters when entering the product name.</div>
</fieldset>
@error("description") <span class="alert alert-danger text-center">{{$message}}</span> @enderror
</div>

<div class="wg-box">
<fieldset>
<div class="body-title">Upload images <span class="tf-color-1">*</span></div>
<div class="upload-image flex-grow">
<div class="item" id="imgpreview" style="display:none">
<img src="{{asset('images/upload/upload-1.png')}}" class="effect8" alt="">
</div>
<div id="upload-file" class="item up-load">
<label class="uploadfile" for="myFile">
<span class="icon">
<i class="icon-upload-cloud"></i>
</span>
<span class="body-text">Drop your images here or select <span class="tf-color">click to browse</span></span>
<input type="file" id="myFile" name="image" accept="image/*">
</label>
</div>
</div>
</fieldset>
@error("image") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<fieldset>
<div class="body-title mb-10">Upload Gallery Images</div>
<div class="upload-image mb-16">
<div id ="galUpload" class="item up-load">
<label class="uploadfile" for="gFile">
<span class="icon">
<i class="icon-upload-cloud"></i>
</span>
<span class="text-tiny">Drop your images here or select <span class="tf-color">click to browse</span></span>
<input type="file" id="gFile" name="images[]" accept="image/*" multiple>
</label>
</div>
</div>
</fieldset>
@error("images") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<div class="cols gap22">
<fieldset class="name">
<div class="body-title mb-10">Regular Price <span class="tf-color-1">*</span></div>
<input class="mb-10" type="text" placeholder="Enter regular price" name="regular_price" tabindex="0" value="" aria-required="true">
</fieldset>
@error("regular_price") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<fieldset class="name">
<div class="body-title mb-10">Sale Price <span class="tf-color-1">*</span></div>
<input class="mb-10" type="text" placeholder="Enter sale price" name="sale_price" tabindex="0" value="" aria-required="true">
</fieldset>
@error("sale_price") <span class="alert alert-danger text-center">{{$message}}</span> @enderror
</div>


<div class="cols gap22">
<fieldset class="name">
<div class="body-title mb-10">SKU <span class="tf-color-1">*</span></div>
<input class="mb-10" type="text" placeholder="Enter SKU" name="SKU" tabindex="0" value="" aria-required="true">
</fieldset>
@error("SKU") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<fieldset class="name">
<div class="body-title mb-10">Quantity <span class="tf-color-1">*</span></div>
<input class="mb-10" type="text" placeholder="Enter quantity" name="quantity" tabindex="0" value="" aria-required="true">
</fieldset>
@error("quantity") <span class="alert alert-danger text-center">{{$message}}</span> @enderror
</div>

<div class="cols gap22">
<fieldset class="name">
<div class="body-title mb-10">Stock</div>
<div class="select mb-10">
<select class="" name="stock_status">
<option value="instock">InStock</option>
<option value="outofstock">Out of Stock</option>
</select>
</div>
</fieldset>
@error("stock_status") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

<fieldset class="name">
<div class="body-title mb-10">Featured</div>
<div class="select mb-10">
<select class="" name="featured">
<option value="0">No</option>
<option value="1">Yes</option>
</select>
</div>
</fieldset>
@error("featured") <span class="alert alert-danger text-center">{{$message}}</span> @enderror

</div>
<div class="cols gap10">
<button class="tf-button w-full" type="submit">Add product</button>
</div>
</div>
</form>
<!-- /form-add-product -->
</div>
<!-- /main-content-wrap -->
</div>
<!-- /main-content-wrap -->
@endsection

Adding JavaScript Code

After this, let's add the @push directive, and inside this, let's add the JavaScript code for previewing the product images and also for generating a slug:


@push("scripts")
<script>
$(function(){
$("#myFile").on("change",function(e){
const photoInp = $("#myFile");
const [file] = this.files;
if (file) {
$("#imgpreview img").attr('src',URL.createObjectURL(file));
$("#imgpreview").show();
}
});


$("#gFile").on("change",function(e){
$(".gitems").remove();
const gFile = $("gFile");
const gphotos = this.files;
$.each(gphotos,function(key,val){
$("#galUpload").prepend(`<div class="item gitems"><img src="${URL.createObjectURL(val)}" alt=""></div>`);
});
});


$("input[name='name']").on("change",function(){
$("input[name='slug']").val(StringToSlug($(this).val()));
});

});
function StringToSlug(Text) {
return Text.toLowerCase()
.replace(/[^\w ]+/g, "")
.replace(/ +/g, "-");
}
</script>
@endpush

Storing the Product

Now, go to the AdminController and create a new function for storing the product.


public function product_store(Request $request)
{
$request->validate([
'name'=>'required',
'slug'=>'required|unique:products,slug',
'category_id'=>'required',
'brand_id'=>'required',
'short_description'=>'required',
'description'=>'required',
'regular_price'=>'required',
'sale_price'=>'required',
'SKU'=>'required',
'stock_status'=>'required',
'featured'=>'required',
'quantity'=>'required',
'image'=>'required|mimes:png,jpg,jpeg|max:2048'
]);

$product = new Product();
$product->name = $request->name;
$product->slug = Str::slug($request->name);
$product->short_description = $request->short_description;
$product->description = $request->description;
$product->regular_price = $request->regular_price;
$product->sale_price = $request->sale_price;
$product->SKU = $request->SKU;
$product->stock_status = $request->stock_status;
$product->featured = $request->featured;
$product->quantity = $request->quantity;
$current_timestamp = Carbon::now()->timestamp;

if($request->hasFile('image'))
{
if (File::exists(public_path('uploads/products').'/'.$product->image)) {
File::delete(public_path('uploads/products').'/'.$product->image);
}
if (File::exists(public_path('uploads/products/thumbnails').'/'.$product->image)) {
File::delete(public_path('uploads/products/thumbnails').'/'.$product->image);
}

$image = $request->file('image');
$imageName = $current_timestamp.'.'.$image->extension();

$this->GenerateThumbnailImage($image,$imageName);
$product->image = $imageName;
}

$gallery_arr = array();
$gallery_images = "";
$counter = 1;

if($request->hasFile('images'))
{
$oldGImages = explode(",",$product->images);
foreach($oldGImages as $gimage)
{
if (File::exists(public_path('uploads/products').'/'.trim($gimage))) {
File::delete(public_path('uploads/products').'/'.trim($gimage));
}

if (File::exists(public_path('uploads/products/thumbails').'/'.trim($gimage))) {
File::delete(public_path('uploads/products/thumbails').'/'.trim($gimage));
}
}
$allowedfileExtension=['jpg','png','jpeg'];
$files = $request->file('images');
foreach($files as $file){
$gextension = $file->getClientOriginalExtension();
$check=in_array($gextension,$allowedfileExtension);
if($check)
{
$gfilename = $current_timestamp . "-" . $counter . "." . $gextension;
$this->GenerateThumbnailImage($file,$gfilename);
array_push($gallery_arr,$gfilename);
$counter = $counter + 1;
}
}
$gallery_images = implode(',', $gallery_arr);
}
$product->images = $gallery_images;
$product->category_id = $request->category_id;
$product->brand_id = $request->brand_id;
$product->save();
return redirect()->route('admin.products')->with('status','Record has been added successfully !');
}

Creating the Route for Storing the Product

Now, create a route for this function:


Route::post('/admin/product/store',[AdminController::class,'product_store'])->name('admin.product.store');

Adding the Link for Adding a New Product

Now, go to the products.blade.php file and add a link for adding a new product:


<a class="tf-button style-1 w208" href="{{ route('admin.product.add') }}"><i class="icon-plus"></i>Add new</a>

Also, add the "Add new Product" link on the admin layout page, so go to the admin.blade.php and add the link as follows:


<li class="menu-item has-children">
<a href="javascript:void(0);" class="menu-item-button">
<div class="icon"><i class="icon-shopping-cart"></i></div>
<div class="text">Products</div>
</a>
<ul class="sub-menu">
<li class="sub-menu-item">
<a href="{{route('admin.product.add')}}" class="">
<div class="text">Add Product</div>
</a>
</li>
</ul>
</li>

Checking the Result

Now, it's done. Let's check. Refresh the page, and let's enter the product details here, then click on submit, and after that, you will see the product will be added.

So, in this way, you can create a new product page. That's all about creating a new product page.