• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

timber / timber / 21904947821

11 Feb 2026 12:24PM UTC coverage: 89.673% (+0.07%) from 89.608%
21904947821

Pull #3023

travis-ci

web-flow
Merge 70be7c33f into d6c4d6191
Pull Request #3023: Add render_twig_block method

65 of 67 new or added lines in 4 files covered. (97.01%)

38 existing lines in 6 files now uncovered.

4637 of 5171 relevant lines covered (89.67%)

65.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.03
/src/Loader.php
1
<?php
2

3
namespace Timber;
4

5
use InvalidArgumentException;
6
use Timber\Cache\Cleaner;
7
use Twig\CacheExtension;
8
use Twig\Environment;
9
use Twig\Extension\DebugExtension;
10
use Twig\Loader\FilesystemLoader;
11
use Twig\TwigFunction;
12

13
class Loader implements LoaderInterface
14
{
15
    public const CACHEGROUP = 'timberloader';
16

17
    public const TRANS_KEY_LEN = 50;
18

19
    public const CACHE_NONE = 'none';
20

21
    public const CACHE_OBJECT = 'cache';
22

23
    public const CACHE_TRANSIENT = 'transient';
24

25
    public const CACHE_SITE_TRANSIENT = 'site-transient';
26

27
    public const CACHE_USE_DEFAULT = 'default';
28

29
    /** Identifier of the main namespace. Will likely mirror Twig\Loader\FilesystemLoader::MAIN_NAMESPACE */
30
    public const MAIN_NAMESPACE = '__main__';
31

32
    public static $cache_modes = [
33
        self::CACHE_NONE,
34
        self::CACHE_OBJECT,
35
        self::CACHE_TRANSIENT,
36
        self::CACHE_SITE_TRANSIENT,
37
    ];
38

39
    protected $cache_mode = self::CACHE_TRANSIENT;
40

41
    protected $locations;
42

43
    /**
44
     * @param bool|string   $caller the calling directory or false
45
     */
46
    public function __construct($caller = false)
451✔
47
    {
48
        $this->locations = LocationManager::get_locations($caller);
451✔
49

50
        /**
51
         * Filters the cache mode.
52
         *
53
         * You can read more about Caching in the
54
         * [Performance/Caching]({{<relref "performance.md" >}}) guide.
55
         *
56
         * @since 0.20.10
57
         *
58
         * @param string $cache_mode The cache mode. Can be one of the following:
59
         *                           `Timber\Loader::CACHE_NONE`,
60
         *                           `Timber\Loader::CACHE_OBJECT`,
61
         *                           `Timber\Loader::CACHE_TRANSIENT`,
62
         *                           `Timber\Loader::CACHE_SITE_TRANSIENT`,
63
         *                           `Timber\Loader::CACHE_USE_DEFAULT`.
64
         *                           Default `Timber\Loader::CACHE_TRANSIENT`.
65
         */
66
        $this->cache_mode = \apply_filters('timber/cache/mode', $this->cache_mode);
451✔
67

68
        /**
69
         * Filters the cache mode.
70
         *
71
         * @deprecated 2.0.0, use `timber/cache/mode`
72
         */
73
        $this->cache_mode = \apply_filters_deprecated(
451✔
74
            'timber_cache_mode',
451✔
75
            [$this->cache_mode],
451✔
76
            '2.0.0',
451✔
77
            'timber/cache/mode'
451✔
78
        );
451✔
79
    }
80

81
    /**
82
     * @param string            $file
83
     * @param array             $data
84
     * @param array|boolean     $expires (array for options, false for none, integer for # of seconds)
85
     * @param string            $cache_mode
86
     * @return bool|string
87
     */
88
    public function render($file, $data = null, $expires = false, $cache_mode = self::CACHE_USE_DEFAULT)
100✔
89
    {
90
        // Different $expires if user is anonymous or logged in
91
        if (\is_array($expires)) {
100✔
92
            /** @var array $expires */
93
            if (\is_user_logged_in() && isset($expires[1])) {
4✔
94
                $expires = $expires[1];
1✔
95
            } else {
96
                $expires = $expires[0];
3✔
97
            }
98
        }
99

100
        if ($expires === 0) {
100✔
UNCOV
101
            $expires = false;
×
102
        }
103

104
        $key = null;
100✔
105
        $output = false;
100✔
106
        if (false !== $expires) {
100✔
107
            $key = $this->get_cache_key($file, $data);
17✔
108
            if (null !== $key) {
17✔
109
                $output = $this->get_cache($key, self::CACHEGROUP, $cache_mode);
16✔
110
            }
111
        }
112

113
        if (false === $output || null === $output) {
100✔
114
            $output = $this->render_template($file, $data);
100✔
115
        }
116

117
        if (false !== $output && false !== $expires && null !== $key) {
99✔
118
            $this->delete_cache();
16✔
119
            $this->set_cache($key, $output, self::CACHEGROUP, $expires, $cache_mode);
16✔
120
        }
121

122
        /**
123
         * Filters …
124
         *
125
         * @todo  Add summary, description, example, parameter descriptions
126
         *
127
         * @since 0.20.10
128
         *
129
         * @param string $output
130
         * @param array  $data
131
         * @param string $file
132
         */
133
        $output = \apply_filters('timber/output', $output, $data, $file);
99✔
134

135
        /**
136
         * Filters …
137
         *
138
         * @todo Add summary
139
         *
140
         * @deprecated 2.0.0, use `timber/output`
141
         */
142
        $output = \apply_filters_deprecated('timber_output', [$output], '2.0.0', 'timber/output');
99✔
143

144
        return $output;
99✔
145
    }
146

147
    public function delete_cache()
16✔
148
    {
149
        Cleaner::delete_transients();
16✔
150
    }
151

152
    /**
153
     * Generate a cache key for the template.
154
     *
155
     * @param string $file The template file.
156
     * @param array  $data The data to pass to the template.
157
     * @return string|null The cache key or null if encoding failed.
158
     */
159
    protected function get_cache_key($file, $data)
14✔
160
    {
161
        \ksort($data);
14✔
162
        $encoded = \json_encode($data);
14✔
163

164
        /**
165
         * The encoding might fail, e.g. when an object has a recursion. In that case, we'd rather not cache the
166
         * data instead of possibly returning the wrong data.
167
         */
168
        if (false === $encoded) {
14✔
NEW
169
            return null;
×
170
        }
171

172
        return \md5($file . $encoded);
14✔
173
    }
174

175
    /**
176
     * Render the template and return the output.
177
     *
178
     * @param string $file The template file.
179
     * @param array  $data The data to pass to the template.
180
     * @return string The rendered output.
181
     */
182
    protected function render_template($file, $data)
100✔
183
    {
184
        $twig = $this->get_twig();
100✔
185

186
        if (\strlen($file)) {
100✔
187
            $loader = $this->get_loader();
100✔
188
            $result = $loader->getCacheKey($file);
100✔
189

190
            /**
191
             * Fires after …
192
             *
193
             * @todo Add summary, description parameter description
194
             *
195
             * @param string $result
196
             */
197
            \do_action('timber/loader/render_file', $result);
100✔
198

199
            /**
200
             * Fires after …
201
             *
202
             * This action is used by the Timber Debug Bar extension.
203
             *
204
             * @todo Add summary
205
             *
206
             * @deprecated 2.0.0, use `timber/loader/render_file`
207
             */
208
            \do_action_deprecated(
100✔
209
                'timber_loader_render_file',
100✔
210
                [$result],
100✔
211
                '2.0.0',
100✔
212
                'timber/loader/render_file'
100✔
213
            );
100✔
214
        }
215

216
        /**
217
         * Filters …
218
         *
219
         * @todo Add summary, description, example, parameter descriptions
220
         *
221
         * @since 0.20.10
222
         *
223
         * @param array  $data
224
         * @param string $file
225
         */
226
        $data = \apply_filters('timber/loader/render_data', $data, $file);
100✔
227

228
        /**
229
         * Filters …
230
         *
231
         * @todo Add summary
232
         *
233
         * @deprecated 2.0.0, use `timber/loader/render_data`
234
         */
235
        $data = \apply_filters_deprecated(
100✔
236
            'timber_loader_render_data',
100✔
237
            [$data],
100✔
238
            '2.0.0',
100✔
239
            'timber/loader/render_data'
100✔
240
        );
100✔
241

242
        $template = $twig->load($file);
100✔
243
        $output = $this->render_twig_template($template, $data);
99✔
244

245
        /**
246
         * Filters $output before it is cached.
247
         *
248
         * @since 2.1.0
249
         *
250
         * @param string $output
251
         * @param array  $data
252
         * @param string $file
253
         */
254
        return \apply_filters('timber/output/pre-cache', $output, $data, $file);
99✔
255
    }
256

257
    /**
258
     * Render a Twig template.
259
     *
260
     * This method can be overridden in subclasses to customize rendering behavior.
261
     *
262
     * @param \Twig\TemplateWrapper $template The Twig template.
263
     * @param array                  $data     The data to pass to the template.
264
     * @return string The rendered output.
265
     */
266
    protected function render_twig_template($template, $data)
82✔
267
    {
268
        return $template->render($data);
82✔
269
    }
270

271
    /**
272
     * Get first existing template.
273
     *
274
     * @param array|string $templates  Name(s) of the Twig template(s) to choose from.
275
     * @return string|bool             Name of chosen template, otherwise false.
276
     */
277
    public function choose_template($templates)
107✔
278
    {
279
        // Change $templates into array, if needed
280
        if (!\is_array($templates)) {
107✔
281
            $templates = (array) $templates;
102✔
282
        }
283

284
        // Get Twig loader
285
        $loader = $this->get_loader();
107✔
286

287
        // Run through template array
288
        foreach ($templates as $template) {
107✔
289
            // Remove any whitespace around the template name
290
            $template = \trim((string) $template);
107✔
291
            // Use the Twig loader to test for existence
292
            if ($loader->exists($template)) {
107✔
293
                // Return name of existing template
294
                return $template;
100✔
295
            }
296
        }
297

298
        // No existing template was found
299
        return false;
7✔
300
    }
301

302
    /**
303
     * @return FilesystemLoader
304
     */
305
    public function get_loader()
441✔
306
    {
307
        $paths = $this->locations;
441✔
308

309
        /**
310
         * Filters the template paths used by the Loader.
311
         *
312
         * @since 0.20.10
313
         *
314
         * @deprecated 2.0.0, use `timber/locations`
315
         *
316
         * @param array $paths
317
         */
318
        $paths = \apply_filters_deprecated(
441✔
319
            'timber/loader/paths',
441✔
320
            [$paths],
441✔
321
            '2.0.0',
441✔
322
            'timber/locations'
441✔
323
        );
441✔
324

325
        $open_basedir = \ini_get('open_basedir');
441✔
326
        $rootPath = '/';
441✔
327
        if ($open_basedir) {
441✔
UNCOV
328
            $rootPath = null;
×
329
        }
330

331
        $fs = new FilesystemLoader([], $rootPath);
441✔
332

333
        foreach ($paths as $namespace => $path_locations) {
441✔
334
            if (\is_array($path_locations)) {
441✔
335
                \array_map(function ($path) use ($fs, $namespace) {
440✔
336
                    if (\is_string($namespace)) {
440✔
337
                        $fs->addPath($path, $namespace);
440✔
338
                    } else {
339
                        $fs->addPath($path, Loader::MAIN_NAMESPACE);
8✔
340
                    }
341
                }, $path_locations);
440✔
342
            } else {
343
                Helper::deprecated(
2✔
344
                    'add_filter( \'timber/loader/paths\', [\'path/to/my/templates\'] ) in a non-associative array',
2✔
345
                    'add_filter( \'timber/loader/paths\', [ 0 => [ \'path/to/my/templates\' ] ] )',
2✔
346
                    '2.0.0'
2✔
347
                );
2✔
348
                $fs->addPath($path_locations, self::MAIN_NAMESPACE);
2✔
349
            }
350
        }
351

352
        /**
353
         * Filters …
354
         *
355
         * @todo Add summary, description, example, parameter description
356
         *
357
         * @link https://github.com/timber/timber/pull/1254
358
         * @since 1.1.11
359
         */
360
        $fs = \apply_filters('timber/loader/loader', $fs);
441✔
361

362
        return $fs;
441✔
363
    }
364

365
    /**
366
     * @return Environment
367
     */
368
    public function get_twig()
434✔
369
    {
370
        // Default options.
371
        $environment_options = [
434✔
372
            'debug' => WP_DEBUG,
434✔
373
            'autoescape' => false,
434✔
374
            'cache' => false,
434✔
375
        ];
434✔
376

377
        /**
378
         * Filters the environment options that are used when creating a Twig Environment instance.
379
         *
380
         * By default, Timber sets the following values:
381
         *
382
         * - `'debug' => WP_DEBUG`
383
         * - `'autoescape' => false`
384
         * - `'cache' => false`
385
         *
386
         * @api
387
         * @since 1.9.5
388
         * @link https://twig.symfony.com/doc/2.x/api.html#environment-options
389
         * @example
390
         * ```php
391
         * add_filter( 'timber/twig/environment/options', 'update_twig_environment_options' );
392
         *
393
         * /**
394
         *  * Updates Twig environment options.
395
         *  *
396
         *  * @link https://twig.symfony.com/doc/2.x/api.html#environment-options
397
         *  *
398
         *  * \@param array $options An array of environment options.
399
         *  *
400
         *  * @return array
401
         *  *\/
402
         * function update_twig_environment_options( $options ) {
403
         *     $options['cache']       = true;
404
         *     $options['auto_reload'] = true;
405
         *
406
         *     return $options;
407
         * }
408
         * ```
409
         *
410
         * @param array $environment_options An array of Twig environment options.
411
         */
412
        $environment_options = \apply_filters(
434✔
413
            'timber/twig/environment/options',
434✔
414
            $environment_options
434✔
415
        );
434✔
416

417
        /**
418
         * @deprecated 2.0.0
419
         */
420
        if (isset(Timber::$autoescape) && false !== Timber::$autoescape) {
434✔
421
            Helper::deprecated(
1✔
422
                'Timber::$autoescape',
1✔
423
                'the \'timber/twig/environment/options filter\'',
1✔
424
                '2.0.0'
1✔
425
            );
1✔
426

427
            $environment_options['autoescape'] = Timber::$autoescape;
1✔
428
        }
429

430
        /**
431
         * Backwards compatibility fix.
432
         *
433
         * The value `true` doesn’t exist anymore for the `autoescape` option. You need to define
434
         * an auto-escaping fallback strategy. This fallback uses the `html` strategy.
435
         */
436
        if (true === $environment_options['autoescape']) {
434✔
437
            $environment_options['autoescape'] = 'html';
2✔
438
        }
439

440
        /**
441
         * Alias Timber::$cache can be used for Timber::$twig_cache.
442
         *
443
         * @deprecated 2.0.0
444
         */
445
        if (isset(Timber::$cache) && true === Timber::$cache) {
434✔
446
            Timber::$twig_cache = true;
1✔
447
        }
448

449
        /**
450
         * @deprecated 2.0.0
451
         */
452
        if (isset(Timber::$twig_cache) && false !== Timber::$twig_cache) {
434✔
453
            Helper::deprecated(
2✔
454
                'Timber::$cache and Timber::$twig_cache',
2✔
455
                'the \'timber/twig/environment/options filter\'',
2✔
456
                '2.0.0'
2✔
457
            );
2✔
458

459
            $environment_options['cache'] = Timber::$twig_cache;
2✔
460
        }
461

462
        if (true === $environment_options['cache']) {
434✔
463
            $twig_cache_loc = TIMBER_LOC . '/cache/twig';
8✔
464

465
            /**
466
             * Filters the cache location used for Twig.
467
             *
468
             * Allows you to set a new cache location for Twig. If the folder doesn’t exist yet, it
469
             * will be created automatically.
470
             *
471
             * @since 0.20.10
472
             * @deprecated 2.0.0
473
             *
474
             * @param string $twig_cache_loc Full path to the cache location. Default `/cache/twig`
475
             *                               in the Timber root folder.
476
             */
477
            $twig_cache_loc = \apply_filters_deprecated(
8✔
478
                'timber/cache/location',
8✔
479
                [$twig_cache_loc],
8✔
480
                '2.0.0',
8✔
481
                'timber/twig/environment/options'
8✔
482
            );
8✔
483

484
            if (!\file_exists($twig_cache_loc)) {
8✔
485
                \mkdir($twig_cache_loc, 0777, true);
8✔
486
            }
487

488
            $environment_options['cache'] = $twig_cache_loc;
8✔
489
        }
490
        $twig = new Environment($this->get_loader(), $environment_options);
434✔
491

492
        if (WP_DEBUG) {
434✔
493
            $twig->addExtension(new DebugExtension());
434✔
494
        } else {
UNCOV
495
            $twig->addFunction(new TwigFunction('dump', fn () => null));
×
496
        }
497

498
        /**
499
         * Filters the cache extension activation.
500
         *
501
         * Allows users to disable the cache extension and use their own
502
         *
503
         * @since 2.0.0
504
         * @param bool $enable_cache_extension Whether to enable the cache extension.
505
         */
506
        $enable_cache_extension = \apply_filters('timber/cache/enable_extension', true);
434✔
507

508
        if ($enable_cache_extension && \class_exists(CacheExtension\Extension::class)) {
434✔
UNCOV
509
            $twig->addExtension($this->_get_cache_extension());
×
510
        }
511

512
        /**
513
         * Filters …
514
         *
515
         * @todo Add summary, description, example
516
         *
517
         * @since 0.20.10
518
         *
519
         * @param Environment $twig The Twig environment you can add functionality to.
520
         */
521
        $twig = \apply_filters('timber/loader/twig', $twig);
434✔
522

523
        /**
524
         * Filters …
525
         *
526
         * @deprecated 2.0.0, use `timber/twig`
527
         */
528
        $twig = \apply_filters_deprecated('twig_apply_filters', [$twig], '2.0.0', 'timber/twig');
434✔
529

530
        /**
531
         * Filters the Twig environment used in the global context.
532
         *
533
         * You can use this filter if you want to add additional functionality to Twig, like global
534
         * variables, filters or functions.
535
         *
536
         * @since 0.21.9
537
         * @example
538
         * ```php
539
         * /**
540
         *  * Adds Twig functionality.
541
         *  *
542
         *  * \@param \Twig\Environment $twig The Twig Environment to which you can add additional functionality.
543
         *  *\/
544
         * add_filter( 'timber/twig', function( $twig ) {
545
         *     // Make get_theme_file_uri() usable as {{ theme_file() }} in Twig.
546
         *     $twig->addFunction( new Twig\TwigFunction( 'theme_file', 'get_theme_file_uri' ) );
547
         *
548
         *     return $twig;
549
         * } );
550
         * ```
551
         *
552
         * ```twig
553
         * <a class="navbar-brand" href="{{ site.url }}">
554
         *     <img src="{{ theme_file( 'build/img/logo-example.svg' ) }}" alt="Logo {{ site.title }}">
555
         * </a>
556
         * ```
557
         *
558
         * @param Environment $twig The Twig environment.
559
         */
560
        $twig = \apply_filters('timber/twig', $twig);
434✔
561

562
        /**
563
         * Filters the Twig environment used in the global context.
564
         *
565
         * @deprecated 2.0.0
566
         */
567
        $twig = \apply_filters_deprecated('get_twig', [$twig], '2.0.0', 'timber/twig');
434✔
568

569
        return $twig;
434✔
570
    }
571

572
    /**
573
     * Clears Timber’s cache.
574
     *
575
     * @param string $cache_mode
576
     * @return bool Whether Timber’s cache was cleared
577
     */
578
    public function clear_cache_timber($cache_mode = self::CACHE_USE_DEFAULT)
9✔
579
    {
580
        //_transient_timberloader
581
        $cache_mode = $this->_get_cache_mode($cache_mode);
9✔
582

583
        if (self::CACHE_TRANSIENT === $cache_mode || self::CACHE_SITE_TRANSIENT === $cache_mode) {
9✔
584
            // $wpdb->query() might return 0 affected rows, but that means it’s still successful.
585
            return false !== self::clear_cache_timber_database();
8✔
586
        } elseif (self::CACHE_OBJECT === $cache_mode && $this->is_object_cache()) {
1✔
587
            return false !== self::clear_cache_timber_object();
1✔
588
        }
589

UNCOV
590
        return false;
×
591
    }
592

593
    /**
594
     * Clears Timber cache in database.
595
     *
596
     * @return bool|int Number of deleted rows or false on error.
597
     */
598
    protected static function clear_cache_timber_database()
8✔
599
    {
600
        global $wpdb;
601

602
        return $wpdb->query($wpdb->prepare(
8✔
603
            "DELETE FROM $wpdb->options WHERE option_name LIKE '%s'",
8✔
604
            '_transient%timberloader_%'
8✔
605
        ));
8✔
606
    }
607

608
    /**
609
     * @return bool True when no cache was found or all cache was deleted, false when there was an
610
     *              error deleting the cache.
611
     */
612
    protected static function clear_cache_timber_object()
1✔
613
    {
614
        global $wp_object_cache;
615

616
        $result = true;
1✔
617

618
        // Return true if no object cache is set.
619
        if (!isset($wp_object_cache->cache[self::CACHEGROUP])) {
1✔
UNCOV
620
            return $result;
×
621
        }
622

623
        $items = $wp_object_cache->cache[self::CACHEGROUP];
1✔
624

625
        foreach ($items as $key => $value) {
1✔
626
            if (\is_multisite()) {
1✔
UNCOV
627
                $key = \preg_replace('/^(.*?):/', '', (string) $key);
×
628
            }
629

630
            // If any cache couldn’t be deleted, the result will be false.
631
            if (!\wp_cache_delete($key, self::CACHEGROUP)) {
1✔
UNCOV
632
                $result = false;
×
633
            }
634
        }
635

636
        return $result;
1✔
637
    }
638

639
    public function clear_cache_twig()
11✔
640
    {
641
        $twig = $this->get_twig();
11✔
642

643
        // Get the configured cache location.
644
        $cache_location = $twig->getCache(true);
11✔
645

646
        // Cache not activated.
647
        if (!$cache_location) {
11✔
648
            return true;
3✔
649
        }
650

651
        if (\is_string($cache_location) && \is_dir($cache_location)) {
8✔
652
            self::rrmdir($cache_location);
8✔
653
            return true;
8✔
654
        }
655

UNCOV
656
        return false;
×
657
    }
658

659
    /**
660
     * Remove a directory and everything inside
661
     *
662
     * @param string|false $dirPath
663
     */
664
    public static function rrmdir($dirPath)
8✔
665
    {
666
        if (!\is_dir($dirPath)) {
8✔
UNCOV
667
            throw new InvalidArgumentException("$dirPath must be a directory");
×
668
        }
669
        if (\substr($dirPath, \strlen($dirPath) - 1, 1) != '/') {
8✔
670
            $dirPath .= '/';
8✔
671
        }
672
        $files = \glob($dirPath . '*', GLOB_MARK);
8✔
673
        foreach ($files as $file) {
8✔
674
            if (\is_dir($file)) {
×
UNCOV
675
                self::rrmdir($file);
×
676
            } else {
UNCOV
677
                \unlink($file);
×
678
            }
679
        }
680
        \rmdir($dirPath);
8✔
681
    }
682

683
    /**
684
     * @return CacheExtension\Extension
685
     */
UNCOV
686
    private function _get_cache_extension()
×
687
    {
688
        $key_generator = new Cache\KeyGenerator();
×
689
        $cache_provider = new Cache\WPObjectCacheAdapter($this);
×
690
        $cache_lifetime = \apply_filters('timber/cache/extension/lifetime', 0);
×
691
        $cache_strategy = new CacheExtension\CacheStrategy\GenerationalCacheStrategy(
×
692
            $cache_provider,
×
693
            $key_generator,
×
694
            $cache_lifetime
×
695
        );
×
UNCOV
696
        $cache_extension = new CacheExtension\Extension($cache_strategy);
×
697

UNCOV
698
        return $cache_extension;
×
699
    }
700

701
    /**
702
     * @param string $key
703
     * @param string $group
704
     * @param string $cache_mode
705
     * @return bool
706
     */
707
    public function get_cache($key, $group = self::CACHEGROUP, $cache_mode = self::CACHE_USE_DEFAULT)
22✔
708
    {
709
        $cache_mode = $this->_get_cache_mode($cache_mode);
22✔
710
        $value = false;
22✔
711
        $trans_key = \substr($group . '_' . $key, 0, self::TRANS_KEY_LEN);
22✔
712

713
        /**
714
         * Filters the transient key used for caching.
715
         *
716
         * @api
717
         * @since 2.1.0
718
         * @example
719
         * ```
720
         * add_filter( 'timber/cache/transient_key', function( $trans_key, $key, $group, $cache_mode ) {
721
         *     return $trans_key . '_my_suffix';
722
         * }, 10, 4 );
723
         * ```
724
         *
725
         * @param string $trans_key The transient key.
726
         * @param string $key The cache key.
727
         * @param string $group The cache group.
728
         * @param string $cache_mode The cache mode.
729
         */
730
        $trans_key = \apply_filters('timber/cache/transient_key', $trans_key, $key, $group, $cache_mode);
22✔
731

732
        if (self::CACHE_TRANSIENT === $cache_mode) {
22✔
733
            $value = \get_transient($trans_key);
17✔
734
        } elseif (self::CACHE_SITE_TRANSIENT === $cache_mode) {
5✔
735
            $value = \get_site_transient($trans_key);
1✔
736
        } elseif (self::CACHE_OBJECT === $cache_mode && $this->is_object_cache()) {
4✔
737
            $value = \wp_cache_get($key, $group);
3✔
738
        }
739

740
        return $value;
22✔
741
    }
742

743
    /**
744
     * @param string $key
745
     * @param string|boolean $value
746
     * @param string $group
747
     * @param integer $expires
748
     * @param string $cache_mode
749
     * @return string|boolean
750
     */
751
    public function set_cache($key, $value, $group = self::CACHEGROUP, $expires = 0, $cache_mode = self::CACHE_USE_DEFAULT)
24✔
752
    {
753
        if ((int) $expires < 1) {
24✔
754
            $expires = 0;
3✔
755
        }
756

757
        $cache_mode = $this->_get_cache_mode($cache_mode);
24✔
758
        $trans_key = \substr($group . '_' . $key, 0, self::TRANS_KEY_LEN);
24✔
759

760
        /**
761
         * Filters the transient key used for caching.
762
         *
763
         * @api
764
         * @since 2.1.0
765
         * @example
766
         * ```
767
         * add_filter( 'timber/cache/transient_key', function( $trans_key, $key, $group, $cache_mode ) {
768
         *     return $trans_key . '_my_suffix';
769
         * }, 10, 4 );
770
         * ```
771
         *
772
         * @param string $trans_key The transient key.
773
         * @param string $key The cache key.
774
         * @param string $group The cache group.
775
         * @param string $cache_mode The cache mode.
776
         */
777
        $trans_key = \apply_filters('timber/cache/transient_key', $trans_key, $key, $group, $cache_mode);
24✔
778

779
        if (self::CACHE_TRANSIENT === $cache_mode) {
24✔
780
            \set_transient($trans_key, $value, $expires);
19✔
781
        } elseif (self::CACHE_SITE_TRANSIENT === $cache_mode) {
5✔
782
            \set_site_transient($trans_key, $value, $expires);
1✔
783
        } elseif (self::CACHE_OBJECT === $cache_mode && $this->is_object_cache()) {
4✔
784
            \wp_cache_set($key, $value, $group, $expires);
3✔
785
        }
786

787
        return $value;
24✔
788
    }
789

790
    /**
791
     * @param string $cache_mode
792
     * @return string
793
     */
794
    private function _get_cache_mode($cache_mode)
27✔
795
    {
796
        if (empty($cache_mode) || self::CACHE_USE_DEFAULT === $cache_mode) {
27✔
797
            $cache_mode = $this->cache_mode;
23✔
798
        }
799

800
        // Fallback if self::$cache_mode did not get a valid value
801
        if (!\in_array($cache_mode, self::$cache_modes)) {
27✔
UNCOV
802
            $cache_mode = self::CACHE_OBJECT;
×
803
        }
804

805
        return $cache_mode;
27✔
806
    }
807

808
    /**
809
     * Checks whether WordPress object cache is activated.
810
     *
811
     * @since 2.0.0
812
     * @return bool
813
     */
814
    protected function is_object_cache()
3✔
815
    {
816
        return isset($GLOBALS['wp_object_cache']) && \is_object($GLOBALS['wp_object_cache']);
3✔
817
    }
818
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc