Plugin Directory

Changeset 3797446


Ignore:
Timestamp:
11/12/2026 03:43:15 AM (17 hours ago)
Author:
gravitymaster97
Message:

Description of changes

Location:
gm-woo-product-list-widget
Files:
16 added
16 edited

Legend:

Unmodified
Added
Removed
  • gm-woo-product-list-widget/trunk/build/block.js

    r3180590 r3797446  
    1 const { registerBlockType } = wp.blocks;
    2 const { SelectControl } = wp.components;
    3 const { createElement, useEffect } = wp.element;
     1( function ( wp ) {
     2        'use strict';
    43
    5 registerBlockType('gmwplw/gmwplw-block', {
    6     title: 'Product Shortcode - Widget - Block for Woocommerce',
    7     category: 'common',
    8     attributes: {
    9         selectedOption: {
    10             type: 'string',
    11             default: ''
    12         }
    13     },
    14     edit: (props) => {
    15         const { attributes, setAttributes } = props;
     4        var registerBlockType = wp.blocks.registerBlockType;
     5        var el = wp.element.createElement;
     6        var useEffect = wp.element.useEffect;
    167
    17         // Set the default value to the first option if none is selected
    18         useEffect(() => {
    19             if (!attributes.selectedOption && gmwplwBlockData.options.length > 0) {
    20                 setAttributes({ selectedOption: gmwplwBlockData.options[0].value });
    21             }
    22         }, []);
     8        var options = ( window.gmwplwBlockData && window.gmwplwBlockData.options ) || [];
    239
    24         return createElement(SelectControl, {
    25             label: 'Choose a Product Widget',
    26             value: attributes.selectedOption,
    27             options: gmwplwBlockData.options, // Access the PHP-passed options
    28             onChange: (newValue) => setAttributes({ selectedOption: newValue })
    29         });
    30     },
    31     save: () => {
    32         return null; // Server-side rendering only
    33     }
    34 });
     10        registerBlockType( 'gmwplw/gmwplw-block', {
     11                title: 'Product Shortcode - Widget - Block for Woocommerce',
     12                icon: 'grid-view',
     13                category: 'woocommerce',
     14                attributes: {
     15                        selectedOption: {
     16                                type: 'string',
     17                                default: '',
     18                        },
     19                },
     20
     21                edit: function ( props ) {
     22                        var attributes = props.attributes;
     23                        var setAttributes = props.setAttributes;
     24
     25                        useEffect( function () {
     26                                if ( ! attributes.selectedOption && options.length > 0 ) {
     27                                        setAttributes( { selectedOption: options[ 0 ].value } );
     28                                }
     29                        }, [] );
     30
     31                        if ( options.length === 0 ) {
     32                                return el(
     33                                        'div',
     34                                        { className: 'gmwplw-block-card gmwplw-block-card--empty' },
     35                                        el( 'div', { className: 'gmwplw-block-card__icon' }, '\u25A6' ),
     36                                        el(
     37                                                'p',
     38                                                { className: 'gmwplw-block-card__empty-text' },
     39                                                'No Product Builders found yet. Create one on the ',
     40                                                el(
     41                                                        'a',
     42                                                        { href: ( window.gmwplwBlockData && window.gmwplwBlockData.buildersUrl ) || '#', target: '_blank', rel: 'noopener noreferrer' },
     43                                                        'Product Builders'
     44                                                ),
     45                                                ' admin page, then come back and add this block.'
     46                                        )
     47                                );
     48                        }
     49
     50                        var selected = options.find( function ( option ) {
     51                                return option.value === attributes.selectedOption;
     52                        } );
     53
     54                        return el(
     55                                'div',
     56                                { className: 'gmwplw-block-card' },
     57                                el(
     58                                        'div',
     59                                        { className: 'gmwplw-block-card__header' },
     60                                        el( 'span', { className: 'gmwplw-block-card__icon' }, '\u25A6' ),
     61                                        el( 'span', { className: 'gmwplw-block-card__title' }, 'Product Builder' )
     62                                ),
     63                                el(
     64                                        'label',
     65                                        { className: 'gmwplw-block-card__label', htmlFor: 'gmwplw-block-select' },
     66                                        'Choose a Product Builder'
     67                                ),
     68                                el(
     69                                        'select',
     70                                        {
     71                                                id: 'gmwplw-block-select',
     72                                                className: 'gmwplw-block-select',
     73                                                value: attributes.selectedOption,
     74                                                onChange: function ( event ) {
     75                                                        setAttributes( { selectedOption: event.target.value } );
     76                                                },
     77                                        },
     78                                        options.map( function ( option ) {
     79                                                return el(
     80                                                        'option',
     81                                                        { key: option.value, value: option.value },
     82                                                        option.label
     83                                                );
     84                                        } )
     85                                ),
     86                                selected &&
     87                                        el(
     88                                                'p',
     89                                                { className: 'gmwplw-block-card__hint' },
     90                                                'Showing: ',
     91                                                el( 'strong', {}, selected.label )
     92                                        )
     93                        );
     94                },
     95
     96                save: function () {
     97                        return null; // Server-side rendering only.
     98                },
     99        } );
     100} )( window.wp );
  • gm-woo-product-list-widget/trunk/css/admin-style.css

    r3067768 r3797446  
    1 .showc_taxonomy_val{
    2     display: none;
    3 }
     1#gmwplw-metabox-root,
     2#gmwplw-builder-app-root {
     3        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
     4}
     5
     6#gmwplw-builder-app-root * {
     7        box-sizing: border-box;
     8}
     9
     10.gmwplw-page {
     11        max-width: 1180px;
     12        margin: 24px 20px 40px 0;
     13        display: flex;
     14        flex-direction: column;
     15        gap: 22px;
     16}
     17
     18/* Page header ---------------------------------------------------------- */
     19
     20.gmwplw-page-header {
     21        display: flex;
     22        align-items: center;
     23        justify-content: space-between;
     24        gap: 20px;
     25        background: linear-gradient(135deg, #6C4CF1, #5433D6);
     26        border-radius: 14px;
     27        padding: 24px 28px;
     28        color: #fff;
     29}
     30
     31.gmwplw-page-header__brand {
     32        display: flex;
     33        align-items: center;
     34        gap: 16px;
     35}
     36
     37.gmwplw-page-header__logo {
     38        width: 46px;
     39        height: 46px;
     40        flex-shrink: 0;
     41        display: flex;
     42        align-items: center;
     43        justify-content: center;
     44        background: rgba(255, 255, 255, 0.15);
     45        border-radius: 12px;
     46        font-size: 22px;
     47}
     48
     49.gmwplw-page-header__title {
     50        font-size: 20px;
     51        font-weight: 700;
     52        margin: 0 0 4px 0;
     53        color: #fff;
     54}
     55
     56.gmwplw-page-header__desc {
     57        font-size: 13px;
     58        margin: 0;
     59        color: rgba(255, 255, 255, 0.85);
     60}
     61
     62.gmwplw-page-header__support {
     63        flex-shrink: 0;
     64        background: rgba(255, 255, 255, 0.12) !important;
     65        border-color: rgba(255, 255, 255, 0.4) !important;
     66        color: #fff !important;
     67        white-space: nowrap;
     68}
     69
     70.gmwplw-page-header__support:hover {
     71        background: rgba(255, 255, 255, 0.22) !important;
     72        border-color: #fff !important;
     73        color: #fff !important;
     74}
     75
     76.gmwplw-page-footer {
     77        text-align: center;
     78        font-size: 12.5px;
     79        color: #ADA6BE;
     80        padding: 4px 0 8px;
     81}
     82
     83.gmwplw-page-footer a {
     84        color: #6C4CF1;
     85        text-decoration: none;
     86        font-weight: 600;
     87}
     88
     89.gmwplw-page-footer a:hover {
     90        text-decoration: underline;
     91}
     92
     93/* Stat cards -------------------------------------------------------- */
     94
     95.gmwplw-stats-row {
     96        display: grid;
     97        grid-template-columns: repeat(4, 1fr);
     98        gap: 14px;
     99        margin-bottom: 20px;
     100}
     101
     102.gmwplw-stat-card {
     103        background: #fff;
     104        border: 1px solid #E7E3F3;
     105        border-radius: 12px;
     106        padding: 16px 18px;
     107        display: flex;
     108        flex-direction: column;
     109        gap: 2px;
     110}
     111
     112.gmwplw-stat-card__value {
     113        font-size: 22px;
     114        font-weight: 700;
     115        color: #1E1B2E;
     116}
     117
     118.gmwplw-stat-card__label {
     119        font-size: 12px;
     120        color: #6B6478;
     121}
     122
     123/* General layout ------------------------------------------------------ */
     124
     125.gmwplw-admin-listhead {
     126        display: flex;
     127        align-items: center;
     128        justify-content: space-between;
     129        gap: 20px;
     130        margin-bottom: 4px;
     131}
     132
     133.gmwplw-admin-listhead__title {
     134        font-size: 16px;
     135        font-weight: 600;
     136        margin: 0;
     137        color: #1E1B2E;
     138}
     139
     140.gmwplw-admin-listhead__desc {
     141        font-size: 13px;
     142        color: #6B6478;
     143        margin: 0;
     144        max-width: 520px;
     145}
     146
     147.gmwplw-admin-empty {
     148        color: #6B6478;
     149        font-size: 13px;
     150        padding: 20px 0;
     151}
     152
     153.gmwplw-admin-table {
     154        width: 100%;
     155        border-collapse: collapse;
     156        font-size: 13px;
     157}
     158
     159.gmwplw-admin-table th {
     160        text-align: left;
     161        padding: 10px 12px;
     162        font-size: 11px;
     163        font-weight: 600;
     164        text-transform: uppercase;
     165        letter-spacing: 0.03em;
     166        color: #6B6478;
     167        border-bottom: 1px solid #E7E3F3;
     168}
     169
     170.gmwplw-admin-table td {
     171        padding: 12px;
     172        border-bottom: 1px solid #F0EDF9;
     173        vertical-align: middle;
     174}
     175
     176.gmwplw-admin-table tr:hover td {
     177        background: #FBFAFE;
     178}
     179
     180.gmwplw-admin-table code {
     181        background: #F8F7FC;
     182        color: #5433D6;
     183        padding: 2px 8px;
     184        border-radius: 4px;
     185        font-size: 12px;
     186}
     187
     188.gmwplw-admin-table__actions {
     189        display: flex;
     190        gap: 6px;
     191        justify-content: flex-end;
     192}
     193
     194.gmwplw-admin-icon-btn {
     195        appearance: none;
     196        border: 1px solid #E7E3F3;
     197        background: #fff;
     198        color: #6B6478;
     199        border-radius: 7px;
     200        width: 30px;
     201        height: 30px;
     202        display: inline-flex;
     203        align-items: center;
     204        justify-content: center;
     205        cursor: pointer;
     206        transition: all 0.15s ease;
     207}
     208
     209.gmwplw-admin-icon-btn:hover {
     210        border-color: #6C4CF1;
     211        color: #6C4CF1;
     212}
     213
     214.gmwplw-admin-icon-btn--danger:hover {
     215        border-color: #E24444;
     216        color: #E24444;
     217}
     218
     219.gmwplw-admin-icon-btn:disabled {
     220        opacity: 0.5;
     221        cursor: not-allowed;
     222}
     223
     224.gmwplw-icon {
     225        display: block;
     226}
     227
     228.gmwplw-admin-badge {
     229        display: inline-block;
     230        padding: 3px 10px;
     231        border-radius: 999px;
     232        font-size: 11px;
     233        font-weight: 600;
     234        text-transform: capitalize;
     235        background: #EFEAFF;
     236        color: #5433D6;
     237}
     238
     239.gmwplw-admin-badge--table {
     240        background: #FFF3D6;
     241        color: #8A6300;
     242}
     243
     244.gmwplw-admin-badge--grid {
     245        background: #DFF5E9;
     246        color: #14804A;
     247}
     248
     249.gmwplw-admin-back {
     250        appearance: none;
     251        border: none;
     252        background: none;
     253        color: #6C4CF1;
     254        font-size: 13px;
     255        font-weight: 600;
     256        cursor: pointer;
     257        padding: 0;
     258        align-self: flex-start;
     259}
     260
     261.gmwplw-admin-back:hover {
     262        text-decoration: underline;
     263}
     264
     265.gmwplw-admin-card {
     266        position: relative;
     267        display: flex;
     268        flex-direction: column;
     269        gap: 18px;
     270        background: #fff;
     271        border: 1px solid #E7E3F3;
     272        border-radius: 14px;
     273        padding: 22px 24px;
     274}
     275
     276.gmwplw-admin-loading {
     277        align-items: center;
     278        justify-content: center;
     279        padding: 40px 0;
     280}
     281
     282.gmwplw-admin-spinner {
     283        width: 22px;
     284        height: 22px;
     285        border-radius: 50%;
     286        border: 2px solid #E7E3F3;
     287        border-top-color: #6C4CF1;
     288        animation: gmwplw-admin-spin 0.7s linear infinite;
     289        display: inline-block;
     290}
     291
     292@keyframes gmwplw-admin-spin {
     293        to { transform: rotate(360deg); }
     294}
     295
     296.gmwplw-admin-shortcode {
     297        display: flex;
     298        align-items: center;
     299        gap: 10px;
     300        padding: 10px 14px;
     301        background: #F8F7FC;
     302        border: 1px solid #E7E3F3;
     303        border-radius: 8px;
     304        font-size: 12.5px;
     305}
     306
     307.gmwplw-admin-shortcode code {
     308        flex: 1;
     309}
     310
     311.gmwplw-copy-link {
     312        appearance: none;
     313        border: none;
     314        background: none;
     315        color: #6C4CF1;
     316        font-size: 12px;
     317        font-weight: 600;
     318        cursor: pointer;
     319        display: inline-flex;
     320        align-items: center;
     321        gap: 4px;
     322        padding: 0;
     323        margin-left: auto;
     324}
     325
     326.gmwplw-copy-link:hover {
     327        text-decoration: underline;
     328}
     329
     330.gmwplw-admin-shortcode span {
     331        font-weight: 600;
     332        color: #6B6478;
     333        text-transform: uppercase;
     334        font-size: 11px;
     335        letter-spacing: 0.03em;
     336}
     337
     338.gmwplw-admin-shortcode code {
     339        background: #EFEAFF;
     340        color: #5433D6;
     341        padding: 2px 8px;
     342        border-radius: 4px;
     343}
     344
     345/* Tabs ------------------------------------------------------------- */
     346
     347.gmwplw-tabs {
     348        display: flex;
     349        gap: 4px;
     350        border-bottom: 1px solid #E7E3F3;
     351        margin-bottom: 4px;
     352}
     353
     354.gmwplw-tab {
     355        appearance: none;
     356        border: none;
     357        background: none;
     358        padding: 10px 16px;
     359        font-size: 13px;
     360        font-weight: 600;
     361        color: #6B6478;
     362        cursor: pointer;
     363        border-bottom: 2px solid transparent;
     364        margin-bottom: -1px;
     365        transition: color 0.15s ease, border-color 0.15s ease;
     366}
     367
     368.gmwplw-tab:hover {
     369        color: #1E1B2E;
     370}
     371
     372.gmwplw-tab.is-active {
     373        color: #6C4CF1;
     374        border-bottom-color: #6C4CF1;
     375}
     376
     377.gmwplw-tabpanel {
     378        display: flex;
     379        flex-direction: column;
     380        gap: 16px;
     381        padding-top: 6px;
     382}
     383
     384/* Fields ------------------------------------------------------------ */
     385
     386.gmwplw-admin-field {
     387        display: flex;
     388        flex-direction: column;
     389        gap: 6px;
     390}
     391
     392.gmwplw-admin-field--inline {
     393        flex-direction: row;
     394        align-items: center;
     395        justify-content: space-between;
     396}
     397
     398.gmwplw-admin-field__label {
     399        font-size: 12px;
     400        font-weight: 600;
     401        color: #1E1B2E;
     402}
     403
     404.gmwplw-admin-field__hint {
     405        font-size: 11.5px;
     406        color: #6B6478;
     407        margin: 0;
     408        font-style: italic;
     409}
     410
     411.gmwplw-admin-pills {
     412        display: flex;
     413        flex-wrap: wrap;
     414        gap: 8px;
     415}
     416
     417.gmwplw-admin-pill {
     418        appearance: none;
     419        border: 1px solid #E7E3F3;
     420        background: #fff;
     421        color: #1E1B2E;
     422        padding: 8px 16px;
     423        border-radius: 999px;
     424        font-size: 12.5px;
     425        font-weight: 500;
     426        cursor: pointer;
     427        display: inline-flex;
     428        align-items: center;
     429        gap: 6px;
     430        transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
     431}
     432
     433.gmwplw-admin-pill__icon {
     434        font-size: 13px;
     435}
     436
     437.gmwplw-admin-pill:hover {
     438        border-color: #6C4CF1;
     439}
     440
     441.gmwplw-admin-pill.is-active {
     442        background: #6C4CF1;
     443        border-color: #6C4CF1;
     444        color: #fff;
     445}
     446
     447.gmwplw-admin-input,
     448.gmwplw-admin-select {
     449        width: 100%;
     450        max-width: 320px;
     451        box-sizing: border-box;
     452        padding: 8px 12px;
     453        font-size: 13px;
     454        color: #1E1B2E;
     455        background: #fff;
     456        border: 1px solid #E7E3F3;
     457        border-radius: 8px;
     458        outline: none;
     459        transition: border-color 0.15s ease, box-shadow 0.15s ease;
     460}
     461
     462.gmwplw-admin-input:focus,
     463.gmwplw-admin-select:focus {
     464        border-color: #6C4CF1;
     465        box-shadow: 0 0 0 3px #EFEAFF;
     466}
     467
     468.gmwplw-range-inputs {
     469        display: flex;
     470        align-items: center;
     471        gap: 8px;
     472        max-width: 320px;
     473}
     474
     475.gmwplw-range-inputs .gmwplw-admin-input {
     476        max-width: none;
     477}
     478
     479.gmwplw-range-sep {
     480        color: #ADA6BE;
     481}
     482
     483/* Toggle switch ------------------------------------------------------ */
     484
     485.gmwplw-toggle {
     486        appearance: none;
     487        border: none;
     488        background: none;
     489        display: inline-flex;
     490        align-items: center;
     491        gap: 10px;
     492        cursor: pointer;
     493        padding: 0;
     494}
     495
     496.gmwplw-toggle__track {
     497        width: 38px;
     498        height: 22px;
     499        border-radius: 999px;
     500        background: #E7E3F3;
     501        position: relative;
     502        transition: background 0.15s ease;
     503        flex-shrink: 0;
     504}
     505
     506.gmwplw-toggle__thumb {
     507        position: absolute;
     508        top: 2px;
     509        left: 2px;
     510        width: 18px;
     511        height: 18px;
     512        border-radius: 50%;
     513        background: #fff;
     514        box-shadow: 0 1px 3px rgba(30, 27, 46, 0.25);
     515        transition: transform 0.15s ease;
     516}
     517
     518.gmwplw-toggle.is-on .gmwplw-toggle__track {
     519        background: #6C4CF1;
     520}
     521
     522.gmwplw-toggle.is-on .gmwplw-toggle__thumb {
     523        transform: translateX(16px);
     524}
     525
     526.gmwplw-toggle__label {
     527        font-size: 12.5px;
     528        color: #6B6478;
     529}
     530
     531/* Buttons ------------------------------------------------------------ */
     532
     533.gmwplw-admin-actionbar {
     534        margin-top: 4px;
     535}
     536
     537.gmwplw-admin-btn {
     538        appearance: none;
     539        border: none;
     540        border-radius: 8px;
     541        padding: 10px 22px;
     542        font-size: 13px;
     543        font-weight: 600;
     544        cursor: pointer;
     545        display: inline-flex;
     546        align-items: center;
     547        gap: 6px;
     548        transition: background 0.15s ease, opacity 0.15s ease;
     549}
     550
     551.gmwplw-admin-btn--primary {
     552        background: #6C4CF1;
     553        color: #fff;
     554}
     555
     556.gmwplw-admin-btn--primary:hover {
     557        background: #5433D6;
     558}
     559
     560.gmwplw-admin-btn--primary:disabled {
     561        opacity: 0.6;
     562        cursor: not-allowed;
     563}
     564
     565.gmwplw-admin-btn--outline {
     566        background: #fff;
     567        border: 1px solid #E7E3F3;
     568        color: #1E1B2E;
     569}
     570
     571.gmwplw-admin-btn--outline:hover {
     572        border-color: #6C4CF1;
     573        color: #6C4CF1;
     574}
     575
     576.gmwplw-admin-btn--ghost {
     577        background: none;
     578        color: #6B6478;
     579}
     580
     581.gmwplw-admin-btn--danger {
     582        background: #E24444;
     583        color: #fff;
     584}
     585
     586.gmwplw-admin-btn--danger:hover {
     587        background: #C62F2F;
     588}
     589
     590.gmwplw-admin-toast {
     591        position: fixed;
     592        bottom: 24px;
     593        right: 24px;
     594        background: #1E1B2E;
     595        color: #fff;
     596        padding: 12px 20px;
     597        border-radius: 10px;
     598        font-size: 13px;
     599        font-weight: 500;
     600        box-shadow: 0 4px 16px rgba(30, 27, 46, 0.16);
     601        z-index: 100000;
     602}
     603
     604/* Confirm modal -------------------------------------------------------- */
     605
     606.gmwplw-modal-overlay {
     607        position: fixed;
     608        inset: 0;
     609        background: rgba(30, 27, 46, 0.45);
     610        display: flex;
     611        align-items: center;
     612        justify-content: center;
     613        z-index: 100000;
     614}
     615
     616.gmwplw-modal {
     617        background: #fff;
     618        border-radius: 12px;
     619        padding: 22px 24px;
     620        max-width: 380px;
     621        width: 90%;
     622        box-shadow: 0 12px 32px rgba(30, 27, 46, 0.2);
     623}
     624
     625.gmwplw-modal__title {
     626        margin: 0 0 8px 0;
     627        font-size: 16px;
     628        color: #1E1B2E;
     629}
     630
     631.gmwplw-modal__message {
     632        margin: 0 0 18px 0;
     633        font-size: 13px;
     634        color: #6B6478;
     635        line-height: 1.5;
     636}
     637
     638.gmwplw-modal__actions {
     639        display: flex;
     640        justify-content: flex-end;
     641        gap: 10px;
     642}
     643
     644/* Editor two-column layout -------------------------------------------- */
     645
     646.gmwplw-editor-grid {
     647        display: grid;
     648        grid-template-columns: minmax(0, 1fr) 320px;
     649        gap: 20px;
     650        align-items: start;
     651}
     652
     653.gmwplw-editor-side {
     654        position: sticky;
     655        top: 32px;
     656}
     657
     658@media (max-width: 960px) {
     659        .gmwplw-stats-row {
     660                grid-template-columns: repeat(2, 1fr);
     661        }
     662        .gmwplw-page-header {
     663                flex-direction: column;
     664                align-items: flex-start;
     665        }
     666}
     667
     668/* Checkbox list (categories/tags/attributes) ---------------------------- */
     669
     670.gmwplw-checkbox-list {
     671        display: flex;
     672        flex-wrap: wrap;
     673        gap: 8px 16px;
     674        max-height: 220px;
     675        overflow-y: auto;
     676        padding: 12px;
     677        border: 1px solid #E7E3F3;
     678        border-radius: 8px;
     679        background: #FBFAFE;
     680}
     681
     682.gmwplw-checkbox-item {
     683        display: flex;
     684        align-items: center;
     685        gap: 6px;
     686        font-size: 12.5px;
     687        color: #1E1B2E;
     688        cursor: pointer;
     689        white-space: nowrap;
     690}
     691
     692/* Color input ------------------------------------------------------------ */
     693
     694.gmwplw-color-input {
     695        display: flex;
     696        align-items: center;
     697        gap: 10px;
     698        max-width: 320px;
     699}
     700
     701.gmwplw-color-input input[type="color"] {
     702        width: 40px;
     703        height: 36px;
     704        padding: 2px;
     705        border: 1px solid #E7E3F3;
     706        border-radius: 8px;
     707        cursor: pointer;
     708        background: #fff;
     709}
     710
     711.gmwplw-color-input .gmwplw-admin-input {
     712        max-width: none;
     713}
     714
     715/* Column builder ----------------------------------------------------------- */
     716
     717.gmwplw-column-builder {
     718        display: flex;
     719        flex-direction: column;
     720        gap: 12px;
     721}
     722
     723.gmwplw-column-list {
     724        display: flex;
     725        flex-direction: column;
     726        gap: 6px;
     727}
     728
     729.gmwplw-column-row {
     730        display: flex;
     731        align-items: center;
     732        gap: 10px;
     733        padding: 8px 10px;
     734        border: 1px solid #E7E3F3;
     735        border-radius: 8px;
     736        background: #fff;
     737        cursor: grab;
     738}
     739
     740.gmwplw-column-row.is-dragging {
     741        opacity: 0.5;
     742        border-style: dashed;
     743}
     744
     745.gmwplw-column-row__grip {
     746        color: #ADA6BE;
     747        display: flex;
     748        flex-shrink: 0;
     749}
     750
     751.gmwplw-column-row__label {
     752        flex: 1;
     753        font-size: 13px;
     754        font-weight: 600;
     755        color: #1E1B2E;
     756        display: flex;
     757        align-items: center;
     758        gap: 8px;
     759}
     760
     761.gmwplw-column-row__tag {
     762        font-size: 11px;
     763        font-weight: 400;
     764        color: #ADA6BE;
     765        font-style: italic;
     766}
     767
     768.gmwplw-column-row__actions {
     769        display: flex;
     770        align-items: center;
     771        gap: 6px;
     772        flex-shrink: 0;
     773}
     774
     775.gmwplw-mini-btn {
     776        appearance: none;
     777        border: 1px solid #E7E3F3;
     778        background: #fff;
     779        color: #6B6478;
     780        width: 26px;
     781        height: 26px;
     782        border-radius: 6px;
     783        display: inline-flex;
     784        align-items: center;
     785        justify-content: center;
     786        cursor: pointer;
     787        font-size: 12px;
     788        transition: all 0.15s ease;
     789}
     790
     791.gmwplw-mini-btn:hover:not(:disabled) {
     792        border-color: #6C4CF1;
     793        color: #6C4CF1;
     794}
     795
     796.gmwplw-mini-btn:disabled {
     797        opacity: 0.35;
     798        cursor: not-allowed;
     799}
     800
     801.gmwplw-mini-btn--danger:hover {
     802        border-color: #E24444;
     803        color: #E24444;
     804}
     805
     806.gmwplw-column-add {
     807        display: flex;
     808        flex-direction: column;
     809        gap: 10px;
     810        padding-top: 8px;
     811        border-top: 1px dashed #E7E3F3;
     812}
     813
     814.gmwplw-column-add__row {
     815        display: flex;
     816        flex-wrap: wrap;
     817        gap: 8px;
     818        align-items: center;
     819}
     820
     821.gmwplw-column-add__row .gmwplw-admin-input,
     822.gmwplw-column-add__row .gmwplw-admin-select {
     823        max-width: 240px;
     824}
  • gm-woo-product-list-widget/trunk/gm-woo-product-list-widget.php

    r3180590 r3797446  
    11<?php
    22/**
    3  * Plugin Name: Product List / Grid View for Woocommerce
    4  * Description: GM Woo Product list Widget to show product list in widget with verious option
    5  * Version:     1.0
     3 * Plugin Name: Product Table, Grid, List Builder For WooCommerce
     4 * Description: Build reusable product Table, Grid, and List layouts for WooCommerce, insert them anywhere via shortcode or block.
     5 * Version:     3.4.0
    66 * Author:      Gravity Master
    77 * License:     GPLv2 or later
    … …  
    4444spl_autoload_register('gmwplw_class_auto_loader');
    4545
     46/**
     47 * Declare compatibility with WooCommerce High-Performance Order Storage (HPOS).
     48 * This plugin doesn't touch order data directly, so it's compatible as-is.
     49 */
     50add_action( 'before_woocommerce_init', function () {
     51        if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) {
     52                \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
     53        }
     54} );
     55
    4656/* Initialize all modules now. */
    4757
    48 new GMWPLW_Comman();
     58new GMWPLW_Store();
    4959new GMWPLW_Admin();
    5060new GMWPLW_Block();
    5161new GMWPLW_Frontend();
     62new GMWPLW_Api();
    5263
    53 include(GMWPLW_PLUGIN_DIR . 'includes/GMWPLW_Widget.php');
     64/**
     65 * Add a "Settings" link on the Plugins page pointing to the Product Builders screen.
     66 */
     67if ( ! function_exists( 'gmwplw_plugin_action_links' ) ) {
     68        function gmwplw_plugin_action_links( $links ) {
     69                $settings_link = '<a href="' . esc_url( admin_url( 'admin.php?page=gmwplw-builders' ) ) . '">' . __( 'Settings', 'gmwplw' ) . '</a>';
     70                array_unshift( $links, $settings_link );
     71                return $links;
     72        }
     73}
     74add_filter( 'plugin_action_links_' . GMWPLW_PLUGIN_BASENAME, 'gmwplw_plugin_action_links' );
    5475
    55 add_action( 'wp_enqueue_scripts',  'gmwplw_insta_scritps'  );
    56 function gmwplw_insta_scritps () {
    57                 wp_enqueue_style('gmwqp-style', GMWPLW_PLUGIN_URL . '/css/style.css', array(), '1.0.0', 'all');
    58         }
    59 ?>
  • gm-woo-product-list-widget/trunk/includes/GMWPLW_Admin.php

    r3180590 r3797446  
    22
    33/**
    4  * This class is loaded on the back-end since its main job is
    5  * to display the Admin to box.
     4 * This class registers the top-level "Product Builders" admin page.
     5 * The page itself is a React app written in real JSX (src-admin/admin-app.jsx),
     6 * compiled ahead of time with @wordpress/scripts (see package.json — run
     7 * `npm install && npm run build` after editing the source file). It talks
     8 * to the REST endpoints in GMWPLW_Api / GMWPLW_Store.
    69 */
    710
    811class GMWPLW_Admin {
    9        
    10         protected static $instance = NULL;
    1112
     13        const PAGE_SLUG = 'gmwplw-builders';
    1214
    1315        public function __construct () {
    14                 add_action( 'init', array( $this, 'GMWPLW_init' ) );
    15                 add_action( 'add_meta_boxes', array($this, 'GMWPLW_add_meta_box'));
    16                 add_action('admin_enqueue_scripts', array($this, 'GMWPLW_scripts'));
    17                
    18                 add_action( 'wp_ajax_gmwqp_change_tax', array( $this, 'gmwqp_change_tax' ));
    19                 add_action( 'wp_ajax_nopriv_gmwqp_change_tax', array( $this, 'gmwqp_change_tax' ));
    20 
    21                 add_action( 'edit_post', array($this, 'GMWPLW_meta_save'), 10, 2);
     16                add_action( 'admin_menu', array( $this, 'GMWPLW_admin_menu' ) );
     17                add_action( 'admin_enqueue_scripts', array( $this, 'GMWPLW_scripts' ) );
    2218        }
    2319
    24         public function GMWPLW_init () {
    25                
    26                 $args = array(
    27                 'label'  => __( 'Product Widget', 'gmwrpm' ),
    28                 'public'             => false, // Set to false to hide it from the frontend.
    29                 'publicly_queryable' => false, // Set to false to prevent queries from the frontend.
    30                 'show_ui'            => true, // Show in the admin dashboard.
    31                 'show_in_admin_bar'  => true, // Show in the admin bar.
    32                 'query_var'          => false, // Disable query variable.
    33                 'rewrite'            => false, // Disable URL rewriting.
    34                 'capability_type'    => 'post',
    35                 'has_archive'        => false, // Disable archives.
    36                 'menu_position'      => null,
    37                 'supports'  => array( 'title' ),
    38             );
    39             register_post_type( 'product_widget', $args );
    40 
     20        public function GMWPLW_admin_menu() {
     21                add_menu_page(
     22                        __( 'Product Builders', 'gmwplw' ),
     23                        __( 'Product Builders', 'gmwplw' ),
     24                        'manage_woocommerce',
     25                        self::PAGE_SLUG,
     26                        array( $this, 'GMWPLW_render_page' ),
     27                        'dashicons-grid-view',
     28                        56
     29                );
    4130        }
    4231
    43         public function GMWPLW_add_meta_box() {
    44             add_meta_box(
    45                 'GMWPLW_metabox',
    46                 __( 'Product Widget Settings', 'gmwrpm' ),
    47                 array($this, 'GMWPLW_metabox_rule'),
    48                 'product_widget',
    49                 'normal'
    50             );
    51    }
    52    public function GMWPLW_meta_save( $post_id, $post ) {
    53                 if ($post->post_type != 'product_widget') { return; }
    54                 if ( !current_user_can( 'edit_post', $post_id )) return;
     32        public function GMWPLW_render_page() {
     33                $asset_file = GMWPLW_PLUGIN_DIR . 'build/admin/admin-app.asset.php';
    5534
    56                 update_post_meta($post_id, 'gmwplw_select_type', sanitize_text_field($_POST['gmwplw_select_type']));
    57             update_post_meta($post_id, 'gmwplw_product_show', intval($_POST['gmwplw_product_show']));
    58             update_post_meta($post_id, 'gmwplw_show_per_column', intval($_POST['gmwplw_show_per_column']));
    59             update_post_meta($post_id, 'gmwplw_thum', sanitize_text_field($_POST['gmwplw_thum']));
    60             update_post_meta($post_id, 'gmwplw_order_by', sanitize_text_field($_POST['gmwplw_order_by']));
    61             update_post_meta($post_id, 'gmwplw_order', sanitize_text_field($_POST['gmwplw_order']));
    62             update_post_meta($post_id, 'gmwplw_select_tax_val', sanitize_text_field($_POST['gmwplw_select_tax_val']));
    63             update_post_meta($post_id, 'gmwplw_layout', sanitize_text_field($_POST['gmwplw_layout']));
    64            
    65    }
    66    public function GMWPLW_metabox_rule( $post ) {
    67         $gmwplw_select_type = get_post_meta( $post->ID,'gmwplw_select_type', true);
    68         if (empty($gmwplw_select_type)) {
    69             $gmwplw_select_type = 'all';
    70         }
    71         $gmwplw_product_show = get_post_meta( $post->ID,'gmwplw_product_show', true);
    72         if (empty($gmwplw_product_show)) {
    73             $gmwplw_product_show = 5;
    74         }
    75         $gmwplw_show_per_column = get_post_meta( $post->ID,'gmwplw_show_per_column', true);
    76         if (empty($gmwplw_show_per_column)) {
    77             $gmwplw_show_per_column = 3;
     35                if ( ! file_exists( $asset_file ) ) {
     36                        echo '<div class="notice notice-error"><p>';
     37                        echo esc_html__( 'Product Builders: the admin app has not been built yet. Run "npm install && npm run build" in the plugin folder.', 'gmwplw' );
     38                        echo '</p></div>';
     39                        return;
     40                }
     41
     42                echo '<div id="gmwplw-builder-app-root"></div>';
    7843        }
    7944
    80        
    81         $gmwplw_thum = get_post_meta( $post->ID,'gmwplw_thum', true);
    82         if (empty($gmwplw_thum)) {
    83             $gmwplw_thum = 'yes';
    84         }
    85         $gmwplw_order_by = get_post_meta( $post->ID,'gmwplw_order_by', true);
    86         $gmwplw_order = get_post_meta( $post->ID,'gmwplw_order', true);
    87         $gmwplw_select_tax_val = get_post_meta( $post->ID,'gmwplw_select_tax_val', true);
    88         $gmwplw_layout = get_post_meta( $post->ID,'gmwplw_layout', true);
    89         if (empty($gmwplw_layout)) {
    90             $gmwplw_layout = 'list';
    91         }
    92        
    93        
    94         ?>
    95         <div class="gmwplw_settings">
    96                 <table>
    97                         <tr>
    98                                 <td>Shortcode</td>
    99                                 <td>
    100                                         <code>[gmwplw_product_layout id="<?php echo $post->ID;?>"]</code>
    101                                 </td>
    102                         </tr>
    103                         <tr>
    104                                 <td>Display Layout</td>
    105                                 <td>
    106                                         <input  name="gmwplw_layout" type="radio" value="list" <?php checked( $gmwplw_layout, 'list' ); ?> /> List
    107                                         <input  name="gmwplw_layout" type="radio" value="grid" <?php checked( $gmwplw_layout, 'grid' ); ?> /> Grid
    108                                 </td>
    109                         </tr>
    110                         <tr>
    111                                 <td>Select Type</td>
    112                                 <td>
    113                                         <?php
    114                                         $taxonomies=get_object_taxonomies( 'product', 'objects' );
    115                        
    116                                         $taxc = array();
    117                                         foreach ($taxonomies as $key => $value) {
    118                                                 if($value->show_ui){
    119                                                         $taxc[$key] = $value->label;
    120                                                 }
    121                                         }
    122                                         ?>
    123                                         <input 
    124                                         name="gmwplw_select_type"
    125                                         type="radio"
    126                                         value="all" 
    127                                         iscal="no"
    128                                         <?php checked( $gmwplw_select_type, 'all' ); ?> 
    129                                         class="changecat"/> All<br/>
    130                                         <input 
    131                                         name="gmwplw_select_type"
    132                                         type="radio"
    133                                         value="featured" 
    134                                         iscal="no"
    135                                         <?php checked( $gmwplw_select_type, 'featured' ); ?> 
    136                                         class="changecat"/> Featured<br/>
    137                                         <input 
    138                                         name="gmwplw_select_type"
    139                                         type="radio"
    140                                         value="sale"
    141                                         iscal="no" 
    142                                         <?php checked( $gmwplw_select_type, 'sale' ); ?> 
    143                                         class="changecat"/> On-Sale<br/>
    144                                         <?php
    145                                         foreach($taxc as $taxckey=>$taxcval){
    146                                                 $isselcted = (($gmwplw_select_type ==$taxckey) ? 'checked' : '');
    147                                                 $arr_make = array('product_cat','product_tag');
    148                                                 $isdisabled = ((!in_array($taxckey,$arr_make)) ? 'disabled' : '');
    149                                                 echo '<input 
    150                                                                 name="gmwplw_select_type"
    151                                                                 type="radio"
    152                                                                 value="'.$taxckey.'"
    153                                                                 iscal="yes" 
    154                                                                 '.$isselcted.'
    155                                                                 '.$isdisabled.'
    156                                                                 class="changecat"/> '.$taxcval;
    157                                                 if($isdisabled=='disabled'){
    158                                                         echo "&nbsp;&nbsp;<a href='https://www.codesmade.com/store/product-list-widget-for-woocommerce-pro/' target='_blank'>Get Pro</a>";
    159                                                 }
    160                                                 echo '<br/>';
    161                                                 /*echo '<option 
    162                                                 iscal="yes" 
    163                                                 value="'.$taxckey.'"
    164                                                 '.$isselcted.'
    165                                                  '.$isdisabled.'>'.$taxcval.'</option>';*/
    166                                         }
    167                                         ?>
    168                                        
    169                                 </td>
    170                         </tr>
    171                         <?php
    172                         if (array_key_exists($gmwplw_select_type, $taxc)) {
    173                                 $istax=true;
    174                         }else{
    175                                 $istax=false;
    176                         }
    177                         ?>
    178                         <tr class="showc_taxonomy_val" style="<?php echo ($istax == true) ? 'display: table-row' : ''; ?>">
    179                                 <td>Select Taxonomy Value</td>
    180                                 <td>
    181                                         <?php
    182                                         if($istax == true){
    183                                                 $terms = get_terms( $gmwplw_select_type, array(
    184                                                             'hide_empty' => false,
    185                                                         ) );
    186                                                 $taxc = array();
    187                                                 foreach ($terms as $key => $value) {
    188                                                         $taxc[$value->term_id] = $value->name;
    189                                                 }
    190                                         }
    191                                         ?>
    192                                         <select class='changetax_val widefat' name="gmwplw_select_tax_val" >
    193                                                 <?php
    194                                                 if($istax == true){
    195                                                         foreach($taxc as $taxckey=>$taxcval){
    196                                                                 echo '<option value="'.$taxckey.'" '.(($gmwplw_select_tax_val==$taxckey) ? 'selected' : '').'>'.$taxcval.'</option>';
    197                                                         }
    198                                                 }
    199                                                 ?>
    200                                         </select>
    201                                 </td>
    202                         </tr>
    203                         <tr>
    204                                 <td>No of Products Per Column <i>(Just work for grid layout)</i></td>
    205                                 <td>
    206                                         <input type="number" name="gmwplw_show_per_column"  class="widefat" value="<?php echo esc_attr($gmwplw_show_per_column); ?>">
    207                                 </td>
    208                         </tr>
    209                         <tr>
    210                                 <td>No of Products </td>
    211                                 <td>
    212                                         <input type="number" name="gmwplw_product_show"  class="widefat" value="<?php echo esc_attr($gmwplw_product_show); ?>">
    213                                 </td>
    214                         </tr>
    215                         <tr>
    216                                 <td>Show product thumbnails?</td>
    217                                 <td>
    218                                         <input  name="gmwplw_thum" type="radio" value="yes" <?php checked( $gmwplw_thum, 'yes' ); ?> /> Yes
    219                                         <input  name="gmwplw_thum" type="radio" value="no" <?php checked( $gmwplw_thum, 'no' ); ?> /> No
    220                                 </td>
    221                         </tr>
    222                        
    223                         <tr>
    224                                 <td>Order By</td>
    225                                 <td>
    226                                         <select  name="gmwplw_order_by"  class="widefat">
    227                                                 <option value='post_title' <?php echo ($gmwplw_order_by == 'post_title') ? 'selected' : ''; ?>>Product Name</option>
    228                                                 <option value='id' <?php echo ($gmwplw_order_by == 'id') ? 'selected' : ''; ?>>Product ID</option>
    229                                                 <option value='date' <?php echo ($gmwplw_order_by == 'date') ? 'selected' : ''; ?>>Date Published</option>
    230                                                 <option value='modified' <?php echo ($gmwplw_order_by == 'modified') ? 'selected' : ''; ?>>Last Modified</option>
    231                                                 <option value='rand' <?php echo ($gmwplw_order_by == 'rand') ? 'selected' : ''; ?>>Random</option>
    232                                                 <option value='total_sales' <?php echo ($gmwplw_order_by == 'total_sales') ? 'selected' : ''; ?>>Total Sales</option>
    233                                                 <option value='none' <?php echo ($gmwplw_order_by == 'none') ? 'selected' : ''; ?>>None</option>
    234                                         </select>
    235                                 </td>
    236                         </tr>
    237                         <tr>
    238                                 <td>Order By</td>
    239                                 <td>
    240                                         <select  name="gmwplw_order" class="widefat">
    241                                                 <option value='ASC' <?php echo ($gmwplw_order == 'ASC') ? 'selected' : ''; ?>>Ascending</option>
    242                                                 <option value='DESC' <?php echo ($gmwplw_order == 'DESC') ? 'selected' : ''; ?>>Descending</option>
    243                                         </select>
    244                                 </td>
    245                         </tr>
    246                 </table>
    247         </div>
    248         <?php
    249    }
     45        public function GMWPLW_scripts( $hook ) {
     46                if ( 'toplevel_page_' . self::PAGE_SLUG !== $hook ) {
     47                        return;
     48                }
    25049
    251         public static function get_instance()
    252     {
    253         if ( NULL === self::$instance )
    254             self::$instance = new self;
     50                $asset_file = GMWPLW_PLUGIN_DIR . 'build/admin/admin-app.asset.php';
     51                if ( ! file_exists( $asset_file ) ) {
     52                        return;
     53                }
     54                $asset = include $asset_file;
    25555
    256         return self::$instance;
    257     }
    258        
    259        
    260         public function gmwqp_change_tax() {
    261                 $htmlfinal = '';
    262                 $terms = get_terms( sanitize_text_field($_REQUEST['option']), array(
    263                                                     'hide_empty' => false,
    264                                                 ) );
    265                 foreach ($terms as $key => $value) {
    266                         $htmlfinal .= '<option value="'.$value->term_id.'" >'.$value->name.'</option>';
    267                 }
    268                 echo html_entity_decode(esc_html($htmlfinal)) ;
    269                
    270                 exit;
    271         }
    272        
     56                wp_enqueue_script(
     57                        'gmwplw-admin-app',
     58                        GMWPLW_PLUGIN_URL . 'build/admin/admin-app.js',
     59                        $asset['dependencies'],
     60                        $asset['version'],
     61                        true
     62                );
    27363
     64                wp_enqueue_style( 'gmwplw_admin_css', GMWPLW_PLUGIN_URL . 'css/admin-style.css', array(), $asset['version'] );
    27465
    275         public function GMWPLW_scripts(){
    276                 wp_enqueue_script('gmwplwadmin-script', GMWPLW_PLUGIN_URL . '/js/admin-script.js', array(), '1.0.0', true );
    277                 wp_localize_script( 'gmwplwadmin-script', 'gmwplw_ajax_object', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
    278                 wp_enqueue_style('gmwplw_admin_css', GMWPLW_PLUGIN_URL.'css/admin-style.css');
     66                wp_localize_script( 'gmwplw-admin-app', 'gmwplwAdminData', array(
     67                        'restRoot' => esc_url_raw( rest_url() ),
     68                        'nonce'    => wp_create_nonce( 'wp_rest' ),
     69                ) );
    27970        }
    28071
    281        
    282 
    28372}
    284 
    285 ?>
  • gm-woo-product-list-widget/trunk/includes/GMWPLW_Block.php

    r3180590 r3797446  
    11<?php
    22class GMWPLW_Block {
    3        
     3
    44        protected static $instance = NULL;
    55
    … …  
    77        public function __construct () {
    88                add_action( 'init', array( $this, 'GMWPLW_init' ) );
    9                
     9
    1010        }
    1111
    … …  
    1515                GMWPLW_PLUGIN_URL . '/build/block.js',
    1616                array('wp-blocks', 'wp-element', 'wp-editor'),
    17                 '1.0.0',
     17                '3.4.0',
    1818                true
    1919            );
    20             $args = array(
    21                             'post_type' => 'product_widget',
    22                             'posts_per_page' => -1,
    23                             'orderby' => 'date',
    24                             'order' => 'DESC',
    25                             'post_status' => 'publish', // Retrieve only published posts.
    26                         );
    27             $posts = get_posts($args);
    28             $arr= array();
    29             foreach ($posts as $post) {
    30                 $arr[]= array('label' => $post->post_title, 'value' => $post->ID);
     20            wp_register_style(
     21                'gmwplw-block-editor-style',
     22                GMWPLW_PLUGIN_URL . '/css/block-editor.css',
     23                array(),
     24                '3.4.0'
     25            );
     26
     27            $builders = GMWPLW_Store::get_all();
     28            $arr = array();
     29            foreach ( $builders as $id => $builder ) {
     30                $arr[] = array(
     31                        'label' => isset( $builder['name'] ) ? $builder['name'] : 'Untitled Builder',
     32                        'value' => $id,
     33                );
    3134            }
    32              // Pass dynamic options to JavaScript
     35            // Pass dynamic options to JavaScript
    3336            wp_localize_script('gmwplw-block-script', 'gmwplwBlockData', array(
    34                 'options' => $arr
     37                'options' => $arr,
     38                'buildersUrl' => admin_url( 'admin.php?page=gmwplw-builders' ),
    3539            ));
    3640
    3741            register_block_type('gmwplw/gmwplw-block', array(
    3842                'editor_script' => 'gmwplw-block-script',
     43                'editor_style'  => 'gmwplw-block-editor-style',
    3944                'render_callback' => array( $this,'gmwplw_block_render'),
    4045            ));
    … …  
    4247
    4348        public function gmwplw_block_render($attributes) {
    44             if(isset($attributes['selectedOption'])){
    45                 ob_start();
    46                 GMWPLW_returndata($attributes['selectedOption']);
    47                 $output = ob_get_clean();
    48                 return $output ;
    49             }else{
    50                 return 'No option selected';
     49            if ( empty( $attributes['selectedOption'] ) ) {
     50                return 'No Product Builder selected.';
    5151            }
    52            
     52
     53            $builder_id = sanitize_text_field( $attributes['selectedOption'] );
     54            if ( null === GMWPLW_Store::get( $builder_id ) ) {
     55                return 'Product Builder not found.';
     56            }
     57
     58            // Ensure the shared front-end script/style are registered even if
     59            // GMWPLW_Frontend::GMWPLW_register_assets() hasn't run yet in this context.
     60            if ( ! wp_script_is( 'gmwplw-frontend-app', 'registered' ) ) {
     61                wp_register_script(
     62                        'gmwplw-frontend-app',
     63                        GMWPLW_PLUGIN_URL . '/build/frontend-app.js',
     64                        array( 'wp-element' ),
     65                        '3.4.0',
     66                        true
     67                );
     68                wp_register_style(
     69                        'gmwplw-frontend-app-style',
     70                        GMWPLW_PLUGIN_URL . '/css/frontend-app.css',
     71                        array(),
     72                        '3.4.0'
     73                );
     74                wp_localize_script( 'gmwplw-frontend-app', 'gmwplwFrontendData', array(
     75                        'restRoot' => esc_url_raw( rest_url() ),
     76                        'ajaxUrl'  => admin_url( 'admin-ajax.php' ),
     77                        'cartUrl'  => function_exists( 'wc_get_cart_url' ) ? wc_get_cart_url() : '',
     78                ) );
     79            }
     80
     81            wp_enqueue_script( 'gmwplw-frontend-app' );
     82            wp_enqueue_style( 'gmwplw-frontend-app-style' );
     83
     84            return sprintf(
     85                '<div class="gmwplw-mount" data-widget-id="%s"></div>',
     86                esc_attr( $builder_id )
     87            );
    5388        }
    5489
  • gm-woo-product-list-widget/trunk/includes/GMWPLW_Frontend.php

    r3067768 r3797446  
    22
    33class GMWPLW_Frontend {
    4        
     4
    55        protected static $instance = NULL;
    66
    77        public function __construct () {
     8                add_action( 'wp_enqueue_scripts', array( $this, 'GMWPLW_register_assets' ) );
    89                add_shortcode( 'gmwplw_product_layout', array( $this, 'gmwplw_product_layout' ) );
    9 
    1010        }
    1111
    12         public function gmwplw_product_layout($atts) {
    13                
    14         $atts = shortcode_atts(array(
    15             'id' => '',
    16         ), $atts);
     12        /**
     13         * Registers (but does not necessarily enqueue) the shared React
     14         * front-end script/style, and localizes the REST root once so both
     15         * the shortcode and the block's view script can rely on it.
     16         */
     17        public function GMWPLW_register_assets() {
     18                wp_register_script(
     19                        'gmwplw-frontend-app',
     20                        GMWPLW_PLUGIN_URL . '/build/frontend-app.js',
     21                        array( 'wp-element' ),
     22                        '3.4.0',
     23                        true
     24                );
     25                wp_register_style(
     26                        'gmwplw-frontend-app-style',
     27                        GMWPLW_PLUGIN_URL . '/css/frontend-app.css',
     28                        array(),
     29                        '3.4.0'
     30                );
     31                wp_localize_script( 'gmwplw-frontend-app', 'gmwplwFrontendData', array(
     32                        'restRoot' => esc_url_raw( rest_url() ),
     33                        'ajaxUrl'  => admin_url( 'admin-ajax.php' ),
     34                        'cartUrl'  => function_exists( 'wc_get_cart_url' ) ? wc_get_cart_url() : '',
     35                ) );
     36        }
    1737
    18         if (!empty($atts['id'])) {
    19             $post_id = intval($atts['id']);
     38        public function gmwplw_product_layout( $atts ) {
     39                $atts = shortcode_atts( array(
     40                        'id' => '',
     41                ), $atts );
    2042
    21             // Now you can use $product_id in your layout logic
    22             // Example: Fetch and display product details based on $product_id
    23            
    24             ob_start();
    25             GMWPLW_returndata($post_id);
    26             $html_output = ob_get_clean();
     43                if ( empty( $atts['id'] ) ) {
     44                        return "<p>Error: Missing 'id' attribute in the shortcode.</p>";
     45                }
    2746
    28             return $html_output;
    29         } else {
    30             // Handle the case where 'id' attribute is missing
    31             return "<p>Error: Missing 'id' attribute in the shortcode.</p>";
    32         }
    33     }
     47                $builder_id = sanitize_text_field( $atts['id'] );
    3448
    35        
     49                if ( null === GMWPLW_Store::get( $builder_id ) ) {
     50                        return '<p>Error: Product Builder not found.</p>';
     51                }
     52
     53                wp_enqueue_script( 'gmwplw-frontend-app' );
     54                wp_enqueue_style( 'gmwplw-frontend-app-style' );
     55
     56                return sprintf(
     57                        '<div class="gmwplw-mount" data-widget-id="%s"></div>',
     58                        esc_attr( $builder_id )
     59                );
     60        }
    3661
    3762}
  • gm-woo-product-list-widget/trunk/readme.txt

    r3613245 r3797446  
    1 === Product List / Grid View for Woocommerce ===
    2 Tested up to: 7.0
    3 stable tag:1.0
    4 Tags: product widget woocommerce,product list for woocommerce , category filter woocommerce, woocommerce widget product, woocommerce best sale product
     1=== Product Table, Grid, List Builder For WooCommerce ===
     2Tested up to: 6.2
     3Stable tag: 3.4.0
     4Tags: product table woocommerce, product grid woocommerce, product list builder, woocommerce shortcode builder, category filter woocommerce
    55License: GPLv2 or later
    66License URI: http://www.gnu.org/licenses/gpl-3.0.html
    … …  
    88== Description ==
    99
    10 **WooCommerce Products List / Grid View** allows you to display a Fileter selection of products. woocommerce Product display shortcode uses the same styling as the WooCommerce built-in Product List widget. The products are being displayed in the order of much of filter like Product name, Product Id, Date Published, Random, Last Modified .
     10**Product Table, Grid, List Builder For WooCommerce** lets you build unlimited, reusable product displays for your WooCommerce store — no coding required. Design a layout once in the visual builder, then drop it anywhere on your site with a short, simple shortcode or the built-in Gutenberg block.
    1111
    12 [Demo](https://codesmade.com/demo/blog/) | [Support](https://www.codesmade.com/contact-us/)
     12= Key Features =
    1313
     14* **Drag-and-Drop Column Builder** — Visually add, remove, and reorder table/grid/list columns: Image, Name, SKU, Price, Categories, Tags, Attributes, Variations, Rating, Stock, and Add to Cart.
     15* **Custom Field Columns** — Pull in any product custom field (post meta) as its own column, with a custom label.
     16* **Three Display Layouts** — List, Grid, and Table, all driven by the same column configuration so you can switch layouts without rebuilding anything.
     17* **Advanced Query Builder** — Filter products by category, tag, and attribute (combinable), quick filters for Featured/On Sale/Best Sellers, price range, stock status, and specific product exclusions.
     18* **Front-end Search** — Let shoppers search within a builder's products directly from the widget.
     19* **Front-end Filters** — Optional category, tag, attribute, price range, and in-stock filter controls for visitors, with a one-click "Clear filters" reset.
     20* **Sortable Columns** — Let visitors click Name or Price column headers (table layout) to sort products live.
     21* **Add to Cart From the Table** — Ajax add-to-cart straight from the list, grid, or table — no page reload, with instant "Added ✓" feedback.
     22* **Floating Cart** — Optional floating cart bubble so shoppers always see they've added something.
     23* **Appearance Customization** — Accent color, text color, border color, font size, border radius, border width, and hover effects (lift, zoom, or none) — all per builder.
     24* **Flexible Pagination** — Load More button, numbered pages, or no pagination at all.
     25* **Duplicate & Reuse** — Clone any builder in one click and tweak the copy instead of starting from scratch.
     26* **Unlimited Builders** — Create as many Table, Grid, or List builders as you need, each with its own simple shortcode (e.g. `[gmwplw_product_layout id="1"]`) and optional Gutenberg block.
     27* **WooCommerce HPOS Compatible** — Fully compatible with WooCommerce's High-Performance Order Storage.
    1428
     29= How It Works =
    1530
    16 **Woocommerce Display Products by Category** easy to show in widget with display category wise product in woocommerce.
     311. Go to **Product Builders** in your WordPress admin.
     322. Click **New Builder**, choose a layout (List, Grid, or Table), and configure your columns, filters, and appearance.
     333. Copy the generated shortcode (or use the Gutenberg block) and paste it into any post, page, or template.
    1734
    18 #### Features
     35== Changelog ==
    1936
    20 <ul>
    21 <li>One Click installation</li>
    22 <li>Filter by Custom Taxonomy</li>
    23 <li>Filter by <strong>WooCommerce List Products By Category Widget</strong></li>
    24 <li>Filter by Product Attribute <a href="https://www.codesmade.com/store/product-list-widget-for-woocommerce-pro/">Get Pro</a></li>
    25 <li>Filter by Product Featured</li>
    26 <li>Filter by Product On-sale</li>
    27 <li>Filter by <strong>Best Selling Products Widget</strong></li>
    28 <li>Order by Product name, Product Id, Date Published, Random, Last Modified, None</li>
    29 <li>Mobile Friendly</li>
    30 <li>Easy To use</li>
    31 <li>Shorcode Support [gmwplw_product_layout id="168"]</li>
    32 <li>List and Grid  layout</li>
    33 </ul>
     37= 3.4.0 =
     38* Expanded the front-end filter bar with price range and in-stock filters, plus a "Clear filters" reset
     39* Column builder: drag-and-drop reordering, enable/disable any column, and custom field columns
     40* Advanced query builder: multi-select category, tag, and attribute filtering
     41* Front-end search, sortable table columns, ajax add-to-cart, and an optional floating cart
     42* New Appearance tab: accent/text/border colors, font size, border radius/width, hover effects
     43* Simple, sequential shortcode IDs instead of long UUIDs
     44* Declared WooCommerce HPOS compatibility
     45* Refreshed admin UI (page header with Support link) and a full front-end visual redesign
    3446
     47= 3.0 =
     48* Renamed to "Product Table, Grid, List Builder For WooCommerce" to reflect what it actually does
     49* Removed the "Product Widget" custom post type entirely — layouts ("Builders") are now stored as plugin settings, managed from a dedicated top-level admin page
     50* New "Product Builders" admin page: create, edit, and delete unlimited Table/Grid/List builders, each with its own shortcode, from one screen — no more separate post-per-layout editor
     51* The admin page is a real React app written in JSX (src-admin/admin-app.jsx), built with @wordpress/scripts (package.json + webpack.config.js included) — run `npm install && npm run build` after editing it
     52* New REST endpoints for full builder CRUD (list, get, create, update, delete)
     53* Added a Settings link on the Plugins page pointing to the new Product Builders screen
    3554
    36 <h4>Our More Plugins</h4>
     55= 2.1 =
     56* Removed the legacy PHP-rendered fallback entirely — the front end is now 100% React (wp.element), with no server-rendered markup path left
     57* Added "Load More" pagination to the front-end list, grid, and table views
     58* Moved from in-browser Babel compilation to a proper build step (@wordpress/scripts) for the admin app, so there's a real package.json to install and rebuild from
    3759
    38 [Short Description and Attributes Show Loop For Woocommerce](https://wordpress.org/plugins/short-description-and-attribute-show-loop-for-woocommerce/) To create a product loop in WooCommerce that displays a short description and selected product attributes, you can customize the WooCommerce template or use hooks.
     60= 2.0 =
     61* Removed the classic WordPress sidebar Widget entirely — use the shortcode or the block instead
     62* Added a Table display layout alongside List and Grid
     63* Rebuilt both the admin settings screen and the front-end product display as React apps (using wp.element, no @wordpress/components) backed by a new REST API, replacing the old PHP form and server-rendered markup
    3964
    40 [Add to Quote For Woocommerce](https://wordpress.org/plugins/product-quote-cart-for-wc/) feature to WooCommerce with a brief, one-line product description, you can either use a plugin or manually customize the WooCommerce product loop.
    41 
    42 [Product Shortcode – Widget – Block for Woocommerce](https://wordpress.org/plugins/gm-woo-product-list-widget/) in WooCommerce for displaying products with descriptions, you can leverage the built-in WooCommerce shortcodes or customize them to suit your needs.
    43 
    44 [Show Variations On Shop & Category WooCommerce](https://wordpress.org/plugins/woo-show-single-variations-shop-category/) you can show product variations directly on the shop and category pages.
    45 
    46 [Variation Dropdown to Radio For Woocommerce](https://wordpress.org/plugins/gm-variations-radio-buttons-for-woocommerce/) enhancing user experience. Customers can easily see and select variations at a glance.
    47 
    48 [Product Enquiry for WooCommerce](https://wordpress.org/plugins/gm-woocommerce-quote-popup/) This plugin enables customers to submit inquiries directly from product pages.
    49 
    50 [PDF Catalog Woocommerce](https://wordpress.org/plugins/pdf-catalog-woocommerce/) This plugin allows you to generate customizable catalogs featuring product images, descriptions, and prices.
    51 
    52 [Restrict Payment Methods For WooCommerce](https://wordpress.org/plugins/restrict-payment-methods-for-woocommerce/) allows you to restrict payment methods, ensuring customers can only use suitable options at checkout.
    53 
    54 [Display Product Variations Dropdown On Shop Page For Woocommerce](https://wordpress.org/plugins/display-product-variations-dropdown-on-shop-page-for-woocommerce/) Enhance your shop page by displaying product variation dropdowns directly on the product listings.
     65= 1.1 =
     66* Rebuilt the Gutenberg block editor picker with a custom, elegant design instead of the default @wordpress/components dropdown
Note: See TracChangeset for help on using the changeset viewer.