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

timber / timber / 5690345099

pending completion
5690345099

push

github

nlemoine
Refactor file models: update phpdoc

3917 of 4424 relevant lines covered (88.54%)

58.39 hits per line

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

93.1
/src/ExternalImage.php
1
<?php
2

3
namespace Timber;
4

5
/**
6
 * Class ExternalImage
7
 *
8
 * The `Timber\ExternalImage` class represents an image that is not part of the WordPress content (Attachment).
9
 * Instead, it’s an image that can be either a path (relative/absolute) on the same server, or a URL (either from the
10
 * same or from a different website). When you use a URL of an image on a different website, Timber will load it into
11
 * your WordPress installation once and then load it from there.
12
 *
13
 * @api
14
 * @example
15
 * ```php
16
 * $context = Timber::context();
17
 *
18
 * // Lets say you have an external image that you want to use in your theme
19
 *
20
 * $context['cover_image'] = Timber::get_external_image($url);
21
 *
22
 * Timber::render('single.twig', $context);
23
 * ```
24
 *
25
 * ```twig
26
 * <article>
27
 *   <img src="{{ cover_image.src }}" class="cover-image" />
28
 *   <h1 class="headline">{{ post.title }}</h1>
29
 *   <div class="body">
30
 *     {{ post.content }}
31
 *   </div>
32
 * </article>
33
 * ```
34
 *
35
 * ```html
36
 * <article>
37
 *   <img src="http://example.org/wp-content/uploads/2015/06/nevermind.jpg" class="cover-image" />
38
 *   <h1 class="headline">Now you've done it!</h1>
39
 *   <div class="body">
40
 *     Whatever whatever
41
 *   </div>
42
 * </article>
43
 * ```
44
 */
