Laravel E-Commerce Application Development – Product Details Page

Laravel E-Commerce Application Development – Product Details Page

Laravel E-Commerce Application Development ( 27 Lessons )

In this course, you’ll learn how to create an E-Commerce Website from scratch in Laravel. The process has never been easier I’ll take you from the very beginning stages of setting up Laravel till the last steps of adding products to the cart. If you’ve good understanding & experience in PHP & MySQL then this course is for you.

see full series
  1. Laravel E-Commerce Application Development – Introduction
  2. Laravel E-Commerce Application Development – Initial Project Setup
  3. Laravel E-Commerce Application Development – Assets Setup Using Laravel Mix
  4. Laravel E-Commerce Application Development – Admin Model and Migration
  5. Laravel E-Commerce Application Development – Backend Admin Authentication
  6. Laravel E-Commerce Application Development – Base Controller and Repository
  7. Laravel E-Commerce Application Development – Settings Section Part 1
  8. Laravel E-Commerce Application Development – Settings Section Part 2
  9. Laravel E-Commerce Application Development – Categories Section Part 1
  10. Laravel E-Commerce Application Development – Categories Section Part 2
  11. Laravel E-Commerce Application Development – Attributes Section Part 1
  12. Laravel E-Commerce Application Development – Attributes Section Part 2
  13. Laravel E-Commerce Application Development – Attributes Section Part 3
  14. Laravel E-Commerce Application Development – Brands Section
  15. Laravel E-Commerce Application Development – Products Section Part 1
  16. Laravel E-Commerce Application Development – Products Section Part 2
  17. Laravel E-Commerce Application Development – Products Section Part 3
  18. Laravel E-Commerce Application Development – Products Section Part 4
  19. Laravel E-Commerce Application Development – Frontend Login & Registration
  20. Laravel E-Commerce Application Development – Categories Navigation
  21. Laravel E-Commerce Application Development – Catalog Listing
  22. Laravel E-Commerce Application Development – Product Details Page
  23. Laravel E-Commerce Application Development – Shopping Cart
  24. Laravel E-Commerce Application Development – Checkout
  25. Laravel E-Commerce Application Development – Payment Processing
  26. Laravel E-Commerce Application Development – Order Management
  27. Laravel E-Commerce Application Development – Wrap Up

This is part 21 of the Laravel E-Commerce Application Development series. In this part, we will start implementing the product details page.

I assume you should have the e-commerce application project on your machine or you can grab it from Laravel E-Commerce Application repository, we will start from where we left it in the last part.

Updating Product Controller show Method

In the previous post, we created a show() method in our Product Controller. Instead of dumping the current product, we will return a new view file which will show the product details. As on our product page, we would like to show the product attributes as well, so will load all attributes and supply to this our new view.

Within our Product Controller, add the below statement before the class declaration.

use App\Contracts\AttributeContract;

Next, we will add a new protected property to include the attribute repository.

protected $attributeRepository;

Next, we will inject the App\Contracts\AttributeContract class to our constructor.

public function __construct(ProductContract $productRepository, AttributeContract $attributeRepository)
{
    $this->productRepository = $productRepository;
    $this->attributeRepository = $attributeRepository;
}

Now, we will update the show() method which will return the product details view.

public function show($slug)
{
    $product = $this->productRepository->findProductBySlug($slug);
    $attributes = $this->attributeRepository->listAttributes();

    return view('site.pages.product', compact('product', 'attributes'));
}

Adding the Add To Cart Route

Before proceeding to the product details page, I would like to create a new POST route for our add to cart functionality. Open the routes/web.php file and add the below route in it.

Route::post('/product/add/cart', 'Site\[email protected]')->name('product.add.cart');

Adding addToCart() Method in Product Controller

Now, our add to cart route is pointing to addToCart() method, so we will add that in our Product Controller.

public function addToCart(Request $request)
{
    dd($request->all());
}

That’s it for now, let’s move on to the product details page for our application.

Creating Product Details Page

To explain the product details page, I will share the code snippets with the explanation. At the end of this post, I will share the full file for product details.

Head over to resources/views/site/pages folder and add a new file name product.blade.php.

Open this file and add the below HTML markup in it.

@extends('site.app')
@section('title', $product->name)
@section('content')
    <section class="section-pagetop bg-dark">
        <div class="container clearfix">
            <h2 class="title-page">{{ $product->name }}</h2>
        </div>
    </section>
    <section class="section-content bg padding-y border-top" id="site">
        <div class="container">
            <div class="row">
                {{--All Content will goes here--}}
            </div>
        </div>
    </section>
