• 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

79.17
/src/Attachment.php
1
<?php
2

3
namespace Timber;
4

5
use Timber\Factory\PostFactory;
6

7
/**
8
 * Class Attachment
9
 *
10
 * Objects of this class represent WordPress attachments. This is the basis that `Timber\Image`
11
 * objects build upon.
12
 *
13
 * @api
14
 * @since 2.0.0
15
 */
16
class Attachment extends Post
17
{
18
    /**
19
     * Representation.
20
     *
21
     * @var string What does this class represent in WordPress terms?
22
     */
23
    public static $representation = 'attachment';
24

25
    /**
26
     * File.
27
     *
28
     * @api
29
     * @var string
30
     */
31
    protected string $file;
32

33
    /**
34
     * File location.
35
     *
36
     * @api
37
     * @var string The absolute path to the attachmend file in the filesystem
38
     *             (Example: `/var/www/htdocs/wp-content/uploads/2015/08/my-pic.jpg`)
39
     */
40
    protected string $file_loc;
41

42
    /**
43
     * File extension.
44
     *
45
     * @api
46
     * @since 2.0.0
47
     * @var string A file extension.
48
     */
49
    protected string $file_extension;
50

51
    /**
52
     * Absolute URL.
53
     *
54
     * @var string The absolute URL to the attachment.
55
     */
56
    public $abs_url;
57

58
    /**
59
     * Attachment metadata.
60
     *
61
     * @var array Attachment metadata.
62
     */
63
    protected array $metadata;
64

65
    /**
66
     * Size.
67
     *
68
     * @var integer|null
69
     */
70
    protected ?int $size = null;
71

72
    /**
73
     * Gets the src for an attachment.
74
     *
75
     * @api
76
     *
77
     * @return string The src of the attachment.
78
     */
79
    public function __toString(): string
3✔
80
    {
81
        return $this->src();
3✔
82
    }
83

84
    /**
85
     * Gets the link to an attachment.
86
     *
87
     * This returns a link to an attachment’s page, but not the link to the image src itself.
88
     *
89
     * @api
90
     * @example
91
     * ```twig
92
     * <a href="{{ image.link }}"><img src="{{ image.src }} "></a>
93
     * ```
94
     * ```html
95
     * <a href="https://example.org/my-cool-picture">
96
     *     <img src="https://example.org/wp-content/uploads/2015/whatever.jpg"/>
97
     * </a>
98
     * ```
99
     *
100
     * @return string The URL of the attachment.
101
     */
102
    public function link()
1✔
103
    {
104
        if ($this->abs_url) {
1✔
105
            return $this->abs_url;
×
106
        }
107

108
        return \get_permalink($this->ID);
1✔
109
    }
110

111
    /**
112
     * Gets the relative path to an attachment.
113
     *
114
     * @api
115
     * @example
116
     * ```twig
117
     * <img src="{{ image.path }}" />
118
     * ```
119
     * ```html
120
     * <img src="/wp-content/uploads/2015/08/pic.jpg" />
121
     * ```
122
     *
123
     * @return string The relative path to an attachment.
124
     */
125
    public function path(): string
1✔
126
    {
127
        $src = $this->src();
1✔
128
        $src = URLHelper::url_to_file_system($src);
1✔
129

130
        return URLHelper::get_rel_path($src);
1✔
131
    }
132

133
    /**
134
     * Gets the relative path to the uploads folder of an attachment.
135
     *
136
     * @api
137
     *
138
     * @return string
139
     */
140
    public function file(): string
3✔
141
    {
142
        return $this->file ?? ($this->file = (string) \get_post_meta($this->ID, '_wp_attached_file', true));
3✔
143
    }
144

145
    /**
146
     * Gets the absolute path to an attachment.
147
     *
148
     * @api
149
     *
150
     * @return string
151
     */
152
    public function file_loc(): string
67✔
153
    {
154
        return $this->file_loc ?? ($this->file_loc = (string) \get_attached_file($this->ID));
67✔
155
    }
156

157
    /**
158
     * Gets the source URL for an attachment.
159
     *
160
     * @api
161
     * @example
162
     * ```twig
163
     * <a href="{{ get_attachment(post.meta('job_pdf')).src }}" download>
164
     * ```
165
     * ```html
166
     * <a href="https://example.org/wp-content/uploads/2015/08/job-ad-5noe2304i.pdf" download>
167
     * ```
168
     *
169
     * @return string
170
     */
171
    public function src(): string
6✔
172
    {
173
        return (string) \wp_get_attachment_url($this->ID);
6✔
174
    }
175

176
    /**
177
     * Gets the caption of an attachment.
178
     *
179
     * @api
180
     * @since 2.0
181
     * @example
182
     * ```twig
183
     * <figure>
184
     *     <img src="{{ post.thumbnail.src }}">
185
     *
186
     *     {% if post.thumbnail is not empty %}
187
     *         <figcaption>{{ post.thumbnail.caption }}</figcaption
188
     *     {% endif %}
189
     * </figure>
190
     * ```
191
     *
192
     * @return string|null
193
     */
194
    public function caption(): ?string
1✔
195
    {
196
        /**
197
         * Filters the attachment caption.
198
         *
199
         * @since WordPress 4.6.0
200
         * @since 2.0.0
201
         *
202
         * @param string $caption Caption for the given attachment.
203
         * @param int    $post_id Attachment ID.
204
         */
205
        return \apply_filters('wp_get_attachment_caption', $this->post_excerpt, $this->ID);
1✔
206
    }
207

208
    /**
209
     * Gets the raw filesize in bytes.
210
     *
211
     * Use the `size_format` filter to format the raw size into a human readable size («1 MB» instead of «1048576»)
212
     *
213
     * @api
214
     * @since 2.0.0
215
     * @example
216
     * @see https://developer.wordpress.org/reference/functions/size_format/
217
     *
218
     * Use filesize information in a link that downloads a file:
219
     *
220
     * ```twig
221
     * <a class="download" href="{{ attachment.src }}" download="{{ attachment.title }}">
222
     *     <span class="download-title">{{ attachment.title }}</span>
223
     *     <span class="download-info">(Download, {{ attachment.size|size_format }})</span>
224
     * </a>
225
     * ```
226
     *
227
     * @return int|null The raw filesize or null if it could not be read.
228
     */
229
    public function size(): ?int
2✔
230
    {
231
        if (isset($this->size)) {
2✔
232
            return $this->size;
×
233
        }
234

235
        /**
236
         * Since 6.0.0, the filesize is stored in the attachment metadata.
237
         *
238
         * @see https://make.wordpress.org/core/2022/05/02/media-storing-file-size-as-part-of-metadata/
239
         */
240
        $size = $this->metadata('filesize');
2✔
241
        if ($size !== null && \is_numeric($size)) {
2✔
242
            return $this->size = (int) $size;
1✔
243
        }
244

245
        /**
246
         * Filesize wasn't found in the metadata, so we'll try to get it from the file itself.
247
         *
248
         * We could have used `wp_filesize()` here, but it returns 0 when the file doesn't exist. Which is a perfectly valid filesize
249
         * and prevents us from telling the difference between a file that doesn't exist and a file that has a filesize of 0.
250
         *
251
         * @see https://developer.wordpress.org/reference/functions/wp_filesize/
252
         */
253
        $size = \filesize($this->file_loc());
1✔
254
        return $this->size = $size === false ? null : (int) $size;
1✔
255
    }
256

257
    /**
258
     * Gets the extension of the attached file.
259
     *
260
     * @api
261
     * @since 2.0.0
262
     * @example
263
     * Use extension information in a link that downloads a file:
264
     *
265
     * ```twig
266
     * <a class="download" href="{{ attachment.src }}" download="{{ attachment.title }}">
267
     *     <span class="download-title">{{ attachment.title }}</span>
268
     *     <span class="download-info">
269
     *         (Download {{ attachment.extension|upper }}, {{ attachment.size }})
270
     *     </span>
271
     * </a>
272
     * ```
273
     *
274
     * @return string An uppercase extension string.
275
     */
276
    public function extension(): string
1✔
277
    {
278
        return $this->file_extension ?? ($this->file_extension = \pathinfo($this->file(), PATHINFO_EXTENSION));
1✔
279
    }
280

281
    /**
282
     * Gets the parent object.
283
     *
284
     * The parent object of an attachment is a post it is assigned to.
285
     *
286
     * @api
287
     * @example
288
     * ```twig
289
     * This image is assigned to {{ image.parent.title }}
290
     * ```
291
     *
292
     * @return null|Post Parent object as a `Timber\Post`. Returns `false` if no parent
293
     *                            object is defined.
294
     */
295
    public function parent(): ?Post
4✔
296
    {
297
        if (!$this->post_parent) {
4✔
298
            return null;
1✔
299
        }
300

301
        $factory = new PostFactory();
3✔
302

303
        return $factory->from($this->post_parent);
3✔
304
    }
305

306
    /**
307
     * Get a PHP array with pathinfo() info from the file
308
     *
309
     * @deprecated 2.0.0, use Attachment::pathinfo() instead
310
     * @return array
311
     */
312
    public function get_pathinfo()
×
313
    {
314
        Helper::deprecated(
×
315
            "{{ image.get_pathinfo }}",
×
316
            "{{ image.pathinfo }}",
×
317
            '2.0.0'
×
318
        );
×
319
        return PathHelper::pathinfo($this->file());
×
320
    }
321

322
    /**
323
     * Get a PHP array with pathinfo() info from the file
324
     *
325
     * @return array
326
     */
327
    public function pathinfo()
1✔
328
    {
329
        return PathHelper::pathinfo($this->file());
1✔
330
    }
331

332
    /**
333
     * Get attachment metadata the lazy way.
334
     *
335
     * This method is used to retrieve the attachment metadata only when it's needed.
336
     *
337
     * @return array|string|int|null
338
     */
339
    protected function metadata(?string $key = null)
6✔
340
    {
341
        // We haven't retrieved the metadata yet because it's wasn't needed until now.
342
        if (!isset($this->metadata)) {
6✔
343
            // Cache it so we don't have to retrieve it again.
344
            $this->metadata = (array) \wp_get_attachment_metadata($this->ID);
6✔
345
        }
346

347
        if ($key === null) {
6✔
348
            return $this->metadata;
×
349
        }
350

351
        return $this->metadata[$key] ?? null;
6✔
352
    }
353
}
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