/var/www/html_us/wp-content/plugins/woocommerce/src/Blocks/BlockPatterns.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
<?php
declare(strict_types=1);

namespace 
Automattic\WooCommerce\Blocks;

use 
Automattic\WooCommerce\Admin\Features\Features;
use 
Automattic\WooCommerce\Blocks\AIContent\PatternsHelper;
use 
Automattic\WooCommerce\Blocks\Domain\Package;
use 
Automattic\WooCommerce\Blocks\Patterns\PatternRegistry;
use 
Automattic\WooCommerce\Blocks\Patterns\PTKPatternsStore;
use 
WP_Error;

/**
 * Registers patterns under the `./patterns/` directory and from the PTK API and updates their content.
 * Each pattern from core is defined as a PHP file and defines its metadata using plugin-style headers.
 * The minimum required definition is:
 *
 *     /**
 *      * Title: My Pattern
 *      * Slug: my-theme/my-pattern
 *      *
 *
 * The output of the PHP source corresponds to the content of the pattern, e.g.:
 *
 *     <main><p><?php echo "Hello"; ?></p></main>
 *
 * Other settable fields include:
 *
 *   - Description
 *   - Viewport Width
 *   - Categories       (comma-separated values)
 *   - Keywords         (comma-separated values)
 *   - Block Types      (comma-separated values)
 *   - Inserter         (yes/no)
 *
 * @internal
 */
class BlockPatterns {
    const 
CATEGORIES_PREFIXES = [ '_woo_''_dotcom_imported_' ];

    
/**
     * Path to the patterns' directory.
     *
     * @var string $patterns_path
     */
    
private string $patterns_path;

    
/**
     * PatternRegistry instance.
     *
     * @var PatternRegistry $pattern_registry
     */
    
private PatternRegistry $pattern_registry;

    
/**
     * Patterns dictionary
     *
     * @var array|WP_Error
     */
    
private $dictionary;

    
/**
     * PTKPatternsStore instance.
     *
     * @var PTKPatternsStore $ptk_patterns_store
     */
    
private PTKPatternsStore $ptk_patterns_store;

    
/**
     * Constructor for class
     *
     * @param Package          $package An instance of Package.
     * @param PatternRegistry  $pattern_registry An instance of PatternRegistry.
     * @param PTKPatternsStore $ptk_patterns_store An instance of PTKPatternsStore.
     */
    
public function __construct(
        
Package $package,
        
PatternRegistry $pattern_registry,
        
PTKPatternsStore $ptk_patterns_store
    
) {
        
$this->patterns_path      $package->get_path'patterns' );
        
$this->pattern_registry   $pattern_registry;
        
$this->ptk_patterns_store $ptk_patterns_store;

        
add_action'init', array( $this'register_block_patterns' ) );

        if ( 
Features::is_enabled'pattern-toolkit-full-composability' ) ) {
            
add_action'init', array( $this'register_ptk_patterns' ) );
        }
    }

    
/**
     * Returns the Patterns dictionary.
     *
     * @return array|WP_Error
     */
    
private function get_patterns_dictionary() {
        if ( 
null === $this->dictionary ) {
            
$this->dictionary PatternsHelper::get_patterns_dictionary();
        }

        return 
$this->dictionary;
    }

    
/**
     * Register block patterns from core.
     *
     * @return void
     */
    
public function register_block_patterns() {
        if ( ! 
class_exists'WP_Block_Patterns_Registry' ) ) {
            return;
        }

        
$patterns $this->get_block_patterns();
        foreach ( 
$patterns as $pattern ) {
            
$this->pattern_registry->register_block_pattern$pattern['source'], $pattern$this->get_patterns_dictionary() );
        }
    }

    
/**
     * Gets block pattern data from the cache if available
     *
     * @return array Block pattern data.
     */
    
private function get_block_patterns() {
        
$pattern_data $this->get_pattern_cache();

        if ( 
is_array$pattern_data ) ) {
            return 
$pattern_data;
        }

        
$default_headers = array(
            
'title'         => 'Title',
            
'slug'          => 'Slug',
            
'description'   => 'Description',
            
'viewportWidth' => 'Viewport Width',
            
'categories'    => 'Categories',
            
'keywords'      => 'Keywords',
            
'blockTypes'    => 'Block Types',
            
'inserter'      => 'Inserter',
            
'featureFlag'   => 'Feature Flag',
            
'templateTypes' => 'Template Types',
        );

        if ( ! 
file_exists$this->patterns_path ) ) {
            return array();
        }

        
