Testimonial Content
Unlimited testimonials, no cap on the number of entries
Collect and show customer testimonials in Magento 2 with a slider widget, a submission form, 1 to 5 star ratings, customer photos and video links. Testimonial pages output Review schema markup.
Key Features:
Additional Services
Built-in from day one. No add-ons, no upsell, no licence keys to renew.
Unlimited testimonials, no cap on the number of entries
1 to 5 star ratings per testimonial
Drop-in widget, insert via Magento's native widget manager, CMS blocks, or layout XML
Assign a testimonial to multiple categories, Category landing pages with their own URL, meta title, and meta description
Every testimonial gets its own SEO-friendly URL (/testimonials/<url-key>)
Admin moderation, new submissions are saved as pending and require approval
Panth Testimonials is a customer reviews and testimonials extension for Magento 2 and Adobe Commerce that publishes social proof through a slider widget, category pages, and individual SEO-friendly testimonial URLs.
Merchants can collect new testimonials through a frontend submission form, approve or reject them from the admin grid, and showcase the strongest stories with a featured flag. Every testimonial supports 1 to 5 star ratings, a customer photo, and assignment to one or more categories so a B2B catalog, a fashion store, and a services site can all surface the right proof to the right audience.
The testimonials module emits Review schema markup (schema.org/Review) on each testimonial page, which lets Google show star ratings in organic search results and AI Overviews. The widget is responsive, the templates render natively on Hyvä (Alpine.js plus Tailwind) and Luma, and the entire stack is multi-store aware on Magento 2.4.4–2.4.9 with PHP 8.1–8.4.
Translation-ready, MEQP-compliant, and built on the Panth Core foundation so it integrates with other Panth modules without conflicts.
Best for:
Panth Testimonials covers the full social-proof loop — collect, curate, and rank:
Panth_Testimonials adds customer testimonials to a Magento 2 store. It stores testimonials and testimonial categories in their own database tables, manages them from two admin grids, and publishes them on the storefront as a paginated listing page, category pages, one detail page per testimonial and a "Panth Testimonial Slider" widget for CMS pages and layout containers. Customers can submit a testimonial through a storefront form; submissions are saved as pending until an administrator approves them, or published at once when Require Approval is set to No. The listing, category and detail pages emit schema.org JSON-LD (ItemList of Review nodes).
The module adds a custom frontend router for the testimonial URLs, an admin menu under "Panth Extensions", a system configuration section and two database tables. It does not change any core Magento behaviour. It ships separate templates for Hyva (Alpine.js, Hyva snap slider) and Luma (Swiper) and picks the template set through Panth_Core.
Product page: kishansavaliya.com/magento-2-testimonials.html
/<route> (default /testimonials) with category links, pagination (/<route>/page/<n>), breadcrumbs, configurable page title and meta description./<route>/category/<url_key> and detail pages at /<route>/<url_key> served by a custom router; only active categories and approved testimonials resolve; other URLs below the route return the 404 page./<route>/submit, posting to testimonials/submit/save (POST only) with form key validation, plain-text cleaning of every text field, email validation, length limits and a limit of 5 submissions per client IP per hour. Submissions are saved with status Pending.ItemList of up to 50 approved Review nodes on the listing, category and detail pages, with a configurable itemReviewed type, name and optional @id.x-snap-slider) and Luma templates (Swiper from Panth_Core, initialised lazily with IntersectionObserver).With the default route the module serves:
| URL | Page |
|---|---|
/testimonials |
Listing of approved testimonials, sorted by sort order and then newest first, paginated by Items Per Page; a page number beyond the last page returns the 404 page |
/testimonials/page/2 |
Page 2 of the listing |
/testimonials/category/<url_key> |
Listing filtered by an active category; the page title is <Category name> - <Page Title> and the meta description is the category description or a generated text |
/testimonials/<url_key> |
Detail page of an approved testimonial, or the category page when the URL key belongs to an active category |
/testimonials/submit |
Submission form (when Enable Submit Form is Yes) |
The standard route testimonials/* is also registered, so testimonials/index/index, testimonials/view/index?url_key=..., testimonials/category/view?url_key=... and testimonials/submit/index resolve as well while Enable Module is Yes. The custom router runs with sort order 40 and only when Enable Module is Yes.
Testimonials and categories with store ID 0 appear on every store view; other values restrict them to that store view. This applies to the listing, category and detail pages and to the custom router.
The form posts customer_name, customer_email, customer_title, customer_company, rating, title, content and the form key to testimonials/submit/save. Name, a valid email, title and content are required; name, email, title, job title and company are limited to 255 characters and the content to 5000 characters; a rating outside 1 to 5 is stored as 5; HTML tags are stripped from all fields, and before any save (storefront or admin) the model observer decodes HTML entities and strips tags again until the text no longer changes, so entity-encoded markup such as <img> is removed too, double quotes in the customer name become single quotes, and a required field left empty by this cleaning is rejected; category_id is kept only when it belongs to an active category; the URL key is generated from the title and gets a random suffix when it is already used. At most 5 submissions per client IP address are accepted per hour (counter kept in the Magento cache). Requests sent with X-Requested-With: XMLHttpRequest receive a JSON response {"success": bool, "message": string}; other requests are redirected with a session message. The record is saved with status Pending when Require Approval is Yes (it appears on the storefront only after an administrator sets the status to Approved) and with status Approved when it is No. The record gets store ID 0, or the current store view ID when Assign Submissions to Store View is Yes. The Hyva and Luma submit pages and the inline submission modal on the Hyva listing page all send a hidden honeypot field (website_url); a filled honeypot discards the submission silently. The modal shows the message returned by the server, so a rejected submission is reported as an error. The submit forms have no photo upload field; a customer image can only be set directly in the customer_image column.
Insert the widget "Panth Testimonial Slider" (panth_testimonial_slider) from a CMS page, a CMS block or a layout XML widget instance. Parameters:
| Parameter | Default | Effect |
|---|---|---|
| Widget Title | (empty) | Heading above the slider; the template falls back to "What Our Customers Say" |
| Category | all | Restricts the slider to one category |
| Number of Testimonials | 8 | Maximum number of approved testimonials shown, picked in random order |
| Featured Only | No | Shows only testimonials with the Featured flag |
| Show Rating | Yes | Shows the star rating on each card |
| Show Company | Yes | Shows the company name |
| Show Customer Image | Yes | Shows the customer image when the record has one |
| Autoplay | Yes | Advances the slider automatically. A Pause/Start button is shown next to the arrows, autoplay stops while the slider has keyboard focus or the pointer is over it, and it does not start for visitors who prefer reduced motion. |
| Autoplay Interval (ms) | 5000 | Delay between automatic slides |
The widget renders nothing when Enable Module is No for the current store view.
Layout XML example:
<block class="Panth\Testimonials\Block\Widget\TestimonialSlider" name="homepage.testimonials.slider">
<arguments>
<argument name="title" xsi:type="string">What Our Customers Say</argument>
<argument name="count" xsi:type="string">8</argument>
<argument name="featured_only" xsi:type="string">1</argument>
</arguments>
</block>
On Luma the widget renders widget/slider.phtml with Swiper, whose CSS and JS are loaded from Panth_Core on every frontend page by view/frontend/layout/default.xml; the slider is initialised when it scrolls into view and shows 1, 2 and 3 slides on mobile, tablet and desktop. On Hyva the block switches to hyva/widget/slider.phtml, which uses the Hyva x-snap-slider directive and an Alpine.js pager; default_hyva.xml removes the Swiper assets and loads Panth_Testimonials::css/testimonials.css instead.
Panth\Testimonials\Block\Schema renders a <script type="application/ld+json"> in before.body.end on the listing, category and detail pages. The JSON-LD is an ItemList with up to 50 approved testimonials of the current store view, each as a Review with author (Person with name, and jobTitle and affiliation when set), name, reviewBody, reviewRating (1 to 5), datePublished and the configured itemReviewed. Nothing is rendered when no approved testimonial exists.
Templates that can be overridden in a theme under Panth_Testimonials/templates/:
listing.phtml, view.phtml, submit.phtml, widget/slider.phtml, schema.phtmlhyva/listing.phtml, hyva/view.phtml, hyva/submit.phtml, hyva/widget/slider.phtmlLayout handles: testimonials_index_index, testimonials_category_view, testimonials_view_index, testimonials_submit_index and their hyva_ prefixed counterparts that swap in the Hyva templates. Luma styles are in view/frontend/web/css/source/_module.less; Hyva styles in view/frontend/web/css/testimonials.css.
The module has no cron jobs, console commands, web API endpoints, plugins or observers.
USER_GUIDE.md covers installation, configuration, managing testimonials and categories in the admin, the storefront pages, the slider widget, structured data, the submission form and troubleshooting.
See CHANGELOG.md.
| Platform | Versions |
|---|---|
| Magento Open Source | 2.4.4 to 2.4.8 |
| Adobe Commerce | 2.4.4 to 2.4.8 |
| PHP | 8.1, 8.2, 8.3, 8.4 |
| Themes | Hyva, Luma |
Composer constraints on Magento packages: magento/framework ^103.0, magento/module-backend ^102.0, magento/module-config ^101.0, magento/module-store ^101.0, magento/module-ui ^101.0, magento/module-widget ^101.0, magento/module-cms ^104.0.
~8.1.0||~8.2.0||~8.3.0||~8.4.0)mage2kishan/module-core ^1.0 (Panth_Core), installed automatically by ComposerMagento_Cms, Magento_Store and Magento_Widget (part of every Magento installation)composer require mage2kishan/module-testimonials
bin/magento module:enable Panth_Core Panth_Testimonials
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
setup:di:compile is only needed in production mode. setup:static-content:deploy is needed because the module ships CSS under view/frontend/web.
Check the result with:
bin/magento module:status Panth_Testimonials
Go to Stores > Configuration > Panth Extensions > Testimonials. All settings can be set at default, website and store view scope.
| Setting | Default | What it does |
|---|---|---|
| Enable Module | Yes | Enables the custom router and the storefront pages. When disabled the testimonial URLs are not matched and the standard testimonials/* actions return 404. |
| Page Title | Customer Testimonials | Page title, H1 and breadcrumb label of the listing page. |
| URL Route | testimonials | Base path of all testimonial URLs, for example testimonials gives /testimonials. |
| Meta Description | (empty) | Meta description of the listing page. When empty a built-in default text is used. |
| Setting | Default | What it does |
|---|---|---|
| Items Per Page | 12 | Number of testimonials per listing page. |
| Setting | Default | What it does |
|---|---|---|
| Enable Submit Form | Yes | Enables the /<route>/submit page and the testimonials/submit/save POST action. When disabled the submit page returns 404. |
| Require Approval | Yes | Shown only when Enable Submit Form is Yes. Yes saves submissions with status Pending, so an administrator has to approve them. No saves submissions with status Approved, so they are published immediately. The confirmation message changes accordingly. |
| Assign Submissions to Store View | No | Shown only when Enable Submit Form is Yes. Yes saves a submission with the ID of the store view it was sent from, so it is shown only on that store view. No saves it with store ID 0, so it is shown on every store view. |
| Setting | Default | What it does |
|---|---|---|
| Reviewed Item Type | Organization | schema.org @type written into every Review.itemReviewed. Options: Organization, LocalBusiness, ProfessionalService, Product, Service. |
| Reviewed Item Name | (empty) | Name written into Review.itemReviewed.name. When empty the store name from General > Store Information is used, then the store view name, then the website name. |
| Reviewed Item @id (optional) | (empty) | Full URL, or a fragment such as #organization appended to the store base URL, written as Review.itemReviewed.@id. When empty no @id is written. |
Config paths:
panth_testimonials/general/enabledpanth_testimonials/general/page_titlepanth_testimonials/general/routepanth_testimonials/general/meta_descriptionpanth_testimonials/display/items_per_pagepanth_testimonials/submit/enabledpanth_testimonials/submit/require_approvalpanth_testimonials/submit/assign_storepanth_testimonials/schema/item_reviewed_typepanth_testimonials/schema/item_reviewed_namepanth_testimonials/schema/item_reviewed_idWith the defaults the module is active after installation: the listing page is served at /testimonials, the submit form is available and submissions wait for approval.
The admin menu Panth Extensions > Testimonials contains:
panth_testimonials/testimonial/index): grid with keyword search (customer name, company, title and content), columns ID, Customer Name, Title, Rating, Status, Featured and Created, an Edit and Delete action per row and the mass actions Delete, Approve, Reject and Set as Pending (a status change saves only the rows whose status differs). The edit form has Save and Save and Continue Edit buttons and the fields Customer Name (required), Email (validated), Job Title, Company, Rating (select, 1-5 stars) (required), Testimonial Title (required), Full Content (required), Short Excerpt (for cards), URL Key, Status, Featured, Category, Store View (All Store Views or one store view) and Sort Order (0 or greater). An empty Category is stored as NULL. When URL Key is left empty it is generated from the customer name and the title. A URL key that is already used by another testimonial gets a numeric suffix (-2, -3, ...).panth_testimonials/category/index): grid with columns ID, Name, URL Key, Active and Sort Order, row actions and a Delete mass action. The form has the fields Name (required), URL Key, Description, Active and Sort Order. When URL Key is left empty it is generated from the name. A URL key that is already used by another category gets a numeric suffix.The columns customer_image, store_id, meta_title and meta_description exist in the database and are read by the storefront templates, but the admin form has no fields for them. customer_image may hold a full http(s):// URL, a path starting with /, or a path relative to pub/media (for example testimonials/alice.jpg); relative paths are turned into media URLs by every template, including the slider widgets.
bin/magento module:disable Panth_Testimonials
composer remove mage2kishan/module-testimonials
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush
The tables panth_testimonial and panth_testimonial_category and the panth_testimonials/* values in core_config_data are not removed; drop or delete them manually if they are no longer needed. mage2kishan/module-core stays installed if other Panth modules depend on it.
Commercial software license. See LICENSE.txt in this repository.
Panth_Testimonials; Composer package: mage2kishan/module-testimonials; namespace: Panth\Testimonials.Panth_Core, Magento_Cms, Magento_Store, Magento_Widget.Model\Testimonial (constants STATUS_PENDING = 0, STATUS_APPROVED = 1, STATUS_REJECTED = 2; cache tag panth_testimonial; event prefix panth_testimonial) and Model\Category (cache tag and event prefix panth_testimonial_category), with resource models and collections under Model\ResourceModel. Collection helpers: addApprovedFilter(), addStoreFilter(), addCategoryFilter(), addFeaturedFilter(), addDefaultOrder(), addActiveFilter().Model\ResourceModel\Testimonial\Grid\Collection and Model\ResourceModel\Category\Grid\Collection are registered as panth_testimonials_listing_data_source and panth_testimonials_category_listing_data_source in etc/di.xml.Helper\Data exposes the configuration (isEnabled(), getPageTitle(), getMetaDescription(), getCategoryMetaDescription(), getBaseUrl(), isSubmitEnabled(), requireApproval(), isAssignSubmissionStore(), getItemsPerPage()) and the XML_PATH_* constants.Block\Testimonials (listing and category pages), Block\View (detail page), Block\Submit (form), Block\Schema (JSON-LD), Block\Widget\TestimonialSlider (widget; getTestimonials(), getSliderConfig(), getSliderId()).Controller\Router, registered in etc/frontend/di.xml with sort order 40. Frontend controllers: Index\Index, View\Index, Category\View, Submit\Index, Submit\Save. Admin controllers under Controller\Adminhtml\Testimonial and Controller\Adminhtml\Category (Index, NewAction, Edit, Save, Delete, MassDelete).Model\Config\Source\Status, Model\Config\Source\CategoryList, Model\Config\Source\ItemReviewedType.Panth\Core\Helper\Theme::isHyva(); the module registers itself with Panth\Core\ViewModel\ThemeConfig in etc/frontend/di.xml, and etc/theme-config.json holds its colour tokens.Panth_Testimonials::testimonials (menu root), Panth_Testimonials::manage_testimonials (testimonial controllers and menu item), Panth_Testimonials::manage_categories (category controllers and menu item), Panth_Testimonials::configuration (configuration section and menu item).Model\Testimonial and Model\Category implement IdentityInterface. Saving or deleting an approved testimonial, or any category, cleans the panth_testimonial or panth_testimonial_category tag, which the listing, detail and widget blocks report as their identities.etc/db_schema.xml): panth_testimonial and panth_testimonial_category.panth_testimonials; frontend route: testimonials; UI components: panth_testimonials_listing, panth_testimonials_form, panth_testimonials_category_listing, panth_testimonials_category_form.| Module Category | Marketing |
|---|---|
| Best For | All Sizes |
Yes. The module ships Hyva-native templates using Alpine.js and Tailwind. No jQuery required.
Yes. The built-in submission form supports both logged-in customers and guests (configurable), with ReCAPTCHA and admin moderation.
Yes. The module emits schema.org/Review and AggregateRating JSON-LD, which Google uses to display rich snippets (subject to Google's own eligibility rules).
Yes. Unlimited categories are supported, and each testimonial can belong to multiple categories.
Yes. YouTube and Vimeo URLs can be added to any testimonial and are rendered with a lightweight lightbox.
Yes, on both Hyva and Luma.
Yes. All dynamic pieces (pending count, user-specific messaging) load via AJAX or ESI.
Yes. The admin grid supports CSV import/export following a documented column schema.
Yes. Every testimonial, category, and configuration value respects Magento's standard scope hierarchy (default → website → store view).
Yes, Panth_Core is the free shared dependency for all Panth extensions. Composer installs it automatically.
Talk to Kishan directly: written quote, scope and timeline within 24 hours. No sales call.
Customer Testimonials & Reviews for Magento 2