45
class ExternalImage implements ImageInterface
46
{
47
    /**
48
     * Alt text.
49
     *
50
     * @api
51
     * @var string
52
     */
53
    protected string $alt_text;
54

55
    /**
56
     * Alt text.
57
     *
58
     * @api
59
     * @var string
60
     */
61
    protected string $caption;
62

63
    /**
64
     * Representation.
65
     *
66
     * @var string What does this class represent in WordPress terms?
67
     */
68
    public static $representation = 'image';
69

70
    /**
71
     * File location.
72
     *
73
     * @api
74
     * @var string The absolute path to the attachmend file in the filesystem
75
     *             (Example: `/var/www/htdocs/wp-content/themes/my-theme/images/`)
76
     */
77
    protected string $file_loc;
78

79
    /**
80
     * File extension.
81
     *
82
     * @api
83
     * @since 2.0.0
84
     * @var string A file extension.
85
     */
86
    protected string $file_extension;
87

88
    /**
89
     * Absolute URL.
90
     *
91
     * @var string The absolute URL to the attachment.
92
     */
93
    public $abs_url;
94

95
    /**
96
     * Size.
97
     *
98
     * @var integer|null
99
     */
100
    protected ?int $size;
101

102
    /**
103
     * File types.
104
     *
105
     * @var array An array of supported relative file types.
106
     */
107
    private $image_file_types = [
108
        'jpg',
109
        'jpeg',
110
        'png',
111
        'svg',
112
        'bmp',
113
        'ico',
114
        'gif',
115
        'tiff',
116
        'pdf',
117
    ];
118

119
    /**
120
     * Image dimensions.
121
     *
122
     * @internal
123
     * @var ImageDimensions|null stores Image Dimensions in a structured way.
124
     */
125
    protected ?ImageDimensions $image_dimensions;
126

127
    final protected function __construct()
128
    {
129
    }
15✔
130

131
    /**
132
     * Inits the ExternalImage object.
133
     *
134
     * @internal
135
     * @param $url string URL or path to load the image from.
136
     * @param $args array An array of arguments for the image.
137
     */
138
    public static function build($url, array $args = []): ?ExternalImage
139
    {
140
        if (!\is_string($url) || \is_numeric($url)) {
16✔
141
            return null;
1✔
142
        }
143

144
        $args = \wp_parse_args($args, [
15✔
145
            'alt' => '',
15✔
146
        ]);
15✔
147

148
        $external_image = new static();
15✔
149

150
        if (!empty($args['alt'])) {
15✔
151
            $external_image->alt_text = (string) $args['alt'];
1✔
152
        }
153

154
        if (!empty($args['caption'])) {
15✔
155
            $external_image->caption = (string) $args['caption'];
1✔
156
        }
157

158
        if (\str_contains($url, '://')) {
15✔
159
            // Assume URL.
160
            $external_image->init_with_url($url);
2✔
161

162
            return $external_image;
2✔
163
        } elseif (\str_contains($url, ABSPATH)) {
13✔
164
            // Assume absolute path.
165
            $external_image->init_with_file_path($url);
12✔
166

167
            return $external_image;
12✔
168
        } else {
169
            // Check for image file types.
170
            foreach ($external_image->image_file_types as $type) {
1✔
171
                // Assume a relative path.
172
                if (\str_contains(\strtolower($url), $type)) {
1✔
173
                    $external_image->init_with_relative_path($url);
1✔
174

175
                    return $external_image;
1✔
176
                }
177
            }
178
        }
179

180
        return null;
×
181
    }
182

183
    /**
184
     * Gets the source URL for the image.
185
     *
186
     * @api
187
     * @example
188
     * ```twig
189
     * <img src="{{ post.thumbnail.src }}">
190
     * <img src="{{ post.thumbnail.src('medium') }}">
191
     * ```
192
     * ```html
193
     * <img src="http://example.org/wp-content/uploads/2015/08/pic.jpg" />
194
     * <img src="http://example.org/wp-content/uploads/2015/08/pic-800-600.jpg">
195
     * ```
196
     *
197
     * @param string $size Ignored. For compatibility with Timber\Image.
198
     *
199
     * @return string The src URL for the image.
200
     */
201
    public function src($size = 'full'): string
202
    {
203
        return URLHelper::maybe_secure_url($this->abs_url);
7✔
204
    }
205

206
    /**
207
     * Gets the relative path to the file.
208
     *
209
     * @api
210
     * @example
211
     * ```twig
212
     * <img src="{{ image.path }}" />
213
     * ```
214
     * ```html
215
     * <img src="/wp-content/uploads/2015/08/pic.jpg" />
216
     * ```
217
     *
218
     * @return string The relative path to the image file.
219
     */
220
    public function path(): string
221
    {
222
        return URLHelper::get_rel_path($this->file_loc());
1✔
223
    }
224

225
    /**
226
     * Gets the absolute path to the image.
227
     *
228
     * @api
229
     *
230
     * @return string
231
     */
232
    public function file_loc(): string
233
    {
234
        if (isset($this->file_loc)) {
3✔
235
            return $this->file_loc;
3✔
236
        }
237
        return '';
×
238
    }
239

240
    /**
241
     * Gets filesize in a human-readable format.
242
     *
243
     * This can be useful if you want to display the human-readable filesize for a file. It’s
244
     * easier to read «16 KB» than «16555 bytes» or «1 MB» than «1048576 bytes».
245
     *
246
     * @api
247
     * @since 2.0.0
248
     * @example
249
     * Use filesize information in a link that downloads a file:
250
     *
251
     * ```twig
252
     * <a class="download" href="{{ attachment.src }}" download="{{ attachment.title }}">
253
     *     <span class="download-title">{{ attachment.title }}</span>
254
     *     <span class="download-info">(Download, {{ attachment.size }})</span>
255
     * </a>
256
     * ```
257
     *
258
     * @return null|int Filsize or null if the filesize couldn't be determined.
259
     */
260
    public function size(): ?int
261
    {
262
        if (isset($this->size)) {
1✔
263
            return $this->size;
×
264
        }
265

266
        /**
267
         * Filesize wasn't found in the metadata, so we'll try to get it from the file itself.
268
         *
269
         * We could have used `wp_filesize()` here, but it returns 0 when the file doesn't exist. Which is a perfectly valid filesize
270
         * and prevents us from telling the difference between a file that doesn't exist and a file that has a filesize of 0.
271
         *
272
         * @see https://developer.wordpress.org/reference/functions/wp_filesize/
273
         */
274
        $size = \filesize($this->file_loc());
1✔
275
        return $this->size = $size === false ? null : (int) $size;
1✔
276
    }
277

278
    /**
279
     * Gets the src for an attachment.
280
     *
281
     * @api
282
     *
283
     * @return string The src of the attachment.
284
     */
285
    public function __toString(): string
286
    {
287
        return $this->src();
1✔
288
    }
289

290
    /**
291
     * Gets the extension of the attached file.
292
     *
293
     * @api
294
     * @since 2.0.0
295
     * @example
296
     *
297
     * Use extension information in a link that downloads a file:
298
     *
299
     * ```twig
300
     * <a class="download" href="{{ attachment.src }}" download="{{ attachment.title }}">
301
     *     <span class="download-title">{{ attachment.title }}</span>
302
     *     <span class="download-info">
303
     *         (Download {{ attachment.extension|upper }}, {{ attachment.size }})
304
     *     </span>
305
     * </a>
306
     * ```
307
     *
308
     * @return string|null An uppercase extension string.
309
     */
310
    public function extension(): ?string
311
    {
312
        if (isset($this->file_extension)) {
1✔
313
            return $this->file_extension;
×
314
        }
315
        return $this->file_extension = \pathinfo($this->file_loc(), PATHINFO_EXTENSION);
1✔
316
    }
317

318
    /**
319
     * Gets the width of the image in pixels.
320
     *
321
     * @api
322
     * @example
323
     * ```twig
324
     * <img src="{{ image.src }}" width="{{ image.width }}" />
325
     * ```
326
     * ```html
327
     * <img src="http://example.org/wp-content/uploads/2015/08/pic.jpg" width="1600" />
328
     * ```
329
     *
330
     * @return int|null The width of the image in pixels. Null if the width can’t be read, e.g. because the file doesn’t
331
     *                  exist.
332
     */
333
    public function width(): ?int
334
    {
335
        return $this->image_dimensions->width();
4✔
336
    }
337

338
    /**
339
     * Gets the height of the image in pixels.
340
     *
341
     * @api
342
     * @example
343
     * ```twig
344
     * <img src="{{ image.src }}" height="{{ image.height }}" />
345
     * ```
346
     * ```html
347
     * <img src="http://example.org/wp-content/uploads/2015/08/pic.jpg" height="900" />
348
     * ```
349
     *
350
     * @return int|null The height of the image in pixels. Null if the height can’t be read, e.g. because the file
351
     *                  doesn’t exist.
352
     */
353
    public function height(): ?int
354
    {
355
        return $this->image_dimensions->height();
4✔
356
    }
357

358
    /**
359
     * Gets the aspect ratio of the image.
360
     *
361
     * @api
362
     * @example
363
     * ```twig
364
     * {% if post.thumbnail.aspect < 1 %}
365
     *     {# handle vertical image #}
366
     *     <img src="{{ post.thumbnail.src|resize(300, 500) }}" alt="A basketball player" />
367
     * {% else %}
368
     *     <img src="{{ post.thumbnail.src|resize(500) }}" alt="A sumo wrestler" />
369
     * {% endif %}
370
     * ```
371
     *
372
     * @return float The aspect ratio of the image.
373
     */
374
    public function aspect()
375
    {
376
        return $this->image_dimensions->aspect();
4✔
377
    }
378

379
    /**
380
     * Sets the relative alt text of the image.
381
     *
382
     * @param string $alt Alt text for the image.
383
     */
384
    public function set_alt(string $alt)
385
    {
386
        $this->alt_text = $alt;
1✔
387
    }
388

389
    /**
390
     * Sets the relative alt text of the image.
391
     *
392
     * @param string $caption Caption text for the image
393
     */
394
    public function set_caption(string $caption)
395
    {
396
        $this->caption = $caption;
1✔
397
    }
398

399
    /**
400
     * Inits the object with an absolute path.
401
     *
402
     * @internal
403
     *
404
     * @param string $file_path An absolute path to a file.
405
     */
406
    protected function init_with_file_path($file_path)
407
    {
408
        $url = URLHelper::file_system_to_url($file_path);
12✔
409

410
        $this->abs_url = $url;
12✔
411
        $this->file_loc = $file_path;
12✔
412
        $this->image_dimensions = new ImageDimensions($file_path);
12✔
413
    }
414

415
    /**
416
     * Inits the object with a relative path.
417
     *
418
     * @internal
419
     *
420
     * @param string $relative_path A relative path to a file.
421
     */
422
    protected function init_with_relative_path($relative_path)
423
    {
424
        $file_path = URLHelper::get_full_path($relative_path);
1✔
425

426
        $this->abs_url = \home_url($relative_path);
1✔
427
        $this->file_loc = $file_path;
1✔
428
        $this->image_dimensions = new ImageDimensions($file_path);
1✔
429
    }
430

431
    /**
432
     * Inits the object with an URL.
433
     *
434
     * @internal
435
     *
436
     * @param string $url An URL on the same host.
437
     */
438
    protected function init_with_url($url)
439
    {
440
        if (!URLHelper::is_local($url)) {
2✔
441
            $url = ImageHelper::sideload_image($url);
1✔
442
        }
443

444
        $this->abs_url = $url;
2✔
445

446
        if (URLHelper::is_local($url)) {
2✔
447
            $this->file_loc = URLHelper::remove_double_slashes(
2✔
448
                ABSPATH . URLHelper::get_rel_url($url)
2✔
449
            );
2✔
450
            $this->image_dimensions = new ImageDimensions($this->file_loc);
2✔
451
        }
452
    }
453

454
    /**
455
     * Gets the alt text for an image.
456
     *
457
     * For better accessibility, you should always add an alt attribute to your images, even if it’s
458
     * empty.
459
     *
460
     * @api
461
     * @example
462
     * ```twig
463
     * <img src="{{ image.src }}" alt="{{ image.alt }}" />
464
     * ```
465
     * ```html
466
     * <img
467
     *     src="http://example.org/wp-content/uploads/2015/08/pic.jpg"
468
     *     alt="You should always add alt texts to your images for better accessibility"
469
     * />
470
     * ```
471
     *
472
     * @return string Alt text stored in WordPress.
473
     */
474
    public function alt(): string
475
    {
476
        return $this->alt_text;
1✔
477
    }
478

479
    public function caption(): string
480
    {
481
        return $this->caption;
1✔
482
    }
483
}
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