@stop

In this HTML markup, we have simply extended the main layout and added a header section which will show the product name. Next, we have a section container, which will holde the whole product page.

Now, add below markup within the row div in the above code snippet.

<div class="col-md-12">
    <div class="card">
        <div class="row no-gutters">

        </div>
    </div>
</div>

In the above row no-gutters div, we will create an aside section with 5 columns. Add the below markup in it.

<aside class="col-sm-5 border-right">
    <article class="gallery-wrap">
        @if ($product->images->count() > 0)
            <div class="img-big-wrap">
                <div class="padding-y">
                    <a href="{{ asset('storage/'.$product->images->first()->full) }}" data-fancybox="">
                        <img src="{{ asset('storage/'.$product->images->first()->full) }}" alt="">
                    </a>
                </div>
            </div>
        @else
            <div class="img-big-wrap">
                <div>
                    <a href="https://via.placeholder.com/176" data-fancybox=""><img src="https://via.placeholder.com/176"></a>
                </div>
            </div>
        @endif
         @if ($product->images->count() > 0)
            <div class="img-small-wrap">
                @foreach($product->images as $image)
                    <div class="item-gallery">
                        <img src="{{ asset('storage/'.$image->full) }}" alt="">
                    </div>
                @endforeach
            </div>
        @endif
    </article>
</aside>

In the above code snippet, firstly we are checking if any images exist for the current product. If yes then we will show the first image for the current product. If not, we will show a placeholder image.

Next, again checking if there are any images we will run a loop on the images and show each image as a thumbnail.

Now, we will add a new aside section just after the previous aside section.

<aside class="col-sm-7">
    <article class="p-5">
        <h3 class="title mb-3">{{ $product->name }}</h3>
        <dl class="row">
            <dt class="col-sm-3">SKU</dt>
            <dd class="col-sm-9">{{ $product->sku }}</dd>
            <dt class="col-sm-3">Weight</dt>
            <dd class="col-sm-9">{{ $product->weight }}</dd>
        </dl>
        <div class="mb-3">
            @if ($product->sale_price > 0)
                <var class="price h3 text-danger">
                    <span class="currency">{{ config('settings.currency_symbol') }}</span><span class="num" id="productPrice">{{ $product->sale_price }}</span>
                    <del class="price-old"> {{ config('settings.currency_symbol') }}{{ $product->price }}</del>
                </var>
            @else
                <var class="price h3 text-success">
                    <span class="currency">{{ config('settings.currency_symbol') }}</span><span class="num" id="productPrice">{{ $product->price }}</span>
                </var>
            @endif
        </div>
        <hr>
        <form action="{{ route('product.add.cart') }}" method="POST" role="form" id="addToCart">
            @csrf
            <div class="row">
                <div class="col-sm-12">
                    <dl class="dlist-inline">
                        @foreach($attributes as $attribute)
                            @php $attributeCheck = in_array($attribute->id, $product->attributes->pluck('attribute_id')->toArray()) @endphp
                            @if ($attributeCheck)
                                <dt>{{ $attribute->name }}: </dt>
                                <dd>
                                    <select class="form-control form-control-sm option" style="width:180px;" name="{{ strtolower($attribute->name ) }}">
                                        <option data-price="0" value="0"> Select a {{ $attribute->name }}</option>
                                        @foreach($product->attributes as $attributeValue)
                                            @if ($attributeValue->attribute_id == $attribute->id)
                                                <option
                                                    data-price="{{ $attributeValue->price }}"
                                                    value="{{ $attributeValue->value }}"> {{ ucwords($attributeValue->value . ' +'. $attributeValue->price) }}
                                                </option>
                                            @endif
                                        @endforeach
                                    </select>
                                </dd>
                            @endif
                        @endforeach
                    </dl>
                </div>
            </div>
            <hr>
            <div class="row">
                <div class="col-sm-12">
                    <dl class="dlist-inline">
                        <dt>Quantity: </dt>
                        <dd>
                            <input class="form-control" type="number" min="1" value="1" max="{{ $product->quantity }}" name="qty" style="width:70px;">
                            <input type="hidden" name="productId" value="{{ $product->id }}">
                            <input type="hidden" name="price" id="finalPrice" value="{{ $product->sale_price != '' ? $product->sale_price : $product->price }}">
                        </dd>
                    </dl>
                </div>
            </div>
            <hr>
            <button type="submit" class="btn btn-success"><i class="fas fa-shopping-cart"></i> Add To Cart</button>
        </form>
    </article>
</aside>

