From c83106ea243ce356811acf6258fde5c3710d7ef3 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Thu, 23 Jul 2026 18:09:42 +0600 Subject: [PATCH 1/4] Add cart button integration for block and classic themes - Add Gutenberg cart button block for block theme integration - Enable cart button usage in any block theme - Add global cart button function for classic theme integration - Add [tutor_cart_button] shortcode for theme developers - Add customization options: show/hide icon, show/hide count, custom CSS class - Add cart count badge with WooCommerce-style positioning and styling --- CART_BUTTON_INTEGRATION.md | 280 ++++++++++++++++++ assets/src/js/front/tutor-cart-button.js | 44 +++ assets/src/js/front/tutor-front.js | 1 + .../src/js/gutenberg/cart-button/block.json | 40 +++ assets/src/js/gutenberg/cart-button/edit.js | 112 +++++++ assets/src/js/gutenberg/cart-button/index.js | 10 + .../src/js/gutenberg/cart-button/render.php | 48 +++ assets/src/js/gutenberg/cart-button/save.js | 3 + assets/src/scss/blocks/cart-button.scss | 30 ++ classes/Assets.php | 1 + classes/Gutenberg.php | 18 +- classes/Shortcode.php | 40 +++ includes/ecommerce-functions.php | 101 +++++++ rspack.config.mjs | 5 + 14 files changed, 732 insertions(+), 1 deletion(-) create mode 100644 CART_BUTTON_INTEGRATION.md create mode 100644 assets/src/js/front/tutor-cart-button.js create mode 100644 assets/src/js/gutenberg/cart-button/block.json create mode 100644 assets/src/js/gutenberg/cart-button/edit.js create mode 100644 assets/src/js/gutenberg/cart-button/index.js create mode 100644 assets/src/js/gutenberg/cart-button/render.php create mode 100644 assets/src/js/gutenberg/cart-button/save.js create mode 100644 assets/src/scss/blocks/cart-button.scss diff --git a/CART_BUTTON_INTEGRATION.md b/CART_BUTTON_INTEGRATION.md new file mode 100644 index 0000000000..95fa3ffd76 --- /dev/null +++ b/CART_BUTTON_INTEGRATION.md @@ -0,0 +1,280 @@ +# Tutor LMS Cart Button Integration Guide + +This guide explains how to integrate the Tutor LMS native ecommerce cart button into any WordPress theme, similar to WooCommerce's cart button integration. + +## Overview + +The Tutor LMS plugin now provides a global cart button function that can be used by any theme to display the shopping cart button in the header or any other location. This works with Tutor's native ecommerce system (when monetization is set to 'tutor'). + +## Available Functions + +### 1. `tutor_ecommerce_cart_button( $args = array() )` + +Displays the cart button with icon and item count. + +**Parameters:** +- `$args` (array) - Optional arguments to customize the cart button: + - `class` (string) - CSS class for the cart button. Default: 'cart-contents' + - `title` (string) - Title attribute for the cart link. Default: 'View your shopping cart' + - `show_icon` (bool) - Whether to show the cart icon. Default: true + - `show_count` (bool) - Whether to show the cart item count. Default: true + - `icon_svg` (string) - Custom SVG icon. If not provided, default cart icon will be used + - `before_count` (string) - Text before cart count. Default: '(' + - `after_count` (string) - Text after cart count. Default: ')' + +**Example Usage:** + +```php +// Basic usage - default cart button + + +// Custom CSS class + 'my-theme-cart' ) ); ?> + +// Hide count, show only icon + false ) ); ?> + +// Custom icon and styling + 'header-cart-btn', + 'title' => 'View Cart', + 'before_count' => '', + 'after_count' => ' items', +) ); +?> +``` + +### 2. `tutor_ecommerce_get_cart_count()` + +Returns the current cart item count as an integer. + +**Example Usage:** + +```php + +``` + +## Shortcode Integration + +For themes that prefer shortcode integration, use: + +``` +[tutor_cart_button] +``` + +**Shortcode Attributes:** +- `class` - CSS class for the cart button +- `title` - Title attribute +- `show_icon` - "true" or "false" +- `show_count` - "true" or "false" +- `before_count` - Text before count +- `after_count` - Text after count + +**Example:** +``` +[tutor_cart_button class="my-cart" show_count="false"] +``` + +## Block Theme Integration (Gutenberg) + +For block-based themes (FSE - Full Site Editing), Tutor LMS provides a dedicated Gutenberg block: + +### Tutor Cart Button Block + +**Block Name:** `tutor-gutenberg/cart-button` +**Category:** Tutor +**Icon:** Cart + +**How to Use:** +1. In the WordPress block editor, search for "Tutor Cart Button" +2. Add the block to your header template or any other template +3. The block will automatically render the cart button with icon and count + +**Features:** +- Automatically detects if Tutor native ecommerce is enabled +- Shows cart icon and item count +- Links to the cart page +- Works in any block template (header, footer, etc.) + +**Note:** The block uses dynamic rendering and will display the cart button only when Tutor native ecommerce is active. + +**Important:** This block cannot be added directly to navigation menus. For navigation menu integration, see the section below. + +## Navigation Menu Integration + +### Classic Themes (PHP-based) + +For classic themes using `wp_nav_menu()`, you can manually add the cart button to your navigation menus by editing your theme's header template or using the `wp_nav_menu_items` filter in your theme. + +**Example - Adding to specific menu location via theme:** + +```php +// In your theme's functions.php +add_filter( 'wp_nav_menu_items', function( $items, $args ) { + if ( 'primary' === $args->theme_location && function_exists( 'tutor_ecommerce_cart_button' ) ) { + ob_start(); + tutor_ecommerce_cart_button(); + $cart_button = ob_get_clean(); + $items .= ''; + } + return $items; +}, 10, 2 ); +``` + +This approach gives themes full control over where the cart appears, similar to WooCommerce's philosophy. + +### Block Themes (FSE - Full Site Editing) + +For block themes, the `wp_nav_menu_items` filter does NOT work because block themes use the Navigation block instead of `wp_nav_menu()`. + +**Important Limitation:** WordPress Navigation blocks have a strict whitelist of allowed blocks. Neither custom blocks (like Tutor Cart Button) nor the Shortcode block can be added directly inside Navigation blocks. This is a WordPress core restriction. + +#### Recommended Approach for Block Themes + +Place the **Tutor Cart Button Gutenberg block** in your header template (outside the Navigation block): + +1. Go to Appearance → Editor (Site Editor) +2. Edit your Header template +3. Add the "Tutor Cart Button" block in the header area, alongside or near your Navigation block +4. The block will display the cart icon and count + +This is the standard approach used by WooCommerce and other plugins - the cart button is placed in the header template, not inside the Navigation block itself. + +#### Alternative: Custom Template Part with PHP + +For more control, create a custom template part: + +1. Go to Appearance → Editor (Site Editor) +2. Create a new template part (e.g., "Header Cart") +3. Add a "Custom HTML" block with the shortcode: `[tutor_cart_button]` +4. Insert this template part in your header + +#### Alternative: Theme Customization + +If you need the cart inside the navigation area and have access to theme files: + +1. Create a child theme +2. Override the header template +3. Use the PHP function: `` + +## Theme Integration Examples + +### Example 1: Simple Header Integration + +```php +// In your theme's header.php file + +
+ +
+ +``` + +### Example 2: Conditional Display (Like WooCommerce) + +```php +// Only show if Tutor native ecommerce is active +is_monetize_by_tutor() ) { + tutor_ecommerce_cart_button(); +} +?> +``` + +### Example 3: Custom Styling Integration + +```php +// In your theme's header with custom wrapper + +
+ 'theme-cart-link', + 'show_count' => true, + 'before_count' => '', + 'after_count' => '', + ) ); + ?> +
+ +``` + +### Example 4: Replacing the Current Starter Theme Implementation + +The current implementation in tutorstarter theme can be simplified: + +**Before (Current):** +```php +if ( class_exists( 'Tutor\Ecommerce\CartController' ) && 'tutor' === tutor_utils()->get_option( 'monetize_by' ) && 'header_fullwidth_center' !== get_theme_mod( 'header_type_select' ) ) { + $tutor_native_cart_controller = new CartController(); + if ( true === get_theme_mod( 'cart_btn_toggle', true ) ) { + $items = $tutor_native_cart_controller->get_cart_items()['courses']; + ?> + + + ... + + get_cart_items()['courses']['total_count'] ); + } ?> + + + + 0) { + counter.textContent = event.detail.cart_count; + counter.style.display = 'inline-block'; + } + }); + }); + + // Listen for remove from cart event + document.addEventListener('tutorRemoveCartEvent', function (event) { + const cartCounters = document.querySelectorAll('.tutor-cart-count'); + cartCounters.forEach(function (counter) { + const mode = counter.getAttribute('data-show-count') || 'if_has_items'; + + if (event.detail.cart_count > 0) { + counter.textContent = event.detail.cart_count; + counter.style.display = 'inline-block'; + } else { + if (mode === 'always') { + counter.textContent = '0'; + counter.style.display = 'inline-block'; + } else { + counter.textContent = ''; + counter.style.display = 'none'; + } + } + }); + }); +}); diff --git a/assets/src/js/front/tutor-front.js b/assets/src/js/front/tutor-front.js index ac1229e3d5..b47995c7ae 100644 --- a/assets/src/js/front/tutor-front.js +++ b/assets/src/js/front/tutor-front.js @@ -8,6 +8,7 @@ import './pages/cart'; import './pages/checkout'; import './pages/course-landing'; import './pages/instructor-list-filter'; +import './tutor-cart-button'; /** * Codes from this file should be decentralized according to relavent file/folder structure. diff --git a/assets/src/js/gutenberg/cart-button/block.json b/assets/src/js/gutenberg/cart-button/block.json new file mode 100644 index 0000000000..16778b3a18 --- /dev/null +++ b/assets/src/js/gutenberg/cart-button/block.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "tutor-gutenberg/cart-button", + "title": "Tutor Cart Button", + "category": "tutor", + "icon": "cart", + "description": "Display a cart button with item count for Tutor LMS ecommerce", + "attributes": { + "showCount": { + "type": "string", + "default": "if_has_items" + }, + "customClass": { + "type": "string", + "default": "cart-contents" + }, + "iconColor": { + "type": "string", + "default": "" + }, + "badgeBgColor": { + "type": "string", + "default": "#e74c3c" + }, + "badgeTextColor": { + "type": "string", + "default": "#ffffff" + } + }, + "supports": { + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "tutor-gutenberg-cart-button", + "style": "tutor-cart-button", + "render": "file:./render.php" +} diff --git a/assets/src/js/gutenberg/cart-button/edit.js b/assets/src/js/gutenberg/cart-button/edit.js new file mode 100644 index 0000000000..4cb09f77e7 --- /dev/null +++ b/assets/src/js/gutenberg/cart-button/edit.js @@ -0,0 +1,112 @@ +import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; +import { PanelBody, RadioControl, TextControl, BaseControl } from '@wordpress/components'; +import { ColorPalette } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export default function Edit( { attributes, setAttributes } ) { + const { showCount, customClass, iconColor, badgeBgColor, badgeTextColor } = attributes; + + // Use a sample count for editor preview + const cartCount = 3; + + return ( + <> + + + setAttributes( { showCount: value } ) } + help={ __( 'The editor does not display the real count value, but a placeholder to indicate how it will look on the front-end.', 'tutor' ) } + /> + setAttributes( { customClass: value } ) } + placeholder="cart-contents" + /> + + + + + + + setAttributes( { iconColor: value } ) } + disableCustomColors={ false } + clearable={ true } + /> + + + setAttributes( { badgeBgColor: value } ) } + disableCustomColors={ false } + clearable={ true } + /> + + + + +
+
+ + + + + + + { ( showCount === 'always' || showCount === 'if_has_items' ) && ( + + { cartCount } + + ) } + +
+
+ + ); +} diff --git a/assets/src/js/gutenberg/cart-button/index.js b/assets/src/js/gutenberg/cart-button/index.js new file mode 100644 index 0000000000..b156efcd9f --- /dev/null +++ b/assets/src/js/gutenberg/cart-button/index.js @@ -0,0 +1,10 @@ +import { registerBlockType } from '@wordpress/blocks'; +import metadata from './block.json'; +import Edit from './edit'; +import save from './save'; + +registerBlockType( metadata.name, { + ...metadata, + edit: Edit, + save, +} ); diff --git a/assets/src/js/gutenberg/cart-button/render.php b/assets/src/js/gutenberg/cart-button/render.php new file mode 100644 index 0000000000..f1df34815d --- /dev/null +++ b/assets/src/js/gutenberg/cart-button/render.php @@ -0,0 +1,48 @@ + 'true', + 'show_count' => isset( $attributes['showCount'] ) ? $attributes['showCount'] : 'if_has_items', + 'class' => isset( $attributes['customClass'] ) && ! empty( $attributes['customClass'] ) ? $attributes['customClass'] : 'cart-contents', +); + +$shortcode = '[tutor_cart_button'; +foreach ( $atts as $key => $value ) { + $shortcode .= ' ' . $key . '="' . esc_attr( $value ) . '"'; +} +$shortcode .= ']'; + +// Build inline CSS variables for custom colors set in the block editor. +// The stylesheet consumes these via var(--tutor-cart-*) with hardcoded fallbacks, +// so no