generator-chisel 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/lib/commands/create/creators/app/chisel-starter-theme/functions.php +1 -1
  3. package/lib/commands/create/creators/app/chisel-starter-theme/inc/{Module/Ajax.php → Controllers/AjaxController.php} +2 -2
  4. package/lib/commands/create/creators/app/chisel-starter-theme/inc/Factory/RegisterAcfOptionsPage.php +1 -1
  5. package/lib/commands/create/creators/app/chisel-starter-theme/inc/Factory/RegisterBlocks.php +21 -39
  6. package/lib/commands/create/creators/app/chisel-starter-theme/inc/Helper/AjaxHelpers.php +2 -2
  7. package/lib/commands/create/creators/app/chisel-starter-theme/inc/Helper/YoastHelpers.php +1 -1
  8. package/lib/commands/create/creators/app/chisel-starter-theme/inc/Plugin/Woocommerce.php +28 -0
  9. package/lib/commands/create/creators/app/chisel-starter-theme/inc/WP/Acf.php +12 -5
  10. package/lib/commands/create/creators/app/chisel-starter-theme/inc/WP/ChiselProduct.php +31 -7
  11. package/lib/commands/create/creators/app/chisel-starter-theme/inc/WP/ChiselProductCategory.php +66 -0
  12. package/lib/commands/create/creators/app/chisel-starter-theme/inc/WP/Site.php +2 -1
  13. package/lib/commands/create/creators/app/chisel-starter-theme/src/scripts/modules/slider.js +6 -0
  14. package/lib/commands/create/creators/app/chisel-starter-theme/twig_cs.php +2 -2
  15. package/lib/commands/create/creators/app/chisel-starter-theme/views/woocommerce/archive-product.twig +8 -4
  16. package/lib/commands/create/creators/app/chisel-starter-theme/views/woocommerce/content-product-cat.twig +42 -0
  17. package/lib/commands/create/creators/app/chisel-starter-theme/woocommerce.php +21 -11
  18. package/lib/commands/create/creators/wp/index.js +1 -0
  19. package/lib/commands/create/creators/wp-plugins/index.js +1 -0
  20. package/lib/commands/create/creators/wp-plugins/plugins.json +2 -1
  21. package/lib/commands/create/packages-versions.js +1 -1
  22. package/package.json +2 -2
  23. package/lib/commands/create/creators/app/chisel-starter-theme/inc/Module/AcfSync.php +0 -223
  24. package/lib/commands/create/creators/app/chisel-starter-theme/src/scripts/acf-sync.js +0 -26
  25. package/lib/commands/create/creators/app/chisel-starter-theme/src/styles/acf-sync.scss +0 -64
package/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  <!-- INSERT-NEW-ENTRIES-HERE -->
4
4
 
