Changeset 3797446
- Timestamp:
- 11/12/2026 03:43:15 AM (17 hours ago)
- Location:
- gm-woo-product-list-widget
- Files:
-
- 16 added
- 16 edited
-
assets/banner-1544x500.png (modified) ( previous)
-
assets/banner-772x250.png (modified) ( previous)
-
assets/icon-128x128.png (modified) ( previous)
-
assets/icon-256x256.png (modified) ( previous)
-
assets/screenshot-1.png (modified) ( previous)
-
assets/screenshot-2.png (modified) ( previous)
-
assets/screenshot-3.png (modified) ( previous)
-
assets/screenshot-4.png (modified) ( previous)
-
assets/screenshot-5.png (modified) ( previous)
-
assets/screenshot-6.png (added)
-
assets/screenshot-7.png (added)
-
assets/screenshot-8.png (added)
-
assets/screenshot-9.png (added)
-
trunk/build/admin (added)
-
trunk/build/admin/admin-app.asset.php (added)
-
trunk/build/admin/admin-app.js (added)
-
trunk/build/block.js (modified) (1 diff)
-
trunk/build/frontend-app.js (added)
-
trunk/css/admin-style.css (modified) (1 diff)
-
trunk/css/block-editor.css (added)
-
trunk/css/frontend-app.css (added)
-
trunk/gm-woo-product-list-widget.php (modified) (2 diffs)
-
trunk/includes/GMWPLW_Admin.php (modified) (1 diff)
-
trunk/includes/GMWPLW_Api.php (added)
-
trunk/includes/GMWPLW_Block.php (modified) (4 diffs)
-
trunk/includes/GMWPLW_Frontend.php (modified) (1 diff)
-
trunk/includes/GMWPLW_Store.php (added)
-
trunk/package.json (added)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/src-admin (added)
-
trunk/src-admin/admin-app.jsx (added)
-
trunk/webpack.config.js (added)
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'; 4 3 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; 16 7 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 ) || []; 23 9 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 1 1 <?php 2 2 /** 3 * Plugin Name: Product List / Grid View for Woocommerce4 * Description: GM Woo Product list Widget to show product list in widget with verious option5 * Version: 1.03 * 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 6 6 * Author: Gravity Master 7 7 * License: GPLv2 or later … … 44 44 spl_autoload_register('gmwplw_class_auto_loader'); 45 45 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 */ 50 add_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 46 56 /* Initialize all modules now. */ 47 57 48 new GMWPLW_ Comman();58 new GMWPLW_Store(); 49 59 new GMWPLW_Admin(); 50 60 new GMWPLW_Block(); 51 61 new GMWPLW_Frontend(); 62 new GMWPLW_Api(); 52 63 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 */ 67 if ( ! 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 } 74 add_filter( 'plugin_action_links_' . GMWPLW_PLUGIN_BASENAME, 'gmwplw_plugin_action_links' ); 54 75 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 2 2 3 3 /** 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. 6 9 */ 7 10 8 11 class GMWPLW_Admin { 9 10 protected static $instance = NULL;11 12 13 const PAGE_SLUG = 'gmwplw-builders'; 12 14 13 15 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' ) ); 22 18 } 23 19 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 ); 41 30 } 42 31 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'; 55 34 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>'; 78 43 } 79 44 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 " <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 } 250 49 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; 255 55 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 ); 273 63 64 wp_enqueue_style( 'gmwplw_admin_css', GMWPLW_PLUGIN_URL . 'css/admin-style.css', array(), $asset['version'] ); 274 65 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 ) ); 279 70 } 280 71 281 282 283 72 } 284 285 ?> -
gm-woo-product-list-widget/trunk/includes/GMWPLW_Block.php
r3180590 r3797446 1 1 <?php 2 2 class GMWPLW_Block { 3 3 4 4 protected static $instance = NULL; 5 5 … … 7 7 public function __construct () { 8 8 add_action( 'init', array( $this, 'GMWPLW_init' ) ); 9 9 10 10 } 11 11 … … 15 15 GMWPLW_PLUGIN_URL . '/build/block.js', 16 16 array('wp-blocks', 'wp-element', 'wp-editor'), 17 ' 1.0.0',17 '3.4.0', 18 18 true 19 19 ); 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 ); 31 34 } 32 // Pass dynamic options to JavaScript35 // Pass dynamic options to JavaScript 33 36 wp_localize_script('gmwplw-block-script', 'gmwplwBlockData', array( 34 'options' => $arr 37 'options' => $arr, 38 'buildersUrl' => admin_url( 'admin.php?page=gmwplw-builders' ), 35 39 )); 36 40 37 41 register_block_type('gmwplw/gmwplw-block', array( 38 42 'editor_script' => 'gmwplw-block-script', 43 'editor_style' => 'gmwplw-block-editor-style', 39 44 'render_callback' => array( $this,'gmwplw_block_render'), 40 45 )); … … 42 47 43 48 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.'; 51 51 } 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 ); 53 88 } 54 89 -
gm-woo-product-list-widget/trunk/includes/GMWPLW_Frontend.php
r3067768 r3797446 2 2 3 3 class GMWPLW_Frontend { 4 4 5 5 protected static $instance = NULL; 6 6 7 7 public function __construct () { 8 add_action( 'wp_enqueue_scripts', array( $this, 'GMWPLW_register_assets' ) ); 8 9 add_shortcode( 'gmwplw_product_layout', array( $this, 'gmwplw_product_layout' ) ); 9 10 10 } 11 11 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 } 17 37 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 ); 20 42 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 } 27 46 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'] ); 34 48 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 } 36 61 37 62 } -
gm-woo-product-list-widget/trunk/readme.txt
r3613245 r3797446 1 === Product List / Grid View for Woocommerce ===2 Tested up to: 7.03 stable tag:1.04 Tags: product widget woocommerce,product list for woocommerce , category filter woocommerce, woocommerce widget product, woocommerce best sale product1 === Product Table, Grid, List Builder For WooCommerce === 2 Tested up to: 6.2 3 Stable tag: 3.4.0 4 Tags: product table woocommerce, product grid woocommerce, product list builder, woocommerce shortcode builder, category filter woocommerce 5 5 License: GPLv2 or later 6 6 License URI: http://www.gnu.org/licenses/gpl-3.0.html … … 8 8 == Description == 9 9 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. 11 11 12 [Demo](https://codesmade.com/demo/blog/) | [Support](https://www.codesmade.com/contact-us/) 12 = Key Features = 13 13 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. 14 28 29 = How It Works = 15 30 16 **Woocommerce Display Products by Category** easy to show in widget with display category wise product in woocommerce. 31 1. Go to **Product Builders** in your WordPress admin. 32 2. Click **New Builder**, choose a layout (List, Grid, or Table), and configure your columns, filters, and appearance. 33 3. Copy the generated shortcode (or use the Gutenberg block) and paste it into any post, page, or template. 17 34 18 #### Features 35 == Changelog == 19 36 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 34 46 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 35 54 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 37 59 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 39 64 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.