There is a lot of things going on int this aside section. We start by showing the product name, SKU and weight. Then moving on to showing the product price, if there is a sale price we will show that.

Next, we have a form which is pointing to the add to cart route. Within this form, firstly we are firstly looping through all attributes which we loaded in the Product Controller.

Within, this loop firstly we will make a check if the current attribute in the loop iteration is same as the product attribute (I used the pluck() method to get the product attributes ids and then checked it with the current attribute id.), if yes then we will show the product attribute.

I have just implemented the select type attribute as implementing all types is beyond the scope of this series.

Next, we will iterate through the product attribute values. Within the select box’s option, I am setting the data-price element which we will use in the JavaScript to change the price based on attribute selected.

Next, we are showing the quantity box and also I have added the two productId and price hidden fields which we will submit in this form.

Finally, we have we submit button.

Now, we will create a new 12 column section and display the product description like below.

<div class="col-md-12">
    <article class="card mt-4">
        <div class="card-body">
            {!! $product->description !!}
        </div>
    </article>
</div>

There is some javascript which I added to change the price of the product based on the attribute selected.

Right at the bootom of this file after @stop add the below code snippet.

@push('scripts')
    <script>
        $(document).ready(function () {
            $('#addToCart').submit(function (e) {
                if ($('.option').val() == 0) {
                    e.preventDefault();
                    alert('Please select an option');
                }
            });
            $('.option').change(function () {
                $('#productPrice').html("{{ $product->sale_price != '' ? $product->sale_price : $product->price }}");
                let extraPrice = $(this).find(':selected').data('price');
                let price = parseFloat($('#productPrice').html());
                let finalPrice = (Number(extraPrice) + price).toFixed(2);
                $('#finalPrice').val(finalPrice);
                $('#productPrice').html(finalPrice);
            });
        });
    </script>
@endpush

Open the resources/views/site/partials/scripts.blade.php file and add the below stack directive at the end of the file.

@stack('scripts')

product.blade.php File

@extends('site.app')
@section('title', $product->name)
@section('content')
    <section class="section-pagetop bg-dark">
        <div class="container clearfix">
            <h2 class="title-page">{{ $product->name }}</h2>
        </div>
    </section>
    <section class="section-content bg padding-y border-top" id="site">
        <div class="container">
            <div class="row">
                <div class="col-md-12">
                    <div class="card">
                        <div class="row no-gutters">
                            <aside class="col-sm-5 border-right">
                                <article class="gallery-wrap">
                                    @if ($product->images->count() > 0)
                                        <div class="img-big-wrap">
                                            <div class="padding-y">
                                                <a href="{{ asset('storage/'.$product->images->first()->full) }}" data-fancybox="">
                                                    <img src="{{ asset('storage/'.$product->images->first()->full) }}" alt="">
                                                </a>
                                            </div>
                                        </div>
                                    @else
                                        <div class="img-big-wrap">
                                            <div>
                                                <a href="https://via.placeholder.com/176" data-fancybox=""><img src="https://via.placeholder.com/176"></a>
                                            </div>
                                        </div>
                                    @endif
                                     @if ($product->images->count() > 0)
                                        <div class="img-small-wrap">
                                            @foreach($product->images as $image)
                                                <div class="item-gallery">
                                                    <img src="{{ asset('storage/'.$image->full) }}" alt="">
                                                </div>
                                            @endforeach
                                        </div>
                                    @endif
                                </article>
                            </aside>
                            <aside class="col-sm-7">
                                <article class="p-5">
                                    <h3 class="title mb-3">{{ $product->name }}</h3>
                                    <dl class="row">
                                        <dt class="col-sm-3">SKU</dt>
                                        <dd class="col-sm-9">{{ $product->sku }}</dd>
                                        <dt class="col-sm-3">Weight</dt>
                                        <dd class="col-sm-9">{{ $product->weight }}</dd>
                                    </dl>
                                    <div class="mb-3">
                                        @if ($product->sale_price > 0)
                                            <var class="price h3 text-danger">
                                                <span class="currency">{{ config('settings.currency_symbol') }}</span><span class="num" id="productPrice">{{ $product->sale_price }}</span>
                                                <del class="price-old"> {{ config('settings.currency_symbol') }}{{ $product->price }}</del>
                                            </var>
                                        @else
                                            <var class="price h3 text-success">
                                                <span class="currency">{{ config('settings.currency_symbol') }}</span><span class="num" id="productPrice">{{ $product->price }}</span>
                                            </var>
                                        @endif
                                    </div>
                                    <hr>
                                    <form action="{{ route('product.add.cart') }}" method="POST" role="form" id="addToCart">
                                        @csrf
                                        <div class="row">
                                            <div class="col-sm-12">
                                                <dl class="dlist-inline">
                                                    @foreach($attributes as $attribute)
                                                        @php $attributeCheck = in_array($attribute->id, $product->attributes->pluck('attribute_id')->toArray()) @endphp
                                                        @if ($attributeCheck)
                                                            <dt>{{ $attribute->name }}: </dt>
                                                            <dd>
                                                                <select class="form-control form-control-sm option" style="width:180px;" name="{{ strtolower($attribute->name ) }}">
                                                                    <option data-price="0" value="0"> Select a {{ $attribute->name }}</option>
                                                                    @foreach($product->attributes as $attributeValue)
                                                                        @if ($attributeValue->attribute_id == $attribute->id)
                                                                            <option
                                                                                data-price="{{ $attributeValue->price }}"
                                                                                value="{{ $attributeValue->value }}"> {{ ucwords($attributeValue->value . ' +'. $attributeValue->price) }}
                                                                            </option>
                                                                        @endif
                                                                    @endforeach
                                                                </select>
                                                            </dd>
                                                        @endif
                                                    @endforeach
                                                </dl>
                                            </div>
                                        </div>
                                        <hr>
                                        <div class="row">
                                            <div class="col-sm-12">
                                                <dl class="dlist-inline">
                                                    <dt>Quantity: </dt>
                                                    <dd>
                                                        <input class="form-control" type="number" min="1" value="1" max="{{ $product->quantity }}" name="qty" style="width:70px;">
                                                        <input type="hidden" name="productId" value="{{ $product->id }}">
                                                        <input type="hidden" name="price" id="finalPrice" value="{{ $product->sale_price != '' ? $product->sale_price : $product->price }}">
                                                    </dd>
                                                </dl>
                                            </div>
                                        </div>
                                        <hr>
                                        <button type="submit" class="btn btn-success"><i class="fas fa-shopping-cart"></i> Add To Cart</button>
                                    </form>
                                </article>
                            </aside>
                        </div>
                    </div>
                </div>
                <div class="col-md-12">
                    <article class="card mt-4">
                        <div class="card-body">
                            {!! $product->description !!}
                        </div>
                    </article>
                </div>
            </div>
        </div>
    </section>