5
+ ## <small>2.1.1 (2025-05-26)</small>
6
+
7
+ - add woo hooks, get_blocks fixes, js slider adjustments ([8c02af7](https://github.com/xfiveco/generator-chisel/commit/8c02af7))
8
+
9
+ ## 2.1.0 (2025-05-16)
10
+
11
+ - acf sync module as a plugin, add x5 plugins to installation script ([93b4f8a](https://github.com/xfiveco/generator-chisel/commit/93b4f8a))
12
+ - improve woocommerce support, small refactor ([1968fbc](https://github.com/xfiveco/generator-chisel/commit/1968fbc))
13
+
5
14
  ## 2.0.0 (2025-04-07)
6
15
 
7
16
  - Update chisel version and readme ([0aca167](https://github.com/xfiveco/generator-chisel/commit/0aca167))
@@ -26,7 +26,7 @@ spl_autoload_register(
26
26
 
27
27
  Timber\Timber::init();
28
28
 
29
- \Chisel\Module\Ajax::get_instance();
29
+ \Chisel\Controllers\AjaxController::get_instance();
30
30
  \Chisel\WP\Blocks::get_instance();
31
31
  \Chisel\WP\Acf::get_instance();
32
32
  \Chisel\WP\AcfBlocks::get_instance();
@@ -1,6 +1,6 @@
1
1
  <?php
2
2
 
3
- namespace Chisel\Module;
3
+ namespace Chisel\Controllers;
4
4
 
5
5
  use Chisel\WP\AjaxEnpoints;
6
6
  use Chisel\Interfaces\InstanceInterface;
@@ -12,7 +12,7 @@ use Chisel\Traits\Singleton;
12
12
  *
13
13
  * @package Chisel
14
14
  */
15
- class Ajax extends \WP_REST_Controller implements InstanceInterface, HooksInterface {
15
+ class AjaxController extends \WP_REST_Controller implements InstanceInterface, HooksInterface {
16
16
 
17
17
  use Singleton;
18
18
 
@@ -37,7 +37,7 @@ class RegisterAcfOptionsPage {
37
37
  /**
38
38
  * Register ACF options page.
39
39
  */
40
- private function register_options_page() {
40
+ public function register() {
41
41
  $options_page_args = array(
42
42
  'page_title' => $this->args['page_title'],
43
43
  'menu_title' => isset( $this->args['menu_title'] ) ? $this->args['menu_title'] : $this->args['page_title'],
@@ -54,20 +54,6 @@ class RegisterBlocks {
54
54
  */
55
55
  private $blocks = array();
56
56
 
57
- /**
58
- * Blocks option name.
59
- *
60
- * @var string
61
- */
62
- private $blocks_option_name;
63
-
64
- /**
65
- * Blocks version option name.
66
- *
67
- * @var string
68
- */
69
- private $blocks_version_option_name;
70
-
71
57
  /**
72
58
  * Theme.
73
59
  *
@@ -102,15 +88,13 @@ class RegisterBlocks {
102
88
  * @param string $blocks_type The blocks type : acf or wp.
103
89
  */
104
90
  public function __construct( $blocks_type ) {
105
- $this->blocks_type = $blocks_type;
106
- $this->theme = wp_get_theme();
107
- $this->blocks_folder = $this->blocks_type === 'acf' ? 'blocks-acf' : 'blocks';
108
- $this->blocks_path = get_template_directory() . '/' . $this->build_folder . '/' . $this->blocks_folder;
109
- $this->blocks_path_src = get_template_directory() . '/' . $this->src_folder . '/' . $this->blocks_folder;
110
- $this->blocks_url = get_template_directory_uri() . '/' . $this->build_folder . '/' . $this->blocks_folder;
111
- $this->blocks = $this->get_blocks();
112
- $this->blocks_option_name = 'chisel_' . $this->blocks_type;
113
- $this->blocks_version_option_name = 'chisel_' . $this->blocks_type . '_version';
91
+ $this->blocks_type = $blocks_type;
92
+ $this->theme = wp_get_theme();
93
+ $this->blocks_folder = $this->blocks_type === 'acf' ? 'blocks-acf' : 'blocks';
94
+ $this->blocks_path = get_template_directory() . '/' . $this->build_folder . '/' . $this->blocks_folder;
95
+ $this->blocks_path_src = get_template_directory() . '/' . $this->src_folder . '/' . $this->blocks_folder;
96
+ $this->blocks_url = get_template_directory_uri() . '/' . $this->build_folder . '/' . $this->blocks_folder;
97
+ $this->blocks = $this->get_blocks();
114
98
 
115
99
  $this->register_scripts = apply_filters( 'chisel_blocks_register_scripts', true, $this->blocks_type );
116
100
  }
@@ -228,29 +212,27 @@ class RegisterBlocks {
228
212
  * @return array
229
213
  */
230
214
  public function get_blocks() {
231
- $blocks = get_option( $this->blocks_option_name, array() ) ?: array();
232
- $blocks_version = get_option( $this->blocks_version_option_name, 0 );
233
-
234
- if ( ! $blocks || version_compare( $this->theme->get( 'Version' ), $blocks_version ) ) {
235
- $blocks_list = is_dir( $this->blocks_path ) ? new \DirectoryIterator( $this->blocks_path ) : array();
215
+ if ( $this->blocks ) {
216
+ return $this->blocks;
217
+ }
236
218
 
237
- if ( $blocks_list ) {
238
- foreach ( $blocks_list as $item ) {
239
- if ( $item->isDot() || ! $item->isDir() ) {
240
- continue;
241
- }
219
+ $blocks_list = is_dir( $this->blocks_path ) ? new \DirectoryIterator( $this->blocks_path ) : array();
242
220
 
243
- $blocks[] = $item->getFilename();
221
+ if ( $blocks_list ) {
222
+ foreach ( $blocks_list as $item ) {
223
+ if ( $item->isDot() || ! $item->isDir() ) {
224
+ continue;
244
225
  }
245
- }
246
226
 
247
- if ( ! ThemeHelpers::is_fast_refresh() ) {
248
- update_option( $this->blocks_option_name, $blocks );
249
- update_option( $this->blocks_version_option_name, $this->theme->get( 'Version' ) );
227
+ $block_name = $item->getFilename();
228
+
229
+ if ( ! in_array( $block_name, $this->blocks, true ) ) {
230
+ $this->blocks[] = $item->getFilename();
231
+ }
250
232
  }
251
233
  }
252
234
 
253
- return $blocks;
235
+ return $this->blocks;
254
236
  }
255
237
 
256
238
  /**
@@ -2,7 +2,7 @@
2
2
 
3
3
  namespace Chisel\Helper;
4
4
 
5
- use Chisel\Module\Ajax;
5
+ use Chisel\Controllers\AjaxController;
6
6
 
7
7
  /**
8
8
  * Helper functions.
@@ -17,7 +17,7 @@ class AjaxHelpers {
17
17
  * @return string
18
18
  */
19
19
  public static function get_ajax_endpoint_url() {
20
- return sprintf( '%s/wp-json/%s/%s', esc_url( get_bloginfo( 'url' ) ), Ajax::ROUTE_NAMESPACE, Ajax::ROUTE_BASE );
20
+ return sprintf( '%s/wp-json/%s/%s', esc_url( get_bloginfo( 'url' ) ), AjaxController::ROUTE_NAMESPACE, AjaxController::ROUTE_BASE );
21
21
  }
22
22
 
23
23
  /**
@@ -10,7 +10,7 @@ namespace Chisel\Helper;
10
10
  class YoastHelpers {
11
11
 
12
12
  /**
13
- * Check if Gravity Forms plugin is active.
13
+ * Check if Yoast plugin is active.
14
14
  *
15
15
  * @return bool
16
16
  */
@@ -59,6 +59,8 @@ class Woocommerce implements InstanceInterface, HooksInterface {
59
59
 
60
60
  add_action( 'woocommerce_before_shop_loop', array( $this, 'before_shop_loop_div_open' ), 19 );
61
61
  add_action( 'woocommerce_before_shop_loop', array( $this, 'before_shop_loop_div_close' ), 31 );
62
+
63
+ add_action( 'customize_register', array( $this, 'modify_customizer' ), 20 );
62
64
  }
63
65
 
64
66
  /**
@@ -78,6 +80,12 @@ class Woocommerce implements InstanceInterface, HooksInterface {
78
80
  remove_action( 'woocommerce_before_shop_loop_item', 'woocommerce_template_loop_product_link_open', 10 );
79
81
  remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_product_link_close', 5 );
80
82
 
83
+ // Remove loop category link open and close, so we can use our own.
84
+ remove_action( 'woocommerce_before_subcategory', 'woocommerce_template_loop_category_link_open', 10 );
85
+ remove_action( 'woocommerce_after_subcategory', 'woocommerce_template_loop_category_link_close', 10 );
86
+ // Remove category default thumbnail.
87
+ remove_action( 'woocommerce_before_subcategory_title', 'woocommerce_subcategory_thumbnail', 10 );
88
+
81
89
  remove_action( 'woocommerce_before_main_content', 'woocommerce_output_content_wrapper', 10 );
82
90
  remove_action( 'woocommerce_after_main_content', 'woocommerce_output_content_wrapper_end', 10 );
83
91
  remove_action( 'woocommerce_before_main_content', 'woocommerce_breadcrumb', 20 );
@@ -115,6 +123,26 @@ class Woocommerce implements InstanceInterface, HooksInterface {
115
123
  echo ' </div> ';
116
124
  }
117
125
 
126
+ /**
127
+ * Modify woocommerce customizer settings.
128
+ *
129
+ * @param WP_Customize_Manager $wp_customize
130
+ *
131
+ * @return void
132
+ */
133
+ public function modify_customizer( $wp_customize ) {
134
+ $shop_page_display_control = $wp_customize->get_control( 'woocommerce_shop_page_display' );
135
+ $category_page_display_control = $wp_customize->get_control( 'woocommerce_category_archive_display' );
136
+
137
+ if ( $shop_page_display_control && isset( $shop_page_display_control->choices ) ) {
138
+ unset( $shop_page_display_control->choices['both'] );
139
+ }
140
+
141
+ if ( $category_page_display_control && isset( $category_page_display_control->choices ) ) {
142
+ unset( $category_page_display_control->choices['both'] );
143
+ }
144
+ }
145
+
118
146
  /**
119
147
  * Register woocommerce sidebars.
120
148
  *
@@ -5,7 +5,6 @@ namespace Chisel\WP;
5
5
  use Chisel\Interfaces\InstanceInterface;
6
6
  use Chisel\Interfaces\HooksInterface;
7
7
  use Chisel\Traits\Singleton;
8
- use Chisel\Module\AcfSync;
9
8
  use Chisel\Factory\RegisterAcfOptionsPage;
10
9
 
11
10
  /**
@@ -39,10 +38,6 @@ class Acf implements InstanceInterface, HooksInterface {
39
38
 
40
39
  $this->action_hooks();
41
40
  $this->filter_hooks();
42
-
43
- if ( class_exists( '\ACF_Admin_Internal_Post_Type_List' ) ) {
44
- AcfSync::get_instance();
45
- }
46
41
  }
47
42
 
48
43
  /**
@@ -115,4 +110,16 @@ class Acf implements InstanceInterface, HooksInterface {
115
110
  }
116
111
  }
117
112
  }
113
+
114
+ /**
115
+ * Register ACF options pages.
116
+ *
117
+ * @param array $data
118
+ * @param string $type
119
+ *
120
+ * @return void
121
+ */
122
+ private function register_options_page( $data, $type = 'page' ) {
123
+ ( new RegisterAcfOptionsPage( $data, $type ) )->register();
124
+ }
118
125
  }
@@ -18,7 +18,14 @@ class ChiselProduct extends TimberPost {
18
18
  *
19
19
  * @var html
20
20
  */
21
- public $thumbnail_html;
21
+ public $thumbnail_html = null;
22
+
23
+ /**
24
+ * Category thumbnail id.
25
+ *
26
+ * @var int
27
+ */
28
+ public $thumbnail_id = null;
22
29
 
23
30
  /**
24
31
  * Get the product thumbnail. Returns the thumbnail responsive image html.
@@ -27,16 +34,33 @@ class ChiselProduct extends TimberPost {
27
34
  * @return html
28
35
  */
29
36
  public function get_thumbnail( $size = 'woocommerce_thumbnail' ) {
30
- if ( ! $this->thumbnail_html ) {
31
- $thumbnail_html = has_post_thumbnail( $this->ID ) ? ImageHelpers::get_responsive_image( get_post_thumbnail_id( $this->ID ), $size ) : '';
37
+ $size = apply_filters( 'single_product_archive_thumbnail_size', $size );
32
38
 
33
- if ( ! $thumbnail_html ) {
34
- $thumbnail_html = wc_placeholder_img( $size );
35
- }
39
+ if ( $this->thumbnail_html === null ) {
40
+ $thumbnail_id = $this->get_thumbnail_id( $size );
36
41
 
37
- $this->thumbnail_html = $thumbnail_html;
42
+ $this->thumbnail_html = $thumbnail_id ? ImageHelpers::get_responsive_image( $thumbnail_id, $size ) : '';
38
43
  }
39
44
 
40
45
  return $this->thumbnail_html;
41
46
  }
47
+
48
+ /**
49
+ * Get the product thumbnail id
50
+ *
51
+ * @return int
52
+ */
53
+ public function get_thumbnail_id() {
54
+ if ( $this->thumbnail_id === null ) {
55
+ $thumbnail_id = get_post_thumbnail_id( $this->ID );
56
+
57
+ if ( ! $thumbnail_id ) {
58
+ $thumbnail_id = get_option( 'woocommerce_placeholder_image', 0 );
59
+ }
60
+
61
+ $this->thumbnail_id = $thumbnail_id;
62
+ }
63
+
64
+ return $this->thumbnail_id;
65
+ }
42
66
  }
@@ -0,0 +1,66 @@
1
+ <?php
2
+
3
+ namespace Chisel\WP;
4
+
5
+ use Timber\Term as TimberTerm;
6
+ use Chisel\Helper\ImageHelpers;
7
+
8
+ /**
9
+ * Extend Timber Term class with custom functionality.
10
+ *
11
+ * @package Chisel
12
+ */
13
+ class ChiselProductCategory extends TimberTerm {
14
+
15
+ /**
16
+ * Category thumbnail.
17
+ *
18
+ * @var html
19
+ */
20
+ public $thumbnail_html = null;
21
+
22
+ /**
23
+ * Category thumbnail id.
24
+ *
25
+ * @var int
26
+ */
27
+ public $thumbnail_id = null;
28
+
29
+ /**
30
+ * Get the product thumbnail. Returns the thumbnail responsive image html.
31
+ *
32
+ * @param string $size Thumbnail size.
33
+ *
34
+ * @return html
35
+ */
36
+ public function get_thumbnail( $size = 'woocommerce_thumbnail' ) {
37
+ $size = apply_filters( 'subcategory_archive_thumbnail_size', $size );
38
+
39
+ if ( $this->thumbnail_html === null ) {
40
+ $thumbnail_id = $this->get_thumbnail_id( $size );
41
+
42
+ $this->thumbnail_html = $thumbnail_id ? ImageHelpers::get_responsive_image( $thumbnail_id, $size ) : '';
43
+ }
44
+
45
+ return $this->thumbnail_html;
46
+ }
47
+
48
+ /**
49
+ * Get the product thumbnail id.
50
+ *
51
+ * @return int
52
+ */
53
+ public function get_thumbnail_id() {
54
+ if ( $this->thumbnail_id === null ) {
55
+ $thumbnail_id = $this->meta( 'thumbnail_id' );
56
+
57
+ if ( ! $thumbnail_id ) {
58
+ $thumbnail_id = get_option( 'woocommerce_placeholder_image', 0 );
59
+ }
60
+
61
+ $this->thumbnail_id = $thumbnail_id;
62
+ }
63
+
64
+ return $this->thumbnail_id;
65
+ }
66
+ }
@@ -92,7 +92,8 @@ class Site extends TimberSite implements InstanceInterface, HooksInterface {
92
92
  */
93
93
  public function term_classmap( $classmap ) {
94
94
  $custom_classmap = array(
95
- 'category' => ChiselTerm::class,
95
+ 'category' => ChiselTerm::class,
96
+ 'product_cat' => ChiselProductCategory::class,
96
97
  );
97
98
 
98
99
  return array_merge( $classmap, $custom_classmap );
@@ -312,6 +312,12 @@ class Slider {
312
312
  slideImg.removeAttribute(attr);
313
313
  });
314
314
 
315
+ if (!thumbnailUrl) {
316
+ throw new Error(
317
+ 'data-thumbnail-url attribute must be present on each swiper-slide element.',
318
+ );
319
+ }
320
+
315
321
  const imageSize = thumbnailUrl.match(/(\d+)x(\d+)\./i);
316
322
 
317
323
  if (imageSize?.[2]) {
@@ -4,8 +4,8 @@ declare(strict_types=1);
4
4
  use FriendsOfTwig\Twigcs;
5
5
 
6
6
  $finder_1 = Twigcs\Finder\TemplateFinder::create()->in( __DIR__ . '/views' );
7
- $finder_2 = Twigcs\Finder\TemplateFinder::create()->in( __DIR__ . '/build/blocks' );
8
- $finder_3 = Twigcs\Finder\TemplateFinder::create()->in( __DIR__ . '/build/blocks-acf' );
7
+ $finder_2 = Twigcs\Finder\TemplateFinder::create()->in( __DIR__ . '/src/blocks' );
8
+ $finder_3 = Twigcs\Finder\TemplateFinder::create()->in( __DIR__ . '/src/blocks-acf' );
9
9
 
10
10
  return Twigcs\Config\Config::create()
11
11
  ->addFinder( $finder_1 )
@@ -34,15 +34,19 @@
34
34
  <div class="o-layout">
35
35
  <div class="{{ bem('o-layout__item', (sidebar ? '8' : '12') ~ '-large') }}">
36
36
  <div class="c-posts-items c-shop-items {{ loop_columns_class }} js-load-more-container">
37
- {% if products is not empty %}
38
- {% for post in products %}
37
+ {% if items is not empty %}
38
+ {% for item in items %}
39
39
 
40
40
  {#
41
41
  * Hook: woocommerce_shop_loop.
42
42
  #}
43
43
  {% do action('woocommerce_shop_loop') %}
44
44
 
45
- {% include "woocommerce/content-product.twig" with {post: post} %}
45
+ {% if show_products %}
46
+ {% include "woocommerce/content-product.twig" with {post: item} %}
47
+ {% else %}
48
+ {% include "woocommerce/content-product-cat.twig" with {term: item} %}
49
+ {% endif %}
46
50
  {% endfor %}
47
51
 
48
52
  {#
@@ -61,7 +65,7 @@
61
65
  {% endif %}
62
66
  </div>
63
67
 
64
- {% if products is not empty %}
68
+ {% if items is not empty and show_products %}
65
69
  {% include 'components/pagination.twig' with {type: 'load-more'} %}
66
70
  {% endif %}
67
71
  </div>
@@ -0,0 +1,42 @@
1
+ <article class="c-product-item c-product-item--category c-post-card">
2
+ <div class="c-product-item__inner">
3
+
4
+ {#
5
+ * Hook: woocommerce_before_subcategory.
6
+ *
7
+ * @hooked woocommerce_template_loop_category_link_open - 10 (Removed by the theme)
8
+ #}
9
+ {% do action('woocommerce_before_subcategory', term) %}
10
+
11
+ <a class="c-product-item__content" href="{{ term.link }}">
12
+ {#
13
+ * Hook: woocommerce_before_subcategory_title.
14
+ *
15
+ * hooked woocommerce_subcategory_thumbnail - 10 (Removed by the theme)
16
+ #}
17
+ {% do action('woocommerce_before_subcategory_title', term) %}
18
+
19
+ <h2 class="c-product-item__title">{{ term.title }}</h2>
20
+
21
+ {#
22
+ * Hook: woocommerce_after_subcategory_title.
23
+ #}
24
+ {% do action('woocommerce_after_subcategory_title') %}
25
+
26
+ {% if term.get_thumbnail() %}
27
+ <div class="c-product-item__image">
28
+ {{ term.get_thumbnail() }}
29
+ </div>
30
+ {% endif %}
31
+
32
+ </a>
33
+
34
+ {#
35
+ * Hook: woocommerce_after_subcategory.
36
+ *
37
+ * @hooked woocommerce_template_loop_category_link_close - 10 (Removed by the theme)
38
+ #}
39
+ {% do action('woocommerce_after_subcategory', term) %}
40
+
41
+ </div>
42
+ </article>
@@ -16,11 +16,11 @@ if ( is_singular( 'product' ) ) {
16
16
  $context['product'] = wc_get_product( $context['post']->ID );
17
17
 
18
18
  // Get upsells ids.
19
- $upsells_ids = $context['product']->get_upsell_ids();
19
+ $upsells_ids = apply_filters( 'chisel_woocommerce_upsell_display', true ) ? $context['product']->get_upsell_ids() : array();
20
20
 
21
21
  // Get related / crossells products ids.
22
22
  $related_limit = wc_get_loop_prop( 'columns' );
23
- $related_ids = wc_get_related_products( $context['post']->id, $related_limit, $upsells_ids );
23
+ $related_ids = apply_filters( 'chisel_woocommerce_output_related_products', true ) ? wc_get_related_products( $context['post']->id, $related_limit, $upsells_ids ) : array();
24
24
 
25
25
  $context['upsells_products'] = $upsells_ids ? Timber::get_posts( $upsells_ids ) : array();
26
26
  $context['related_products'] = $related_ids ? Timber::get_posts( $related_ids ) : array();
@@ -32,26 +32,36 @@ if ( is_singular( 'product' ) ) {
32
32
 
33
33
  Timber::render( 'woocommerce/single-product.twig', $context, CacheHelpers::expiry() );
34
34
  } else {
35
- $products = Timber::get_posts();
35
+ $display_type = woocommerce_get_loop_display_mode();
36
+ $show_products = true;
37
+ $categories = array();
38
+
39
+ if ( $display_type === 'subcategories' ) {
40
+ $categories = woocommerce_get_product_subcategories( is_product_category() ? get_queried_object_id() : 0 );
41
+
42
+ $show_products = empty( $categories );
43
+ }
44
+
45
+ if ( $show_products ) {
46
+ $items = Timber::get_posts();
47
+ } else {
48
+ $items = array_map( 'Timber::get_term', $categories );
49
+ }
50
+
36
51
  $has_sidebar = ! empty( $context['sidebar'] );
37
52
  $loop_columns = wc_get_loop_prop( 'columns' );
38
53
  $loop_rows = wc_get_default_product_rows_per_page();
39
54
 
40
55
  $grid_classnames = WoocommerceHelpers::get_products_grid_classnames( $products, $has_sidebar );
41
56
 
42
- $context['products'] = $products;
57
+ $context['show_products'] = $show_products;
58
+ $context['items'] = $items;
59
+ $context['categories'] = $categories;
43
60
  $context['loop_columns_class'] = $grid_classnames;
44
61
  $context['load_more'] = array(
45
62
  'per_page' => absint( $loop_columns * $loop_rows ),
46
63
  'post_type' => 'product',
47
64
  );
48
65
 
49
- if ( is_product_category() ) {
50
- $queried_object = get_queried_object();
51
- $term_id = $queried_object->term_id;
52
- $context['category'] = get_term( $term_id, 'product_cat' );
53
- $context['title'] = single_term_title( '', false );
54
- }
55
-
56
66
  Timber::render( 'woocommerce/archive-product.twig', $context, CacheHelpers::expiry() );
57
67
  }
@@ -165,6 +165,7 @@ module.exports = (api) => {
165
165
  'install',
166
166
  'disable-emojis',
167
167
  'https://github.com/wp-premium/advanced-custom-fields-pro/archive/master.zip',
168
+ 'xfive-sync-watcher-for-acf',
168
169
  { activate: true },
169
170
  ]);
170
171
  });
@@ -6,6 +6,7 @@ module.exports = (api) => {
6
6
 
7
7
  api.schedule(api.PRIORITIES.PROMPT, async () => {
8
8
  console.log('Advanced Custom Fields Pro is installed by default.');
9
+ console.log('X5 Plato - Reliable Sync Watcher for ACF is installed by default.');
9
10
 
10
11
  await api.prompt([
11
12
  {
@@ -3,6 +3,7 @@
3
3
  "WP Premium: Gravity Forms": "https://github.com/pronamic/gravityforms/archive/master.zip",
4
4
  "SVG Support": "svg-support",
5
5
  "Yoast SEO": "wordpress-seo",
6
- "Yoast SEO ACF": "acf-content-analysis-for-yoast-seo"
6
+ "Yoast SEO ACF": "acf-content-analysis-for-yoast-seo",
7
+ "X5 Aristotle - Monitor Site Errors with Sentry": "xfive-sentry-integration"
7
8
  }
8
9
  }
@@ -1,5 +1,5 @@
1
1
  module.exports = {
2
2
  'chisel-scripts': '2.0.0-2.0.0-alpha.8.1',
3
3
  'chisel-shared-utils': '2.0.0-alpha.1',
4
- 'generator-chisel': '2.0.0',
4
+ 'generator-chisel': '2.1.1',
5
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generator-chisel",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "A generator for scaffolding front-end and WordPress projects",
5
5
  "bin": {
6
6
  "chisel": "bin/chisel.js"
@@ -37,5 +37,5 @@
37
37
  "tinyqueue": "^2.0.3",
38
38
  "update-notifier": "^4.1.0"
39
39
  },
40
- "gitHead": "1c7715ab7398126f66ff0155133481a9cb863b83"
40
+ "gitHead": "5ce0d679d897e7cc1ed936bddf6d50aa9cab3ea1"
41
41
  }
@@ -1,223 +0,0 @@
1
- <?php
2
-
3
- namespace Chisel\Module;
4
-
5
- use Chisel\Interfaces\InstanceInterface;
6
- use Chisel\Interfaces\HooksInterface;
7
- use Chisel\Traits\Singleton;
8
-
9
- /**
10
- * ACF related functionalities.
11
- *
12
- * @package Chisel
13
- */
14
- class AcfSync extends \ACF_Admin_Internal_Post_Type_List implements InstanceInterface, HooksInterface {
15
-
16
- use Singleton;
17
-
18
- /**
19
- * The acf groups post type.
20
- *
21
- * @var string
22
- */
23
- public $post_type = 'acf-field-group';
24
-
25
- /**
26
- * The acf groups sync data.
27
- *
28
- * @var array
29
- */
30
- public $sync = array();
31
-
32
- /**
33
- * The acf group single post id.
34
- *
35
- * @var null|int
36
- */
37
- private $post_id = null;
38
-
39
- /**
40
- * The key of acf field group to sync.
41
- *
42
- * @var null|string
43
- */
44
- private $single_post_key = null;
45
-
46
- /**
47
- * The acf groups sync page url.
48
- *
49
- * @var string
50
- */
51
- private $sync_page_url = '';
52
-
53
- /**
54
- * ACF section current page
55
- *
56
- * @var string
57
- */
58
- public $view = '';
59
-
60
-
61
- /**
62
- * Class constructor.
63
- */
64
- private function __construct() {
65
- $this->action_hooks();
66
- $this->filter_hooks();
67
- }
68
-
69
- /**
70
- * Register action hooks.
71
- */
72
- public function action_hooks() {
73
- add_action( 'admin_notices', array( $this, 'acf_sync_notice' ) );
74
- add_action( 'init', array( $this, 'set_properties' ) );
75
-
76
- add_filter( 'chisel_admin_styles', array( $this, 'load_plugin_scripts' ) );
77
- add_filter( 'chisel_admin_scripts', array( $this, 'load_plugin_scripts' ) );
78
- }
79
-
80
- /**
81
- * Register filter hooks.
82
- */
83
- public function filter_hooks() {
84
- }
85
-
86
- /**
87
- * Set properties.
88
- */
89
- public function set_properties() {
90
- if ( wp_doing_ajax() || wp_doing_cron() ) {
91
- return;
92
- }
93
-
94
- // Stop if parent method doesn't exist.
95
- if ( ! method_exists( $this, 'setup_sync' ) ) {
96
- return;
97
- }
98
-
99
- global $pagenow;
100
- $this->view = acf_request_arg( 'post_status', '' );
101
-
102
- if ( $pagenow === 'edit.php' && isset( $_GET['post_type'] ) && sanitize_text_field( wp_unslash( $_GET['post_type'] ) ) === $this->post_type ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
103
- $this->view = 'all';
104
- }
105
-
106
- if ( $pagenow === 'post.php' && isset( $_GET['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
107
- $post_id = absint( $_GET['post'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
108
- $post_type = get_post_type( $post_id );
109
-
110
- if ( $post_type === $this->post_type ) {
111
- $this->post_id = $post_id;
112
- $this->view = 'single';
113
- }
114
- }
115
-
116
- if ( ! $this->view ) {
117
- return;
118
- }
119
-
120
- // Check for unsynced fields groups. Call a parent method.
121
- $this->setup_sync();
122
-
123
- if ( $this->view === 'single' && $this->sync ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
124
- foreach ( $this->sync as $key => $field_group ) {
125
- if ( $field_group['ID'] === $this->post_id ) {
126
- $this->single_post_key = $key;
127
-
128
- break;
129
- }
130
- }
131
- }
132
-
133
- $this->sync_page_url = add_query_arg(
134
- array(
135
- 'post_type' => $this->post_type,
136
- 'post_status' => 'sync',
137
- ),
138
- admin_url( 'edit.php' )
139
- );
140
- }
141
-
142
- /**
143
- * Enqueue plugin scripts
144
- *
145
- * @param array $scripts
146
- *
147
- * @return array
148
- */
149
- public function load_plugin_scripts( $scripts ) {
150
- $scripts['acf-sync'] = array();
151
-
152
- return $scripts;
153
- }
154
-
155
- /**
156
- * Check if sync notice needs to be displayed.
157
- *
158
- * @return void
159
- */
160
- public function acf_sync_notice() {
161
- if ( $this->post_id && $this->single_post_key ) { // We're on a single page.
162
- $this->display_modal_notice();
163
- } elseif ( $this->sync ) {
164
- $this->display_admin_notice();
165
- }
166
- }
167
-
168
- /**
169
- * Display ACF sync admin notice.
170
- *
171
- * @return void
172
- */
173
- private function display_admin_notice() {
174
- ?>
175
- <div class="error">
176
- <p><?php esc_html_e( 'You have unsynced ACF fields.', 'chisel' ); ?> <a href="<?php echo esc_url( $this->sync_page_url ); ?>"><?php esc_html_e( ' View fields available for sync', 'chisel' ); ?></a></p>
177
- </div>
178
- <?php
179
- }
180
-
181
- /**
182
- * Display ACF sync modal notice.
183
- *
184
- * @return void
185
- */
186
- private function display_modal_notice() {
187
- $url = $this->get_admin_url( '&acfsync=' . $this->single_post_key . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
188
- ?>
189
- <div class="xfive-acf-sync-modal js-xfive-acf-sync-modal is-open" role="dialog">
190
- <div class="xfive-acf-sync-modal__box">
191
- <div class="xfive-acf-sync-modal__content">
192
- <div class="xfive-acf-sync-modal__icon">
193
- <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
194
- <path stroke="#d63638" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 11V6m0 8h.01M19 10a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"></path>
195
- </svg>
196
- </div>
197
-
198
- <h3>
199
- <?php esc_html_e( 'The field group you are editing has not been synced with your local acf json file.', 'chisel' ); ?>
200
- <?php esc_html_e( 'Making any changes will overwrite the local json file and result in losing data.', 'chisel' ); ?>
201
- <?php esc_html_e( 'This is irreversible.', 'chisel' ); ?>
202
- </h3>
203
-
204
- <div class="xfive-acf-sync-modal__actions">
205
- <a href="<?php echo esc_url( $this->sync_page_url ); ?>" class="acf-btn"><?php esc_html_e( 'View changes', 'chisel' ); ?></a>
206
- <a href="<?php echo esc_url( $url ); ?>" class="acf-btn"><?php esc_html_e( 'Sync data', 'chisel' ); ?></a>
207
- <button type="button" class="acf-btn acf-btn-secondary js-xfive-acf-sync-modal-close"><?php esc_html_e( 'Ignore', 'chisel' ); ?></button>
208
- </div>
209
- </div>
210
- </div>
211
- </div>
212
- <?php
213
- }
214
-
215
- /**
216
- * Check if the sync notice scripts should be loaded.
217
- *
218
- * @return bool
219
- */
220
- public static function load_scripts() {
221
- return self::get_instance()->post_id && self::get_instance()->single_post_key;
222
- }
223
- }
@@ -1,26 +0,0 @@
1
- class XfiveACFSync {
2
- constructor() {
3
- this.modal = document.querySelector('.js-xfive-acf-sync-modal');
4
-
5
- if (!this.modal) {
6
- return;
7
- }
8
-
9
- this.classnames = {
10
- open: 'is-open',
11
- };
12
-
13
- this.modalCloseButton = document.querySelector('.js-xfive-acf-sync-modal-close');
14
-
15
- this.modalCloseHandler();
16
- }
17
-
18
- modalCloseHandler() {
19
- this.modalCloseButton.addEventListener('click', () => {
20
- this.modal.classList.remove(this.classnames.open);
21
- });
22
- }
23
- }
24
-
25
- // eslint-disable-next-line no-new
26
- new XfiveACFSync();
@@ -1,64 +0,0 @@
1
- /* ACF Sync module styles */
2
-
3
- .xfive-acf-sync-modal {
4
- position: fixed;
5
- inset: 0;
6
- z-index: 99999;
7
- display: none;
8
- align-items: center;
9
- justify-content: center;
10
- overflow: auto;
11
- background-color: rgba(0, 0, 0, 50%);
12
-
13
- &.is-open {
14
- display: flex;
15
- }
16
- }
17
-
18
- .xfive-acf-sync-modal__box {
19
- width: 100%;
20
- max-width: 500px;
21
- padding: 16px;
22
- margin-top: auto;
23
- margin-bottom: auto;
24
- }
25
-
26
- .xfive-acf-sync-modal__content {
27
- padding: 24px;
28
- font-size: 20px;
29
- line-height: 1.5;
30
- text-align: center;
31
- background-color: #fff;
32
- border-radius: 8px;
33
- box-shadow:
34
- rgba(0, 0, 0, 0%) 0 0 0 0,
35
- rgba(0, 0, 0, 0%) 0 0 0 0,
36
- rgba(0, 0, 0, 10%) 0 1px 3px 0,
37
- rgba(0, 0, 0, 10%) 0 1px 2px -1px;
38
-
39
- h3 {
40
- margin-bottom: 30px;
41
- font-size: 18px !important;
42
- }
43
- }
44
-
45
- .xfive-acf-sync-modal__actions {
46
- display: grid;
47
- grid-template-columns: repeat(3, 1fr);
48
- gap: 16px;
49
-
50
- a,
51
- button {
52
- justify-content: center;
53
- font-size: 15px;
54
- }
55
- }
56
-
57
- .xfive-acf-sync-modal__icon {
58
- text-align: center;
59
-
60
- svg {
61
- width: 50px;
62
- height: 50px;
63
- }
64
- }