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

timber / timber / 20695674007

04 Jan 2026 04:14PM UTC coverage: 89.681% (+1.5%) from 88.211%
20695674007

push

travis-ci

nlemoine
test: Fix ancestors post tests

4615 of 5146 relevant lines covered (89.68%)

63.45 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
     * @link https://secure.php.net/manual/en/language.oop5.overloading.php#object.call
191
     * @link https://github.com/twigphp/Twig/issues/2
192
     * @api
193
     *
194
     * @param string $option     The name of the method being called.
195
     * @param array  $arguments Enumerated array containing the parameters passed to the function.
196
     *                          Not used.
197
     *
198
     * @return mixed The value of the option field named `$field` if truthy, `false` otherwise.
199
     */
200
    public function __call($option, $arguments)
1✔
201
    {
202
        return $this->option($option);
1✔
203
    }
204

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

382
        return null;
1✔
383
    }
384

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

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

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

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

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

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