@stop
@push('scripts')
    <script>
        $(document).ready(function () {
            $('#addToCart').submit(function (e) {
                if ($('.option').val() == 0) {
                    e.preventDefault();
                    alert('Please select an option');
                }
            });
            $('.option').change(function () {
                $('#productPrice').html("{{ $product->sale_price != '' ? $product->sale_price : $product->price }}");
                let extraPrice = $(this).find(':selected').data('price');
                let price = parseFloat($('#productPrice').html());
                let finalPrice = (Number(extraPrice) + price).toFixed(2);
                $('#finalPrice').val(finalPrice);
                $('#productPrice').html(finalPrice);
            });
        });
    </script>
@endpush

Now, if you open a product you will have product page something like below.

Product Details View
Product Details View

What’s Next

In the next post, we will start working on the shopping cart and create a cart page for our this application.

Code Repository

You can find the code base of this series on Laravel eCommerce Application repository.

If you have any question about this post, please leave a comment in the comment box below.

8 comments on “Laravel E-Commerce Application Development – Product Details Page

  1. Hello,
    Many things in this not working like Thumbnail image change, Add cart even if I have selected attributes alert populates like please select options.
    Can you look into the same

    1. You have to implement the thumbnail click functionality yourself as it’s more find of frontend work. For add to cart button click you may need to fiddle with the javascript.

  2. Hi I’m getting issue on hitting the detail page as bellow error occurs

    ErrorException (E_ERROR)
    Call to a member function pluck() on null (View: /var/www/html/ecom/resources/views/site/pages/product.blade.php)

    I’m using 5.4 Version that may be causing issue

  3. Hallo Sir
    I am bit confused on this chapter , where exactly does this code need to go?I have checked your github isn’t matching what you describe . Please help

    -Within our Product Controller, add the below statement before the class declaration. (Is it Product Controller or AttributeController ?)
    use App\Contracts\AttributeContract;
    -Next, we will add a new protected property to include the attribute repository.
    protected $attributeRepository;

    1. You can save the HTML markup in the the description box and then in where you are displaying the content use {{!! $variable !!}} that will render the HTML.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

When sharing a code snippet please wrap you code with pre tag and add a class code-block to it like below.
<pre class="code-block">you code here</pre>

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.