$files glob$this->patterns_path '/*.php' );
        if ( ! 
$files ) {
            return array();
        }

        
$patterns = array();

        foreach ( 
$files as $file ) {
            
$data           get_file_data$file$default_headers );
            
$data['source'] = $file;
            
$patterns[]     = $data;
        }

        
$this->set_pattern_cache$patterns );
        return 
$patterns;
    }

    
/**
     * Gets block pattern cache.
     *
     * @return array|false Returns an array of patterns if cache is found, otherwise false.
     */
    
private function get_pattern_cache() {
        
$pattern_data get_site_transient'woocommerce_blocks_patterns' );

        if ( 
is_array$pattern_data ) && WOOCOMMERCE_VERSION === $pattern_data['version'] ) {
            return 
$pattern_data['patterns'];
        }

        return 
false;
    }

    
/**
     * Sets block pattern cache.
     *
     * @param array $patterns Block patterns data to set in cache.
     */
    
private function set_pattern_cache( array $patterns ) {
        
$pattern_data = array(
            
'version'  => WOOCOMMERCE_VERSION,
            
'patterns' => $patterns,
        );

        
set_site_transient'woocommerce_blocks_patterns'$pattern_dataMONTH_IN_SECONDS );
    }

    
/**
     * Register patterns from the Patterns Toolkit.
     *
     * @return void
     */
    
public function register_ptk_patterns() {
        
// Only if the user has allowed tracking, we register the patterns from the PTK.
        
$allow_tracking 'yes' === get_option'woocommerce_allow_tracking' );
        if ( ! 
$allow_tracking ) {
            return;
        }

        
// The most efficient way to check for an existing action is to use `as_has_scheduled_action`, but in unusual
        // cases where another plugin has loaded a very old version of Action Scheduler, it may not be available to us.
        
$has_scheduled_action function_exists'as_has_scheduled_action' ) ? 'as_has_scheduled_action' 'as_next_scheduled_action';

        
$patterns $this->ptk_patterns_store->get_patterns();
        if ( empty( 
$patterns ) ) {
            
// Only log once per day by using a transient.
            
$transient_key 'wc_ptk_pattern_store_warning';
            
// By only logging when patterns are empty and no fetch is scheduled,
            // we ensure that warnings are only generated in genuinely problematic situations,
            // such as when the pattern fetching mechanism has failed entirely.
            
if ( ! get_transient$transient_key ) && ! call_user_func$has_scheduled_action'fetch_patterns' ) ) {
                
wc_get_logger()->warning(
                    
__'Empty patterns received from the PTK Pattern Store''woocommerce' ),
                );
                
// Set the transient to true to indicate that the warning has been logged in the current day.
                
set_transient$transient_keytrueDAY_IN_SECONDS );
            }
            return;
        }

        
$patterns $this->parse_categories$patterns );

        foreach ( 
$patterns as $pattern ) {
            
$pattern['slug']    = $pattern['name'];
            
$pattern['content'] = $pattern['html'];

            
$this->pattern_registry->register_block_pattern$pattern['ID'], $pattern$this->get_patterns_dictionary() );
        }
    }

    
/**
     * Parse prefixed categories from the PTK patterns into the actual WooCommerce categories.
     *
     * @param array $patterns The patterns to parse.
     * @return array The parsed patterns.
     */
    
private function parse_categories( array $patterns ) {
        return 
array_map(
            function ( 
$pattern ) {
                
$pattern['categories'] = array_map(
                    function ( 
$category ) {
                        foreach ( 
self::CATEGORIES_PREFIXES as $prefix ) {
                            if ( 
strpos$category['title'], $prefix ) !== false ) {
                                
$parsed_category   str_replace$prefix''$category['title'] );
                                
$parsed_category   str_replace'_'' '$parsed_category );
                                
$category['title'] = ucfirst$parsed_category );
                            }
                        }

                        return 
$category;
                    },
                    
$pattern['categories']
                );
                return 
$pattern;
            },
            
$patterns
        
);
    }
}