• 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

87.76
/src/Site.php
1
<?php
2

3
namespace Timber;
4

5
use WP_Site;
6

7
/**
8
 * Class Site
9
 *
10
 * `Timber\Site` gives you access to information you need about your site. In Multisite setups, you
11
 * can get info on other sites in your network.
12
 *
13
 * @api
14
 * @example
15
 * ```php
16
 * $other_site_id = 2;
17
 *
18
 * $context = Timber::context( [
19
 *     'other_site' => new Timber\Site( $other_site_id ),
20
 * ] );
21
 *
22
 * Timber::render('index.twig', $context);
23
 * ```
24
 * ```twig
25
 * My site is called {{site.name}}, another site on my network is {{other_site.name}}
26
 * ```
27
 * ```html
28
 * My site is called Jared's blog, another site on my network is Upstatement.com
29
 * ```
30
 */
31
class Site extends Core implements CoreInterface
32
{
33
    /**
34
     * The underlying WordPress Core object.
35
     *
36
     * @since 2.0.0
37
     *
38
     * @var WP_Site|null Will only be filled in multisite environments. Otherwise `null`.
39
     */
40
    protected ?WP_Site $wp_object = null;
41

42
    /**
43
     * @api
44
     * @var string The admin email address set in the WP admin panel
45
     */
46
    public $admin_email;
47

48
    /**
49
     * @api
50
     * @var string
51
     */
52
    public $blogname;
53

54
    /**
55
     * @api
56
     * @var string
57
     */
58
    public $charset;
59

60
    /**
61
     * @api
62
     * @var string
63
     */
64
    public $description;
65

66
    /**
67
     * @api
68
     * @var int the ID of a site in multisite
69
     */
70
    public $id;
71

72
    /**
73
     * @api
74
     * @var string the language setting ex: en-US
75
     */
76
    public $language;
77

78
    /**
79
     * @api
80
     * @var bool true if multisite, false if plain ole' WordPress
81
     */
82
    public $multisite;
83

84
    /**
85
     * @api
86
     * @var string
87
     */
88
    public $name;
89

90
    /**
91
     * @deprecated 2.0.0, use $pingback_url
92
     * @var string for people who like trackback spam
93
     */
94
    public $pingback;
95

96
    /**
97
     * @api
98
     * @var string for people who like trackback spam
99
     */
100
    public $pingback_url;
101

102
    /**
103
     * @api
104
     * @var string
105
     */
106
    public $siteurl;
107

108
    /**
109
     * @api
110
     * @var Theme
111
     */
112
    public $theme;
113

114
    /**
115
     * @api
116
     * @var string
117
     */
118
    public $title;
119

120
    /**
121
     * @api
122
     * @var string
123
     */
124
    public $url;
125

126
    /**
127
     * @api
128
     * @var string
129
     */
130
    public $home_url;
131

132
    /**
133
     * @api
134
     * @var string
135
     */
136
    public $site_url;
137

138
    /**
139
     * @api
140
     * @var string
141
     */
142
    public $rdf;
143

144
    public $rss;
145

146
    public $rss2;
147

148
    public $atom;
149

150
    /**
151
     * Constructs a Timber\Site object
152
     * @api
153
     * @example
154
     * ```php
155
     * //multisite setup
156
     * $site = new Timber\Site(1);
157
     * $site_two = new Timber\Site("My Cool Site");
158
     * //non-multisite
159
     * $site = new Timber\Site();
160
     * ```
161
     * @param string|int $site_name_or_id
162
     */
163
    public function __construct($site_name_or_id = null)
62✔
164
    {
165
        if (\is_multisite()) {
62✔
166
            $blog_id = self::switch_to_blog($site_name_or_id);
5✔
167
            $this->init();
5✔
168
            $this->init_as_multisite($blog_id);
5✔
169
            \restore_current_blog();
5✔
170
        } else {
171
            $this->init();
57✔
172
            $this->init_as_singlesite();
57✔
173
        }
174
    }
175

176
    /**
177
     * Magic method dispatcher for site option fields, for convenience in Twig views.
178
     *
179
     * Called when explicitly invoking non-existent methods on the Site object. This method is not
180
     * meant to be called directly.
181
     *
182
     * @example
183
     * The following example will dynamically dispatch the magic __call() method with an argument
184
     * of "users_can_register" #}
185
     *
186
     * ```twig
187
     * {% if site.users_can_register %}
188
     *   {# Show a notification and link to the register form #}
189
     * {% endif %}
190
     * ```
191
     * @link https://secure.php.net/manual/en/language.oop5.overloading.php#object.call
192
     * @link https://github.com/twigphp/Twig/issues/2
193
     * @api
194
     *
195
     * @param string $option     The name of the method being called.
196
     * @param array  $arguments Enumerated array containing the parameters passed to the function.
197
     *                          Not used.
198
     *
199
     * @return mixed The value of the option field named `$field` if truthy, `false` otherwise.
200
     */
201
    public function __call($option, $arguments)
1✔
202
    {
203
        return $this->option($option);
1✔
204
    }
205

206
    /**
207
     * Gets the underlying WordPress Core object.
208
     *
209
     * @since 2.0.0
210
     *
211
     * @return WP_Site|null Will only return a `WP_Site` object in multisite environments. Otherwise `null`.
212
     */
213
    public function wp_object(): ?WP_Site
2✔
214
    {
215
        return $this->wp_object;
2✔
216
    }
217

218
    /**
219
     * Switches to the blog requested in the request
220
     *
221
     * @param string|integer|null $blog_identifier The name or ID of the blog to switch to. If `null`, the current blog.
222
     * @return integer with the ID of the new blog
223
     */
224
    protected static function switch_to_blog($blog_identifier = null): int
5✔
225
    {
226
        $current_id = \get_current_blog_id();
5✔
227

228
        if ($blog_identifier === null) {
5✔
229
            $blog_identifier = $current_id;
1✔
230
        }
231

232
        $info = \get_blog_details($blog_identifier, false);
5✔
233

234
        if (false === $info) {
5✔
UNCOV
235
            return $current_id;
×
236
        }
237

238
        $blog_identifier = $info->blog_id;
5✔
239

240
        if ((int) $current_id !== (int) $blog_identifier) {
5✔
241
            \switch_to_blog($blog_identifier);
4✔
242
        }
243

244
        return (int) $blog_identifier;
5✔
245
    }
246

247
    /**
248
     * @internal
249
     * @param integer $site_id
250
     */
251
    protected function init_as_multisite($site_id)
5✔
252
    {
253
        $wp_site = \get_blog_details($site_id);
5✔
254
        $this->import($wp_site);
5✔
255
        $this->ID = $wp_site->blog_id;
5✔
256
        $this->id = $this->ID;
5✔
257
        // Site might be false, but $wp_object needs to be null if it can’t be set.
258
        $this->wp_object = $wp_site ?: null;
5✔
259
        $this->name = $this->blogname;
5✔
260
        $this->title = $this->blogname;
5✔
261
        $theme_slug = \get_blog_option($wp_site->blog_id, 'stylesheet');
5✔
262
        $this->theme = new Theme($theme_slug);
5✔
263
        $this->description = \get_blog_option($wp_site->blog_id, 'blogdescription');
5✔
264
        $this->admin_email = \get_blog_option($wp_site->blog_id, 'admin_email');
5✔
265
        $this->multisite = true;
5✔
266
    }
267

268
    /**
269
     * Executed for single-blog sites
270
     * @internal
271
     */
272
    protected function init_as_singlesite()
57✔
273
    {
274
        // No WP_Site object available in single site environments.
275
        $this->wp_object = null;
57✔
276

277
        $this->admin_email = \get_bloginfo('admin_email');
57✔
278
        $this->name = \get_bloginfo('name');
57✔
279
        $this->title = $this->name;
57✔
280
        $this->description = \get_bloginfo('description');
57✔
281
        $this->theme = new Theme();
57✔
282
        $this->multisite = false;
57✔
283
    }
284

285
    /**
286
     * Executed for all types of sites: both multisite and "regular"
287
     * @internal
288
     */
289
    protected function init()
62✔
290
    {
291
        $this->url = \home_url();
62✔
292
        $this->home_url = $this->url;
62✔
293
        $this->site_url = \site_url();
62✔
294
        $this->rdf = \get_bloginfo('rdf_url');
62✔
295
        $this->rss = \get_bloginfo('rss_url');
62✔
296
        $this->rss2 = \get_bloginfo('rss2_url');
62✔
297
        $this->atom = \get_bloginfo('atom_url');
62✔
298
        $this->language = \get_locale();
62✔
299
        $this->charset = \get_bloginfo('charset');
62✔
300
        $this->pingback = $this->pingback_url = \get_bloginfo('pingback_url');
62✔
301
    }
302

303
    /**
304
     * Returns the language attributes that you're looking for
305
     * @return string
306
     */
307
    public function language_attributes()
1✔
308
    {
309
        return \get_language_attributes();
1✔
310
    }
311

312
    /**
313
     * Get the value for a site option.
314
     *
315
     * @api
316
     * @example
317
     * ```twig
318
     * Published on: {{ post.date|date(site.date_format) }}
319
     * ```
320
     *
321
     * @param string $option The name of the option to get the value for.
322
     *
323
     * @return mixed The option value.
324
     */
325
    public function __get($option)
4✔
326
    {
327
        if (!isset($this->$option)) {
4✔
328
            if (\is_multisite()) {
4✔
UNCOV
329
                $this->$option = \get_blog_option($this->ID, $option);
×
330
            } else {
331
                $this->$option = \get_option($option);
4✔
332
            }
333
        }
334

335
        return $this->$option;
4✔
336
    }
337

338
    /**
339
     * Get the value for a site option.
340
     *
341
     * @api
342
     * @example
343
     * ```twig
344
     * Published on: {{ post.date|date(site.option('date_format')) }}
345
     * ```
346
     *
347
     * @param string $option The name of the option to get the value for.
348
     *
349
     * @return mixed The option value.
350
     */
351
    public function option($option)
2✔
352
    {
353
        return $this->__get($option);
2✔
354
    }
355

356
    /**
357
     * Get the value for a site option.
358
     *
359
     * @api
360
     * @deprecated 2.0.0, use `{{ site.option }}` instead
361
     */
362
    public function meta($option)
1✔
363
    {
364
        Helper::deprecated('{{ site.meta() }}', '{{ site.option() }}', '2.0.0');
1✔
365

366
        return $this->__get($option);
1✔
367
    }
368

369
    /**
370
     * @api
371
     * @return null|Image
372
     */
373
    public function icon()
2✔
374
    {
375
        if (\is_multisite()) {
2✔
UNCOV
376
            return $this->icon_multisite($this->ID);
×
377
        }
378
        $iid = \get_option('site_icon');
2✔
379
        if ($iid) {
2✔
380
            return Timber::get_post($iid);
1✔
381
        }
382

383
        return null;
1✔
384
    }
385

UNCOV
386
    protected function icon_multisite($site_id)
×
387
    {
388
        $image = null;
×
389
        $blog_id = self::switch_to_blog($site_id);
×
390
        $iid = \get_blog_option($blog_id, 'site_icon');
×
391
        if ($iid) {
×
UNCOV
392
            $image = Timber::get_post($iid);
×
393
        }
394
        \restore_current_blog();
×
UNCOV
395
        return $image;
×
396
    }
397

398
    /**
399
     * Returns the link to the site's home.
400
     *
401
     * @api
402
     * @example
403
     * ```twig
404
     * <a href="{{ site.link }}" title="Home">
405
     *       <img src="/wp-content/uploads/logo.png" alt="Logo for some stupid thing" />
406
     * </a>
407
     * ```
408
     * ```html
409
     * <a href="https://example.org" title="Home">
410
     *       <img src="/wp-content/uploads/logo.png" alt="Logo for some stupid thing" />
411
     * </a>
412
     * ```
413
     *
414
     * @return string
415
     */
416
    public function link()
2✔
417
    {
418
        return $this->url;
2✔
419
    }
420

421
    /**
422
     * Updates a site option.
423
     *
424
     * @deprecated 2.0.0 Use `update_option()` or `update_blog_option()` instead.
425
     *
426
     * @param string $key   The key of the site option to update.
427
     * @param mixed  $value The new value.
428
     */
429
    public function update($key, $value)
1✔
430
    {
431
        Helper::deprecated('Timber\Site::update()', 'update_option()', '2.0.0');
1✔
432

433
        /**
434
         * Filters a value before it is updated in the site options.
435
         *
436
         * @since 2.0.0
437
         *
438
         * @param mixed        $value   The new value.
439
         * @param string       $key     The option key.
440
         * @param int          $site_id The site ID.
441
         * @param Site $site    The site object.
442
         */
443
        $value = \apply_filters('timber/site/update_option', $value, $key, $this->ID, $this);
1✔
444

445
        /**
446
         * Filters a value before it is updated in the site options.
447
         *
448
         * @deprecated 2.0.0, use `timber/site/update_option`
449
         * @since 0.20.0
450
         */
451
        $value = \apply_filters_deprecated(
1✔
452
            'timber_site_set_meta',
1✔
453
            [$value, $key, $this->ID, $this],
1✔
454
            '2.0.0',
1✔
455
            'timber/site/update_option'
1✔
456
        );
1✔
457

458
        if (\is_multisite()) {
1✔
UNCOV
459
            \update_blog_option($this->ID, $key, $value);
×
460
        } else {
461
            \update_option($key, $value);
1✔
462
        }
463
        $this->$key = $value;
1✔
464
    }
465
}
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