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

timber / timber / 5690057835

pending completion
5690057835

push

github

nlemoine
Merge branch '2.x' of github.com:timber/timber into 2.x-refactor-file-models

# Conflicts:
#	src/Attachment.php
#	src/ExternalImage.php
#	src/FileSize.php
#	src/URLHelper.php

1134 of 1134 new or added lines in 55 files covered. (100.0%)

3923 of 4430 relevant lines covered (88.56%)

59.08 hits per line

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

94.12
/src/Factory/PostFactory.php
1
<?php
2

3
namespace Timber\Factory;
4

5
use InvalidArgumentException;
6
use Timber\Attachment;
7
use Timber\CoreInterface;
8
use Timber\Helper;
9
use Timber\Image;
10
use Timber\PathHelper;
11
use Timber\Post;
12
use Timber\PostArrayObject;
13

14
use Timber\PostQuery;
15
use WP_Post;
16
use WP_Query;
17

18
/**
19
 * Internal API class for instantiating posts
20
 */
21
class PostFactory
22
{
23
    public function from($params)
24
    {
25
        if (\is_int($params) || \is_string($params) && \is_numeric($params)) {
463✔
26
            return $this->from_id((int) $params);
362✔
27
        }
28

29
        if ($params instanceof WP_Query) {
140✔
30
            return $this->from_wp_query($params);
32✔
31
        }
32

33
        if (\is_object($params)) {
123✔
34
            return $this->from_post_object($params);
88✔
35
        }
36

37
        if ($this->is_numeric_array($params)) {
67✔
38
            return new PostArrayObject(\array_map([$this, 'from'], $params));
20✔
39
        }
40

41
        if (\is_array($params) && !empty($params['ID'])) {
47✔
42
            return $this->from_id($params['ID']);
2✔
43
        }
44

45
        if (\is_array($params)) {
45✔
46
            return $this->from_wp_query(new WP_Query($params));
44✔
47
        }
48

49
        return null;
1✔
50
    }
51

52
    protected function from_id(int $id): ?Post
53
    {
54
        $wp_post = \get_post($id);
364✔
55

56
        if (!$wp_post) {
364✔
57
            return null;
2✔
58
        }
59

60
        return $this->build($wp_post);
363✔
61
    }
62

63
    protected function from_post_object(object $obj): CoreInterface
64
    {
65
        if ($obj instanceof CoreInterface) {
88✔
66
            return $obj;
13✔
67
        }
68

69
        if ($obj instanceof WP_Post) {
77✔
70
            return $this->build($obj);
77✔
71
        }
72

73
        throw new InvalidArgumentException(\sprintf(
×
74
            'Expected an instance of Timber\CoreInterface or WP_Post, got %s',
×
75
            \get_class($obj)
×
76
        ));
×
77
    }
78

79
    protected function from_wp_query(WP_Query $query): iterable
80
    {
81
        return new PostQuery($query);
76✔
82
    }
83

84
    protected function get_post_class(WP_Post $post): string
85
    {
86
        /**
87
         * Pseudo filter that checks whether the non-usable filter was used.
88
         *
89
         * @deprecated 2.0.0, use `timber/post/classmap`
90
         */
91
        if ('deprecated' !== \apply_filters('Timber\PostClassMap', 'deprecated')) {
420✔
92
            Helper::doing_it_wrong(
1✔
93
                'The `Timber\PostClassMap` filter',
1✔
94
                'Use the `timber/post/classmap` filter instead.',
1✔
95
                '2.0.0'
1✔
96
            );
1✔
97
        }
98

99
        /**
100
         * Filters the class(es) used for different post types.
101
         *
102
         * Read more about this in the documentation for [Post Class Maps](https://timber.github.io/docs/v2/guides/class-maps/#the-post-class-map).
103
         *
104
         * The default Post Class Map will contain class names for posts, pages that map to
105
         * `Timber\Post` and a callback that will map attachments to `Timber\Attachment` and
106
         * attachments that are images to `Timber\Image`.
107
         *
108
         * Make sure to merge in your additional classes instead of overwriting the whole Class Map.
109
         *
110
         * @since 2.0.0
111
         * @example
112
         * ```
113
         * use Book;
114
         * use Page;
115
         *
116
         * add_filter( 'timber/post/classmap', function( $classmap ) {
117
         *     $custom_classmap = [
118
         *         'page' => Page::class,
119
         *         'book' => Book::class,
120
         *     ];
121
         *
122
         *     return array_merge( $classmap, $custom_classmap );
123
         * } );
124
         * ```
125
         *
126
         * @param array $classmap The post class(es) to use. An associative array where the key is
127
         *                        the post type and the value the name of the class to use for this
128
         *                        post type or a callback that determines the class to use.
129
         */
130
        $classmap = \apply_filters('timber/post/classmap', [
420✔
131
            'post' => Post::class,
420✔
132
            'page' => Post::class,
420✔
133
            // Apply special logic for attachments.
134
            'attachment' => function (WP_Post $attachment) {
420✔
135
                return $this->is_image($attachment) ? Image::class : Attachment::class;
77✔
136
            },
420✔
137
        ]);
420✔
138

139
        $class = $classmap[$post->post_type] ?? null;
420✔
140

141
        // If class is a callable, call it to get the actual class name
142
        if (\is_callable($class)) {
420✔
143
            $class = $class($post);
82✔
144
        }
145

146
        $class = $class ?? Post::class;
420✔
147

148
        /**
149
         * Filters the post class based on your custom criteria.
150
         *
151
         * Maybe you want to set a custom class based upon how blocks are used?
152
         * This allows you to filter the PHP class, utilizing data from the WP_Post object.
153
         *
154
         * @since 2.0.0
155
         * @example
156
         * ```
157
         * add_filter( 'timber/post/class', function( $class, $post ) {
158
         *     if ( has_blocks($post) ) {
159
         *         return GutenbergPost::class;
160
         *     }
161
         *
162
         *     return $class;
163
         * }, 10, 2 );
164
         * ```
165
         *
166
         * @param string $class The class to use.
167
         * @param WP_Post $post The post object.
168
         */
169
        $class = \apply_filters('timber/post/class', $class, $post);
420✔
170

171
        return $class;
420✔
172
    }
173

174
    protected function is_image(WP_Post $post)
175
    {
176
        $src = \get_attached_file($post->ID);
77✔
177
        $mimes = \wp_get_mime_types();
77✔
178
        // Add mime types that Timber recongizes as images, regardless of config
179
        $mimes['svg'] = 'image/svg+xml';
77✔
180
        $mimes['webp'] = 'image/webp';
77✔
181
        $check = \wp_check_filetype(PathHelper::basename($src), $mimes);
77✔
182

183
        $extensions = \apply_filters('timber/post/image_extensions', [
77✔
184
            'jpg',
77✔
185
            'jpeg',
77✔
186
            'jpe',
77✔
187
            'gif',
77✔
188
            'png',
77✔
189
            'svg',
77✔
190
            'webp',
77✔
191
        ]);
77✔
192

193
        return \in_array($check['ext'], $extensions);
77✔
194
    }
195

196
    protected function build(WP_Post $post): CoreInterface
197
    {
198
        $class = $this->get_post_class($post);
420✔
199

200
        return $class::build($post);
420✔
201
    }
202

203
    protected function is_numeric_array($arr)
204
    {
205
        if (!\is_array($arr)) {
67✔
206
            return false;
1✔
207
        }
208
        foreach (\array_keys($arr) as $k) {
66✔
209
            if (!\is_int($k)) {
66✔
210
                return false;
46✔
211
            }
212
        }
213
        return true;
20✔
214
    }
215
}
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

© 2025 Coveralls, Inc