• 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

96.97
/src/LocationManager.php
1
<?php
2

3
namespace Timber;
4

5
class LocationManager
6
{
7
    /**
8
     * @param bool|string   $caller the calling directory (or false)
9
     * @return array
10
     */
11
    public static function get_locations($caller = false)
427✔
12
    {
13
        //priority: user locations, caller (but not theme), child theme, parent theme, caller, open_basedir
14
        $locs = [];
427✔
15
        $locs = \array_merge_recursive($locs, self::get_locations_user());
427✔
16
        $locs = \array_merge_recursive($locs, self::get_locations_caller($caller, true));
427✔
17
        $locs = \array_merge_recursive($locs, self::get_locations_theme());
427✔
18
        $locs = \array_merge_recursive($locs, self::get_locations_caller($caller));
427✔
19
        $locs = \array_merge_recursive($locs, self::get_locations_open_basedir());
427✔
20
        $locs = \array_map('array_unique', $locs);
427✔
21

22
        //now make sure theres a trailing slash on everything
23
        $locs = \array_map(fn ($loc) => \array_map('trailingslashit', $loc), $locs);
427✔
24

25
        /**
26
         * Filters the filesystem paths to search for Twig templates.
27
         *
28
         * @example
29
         * ```
30
         * add_filter( 'timber/locations', function( $locs ) {
31
         *   $locs = \array_map(function ($loc) {
32
         *      \array_unshift($loc, \dirname(__DIR__) . '/my-custom-dir');
33
         *       return $loc;
34
         *   }, $locs);
35
         *
36
         *     return $locs;
37
         * } );
38
         * ```
39
         *
40
         * @since 0.20.10
41
         *
42
         * @param array $locs An array of filesystem paths to search for Twig templates.
43
         */
44
        $locs = \apply_filters('timber/locations', $locs);
427✔
45

46
        /**
47
         * Filters the filesystem paths to search for Twig templates.
48
         *
49
         * @deprecated 2.0.0, use `timber/locations`
50
         */
51
        $locs = \apply_filters_deprecated('timber_locations', [$locs], '2.0.0', 'timber/locations');
427✔
52

53
        return $locs;
427✔
54
    }
55

56
    /**
57
     * @return array
58
     */
59
    protected static function get_locations_theme()
427✔
60
    {
61
        $theme_locs = [];
427✔
62
        $theme_dirs = LocationManager::get_locations_theme_dir();
427✔
63
        $roots = [\get_stylesheet_directory(), \get_template_directory()];
427✔
64
        $roots = \array_map('realpath', $roots);
427✔
65
        $roots = \array_unique($roots);
427✔
66
        foreach ($roots as $root) {
427✔
67
            if (!\is_dir($root)) {
427✔
68
                continue;
4✔
69
            }
70

71
            $theme_locs[Loader::MAIN_NAMESPACE][] = $root;
423✔
72
            $root = \trailingslashit($root);
423✔
73
            foreach ($theme_dirs as $namespace => $dirnames) {
423✔
74
                $dirnames = self::convert_to_array($dirnames);
423✔
75
                \array_map(function ($dirname) use ($root, $namespace, &$theme_locs) {
423✔
76
                    $tloc = \realpath($root . $dirname);
423✔
77
                    if (\is_dir($tloc)) {
423✔
78
                        $theme_locs[$namespace][] = $tloc;
16✔
79
                    }
80
                }, $dirnames);
423✔
81
            }
82
        }
83

84
        return $theme_locs;
427✔
85
    }
86

87
    /**
88
     * Get calling script file.
89
     * @api
90
     * @param int     $offset
91
     * @return string|null
92
     */
93
    public static function get_calling_script_file($offset = 0)
86✔
94
    {
95
        $callers = [];
86✔
96
        $backtrace = \debug_backtrace();
86✔
97
        foreach ($backtrace as $trace) {
86✔
98
            if (\array_key_exists('file', $trace) && $trace['file'] != __FILE__) {
86✔
99
                $callers[] = $trace['file'];
86✔
100
            }
101
        }
102
        $callers = \array_unique($callers);
86✔
103
        $callers = \array_values($callers);
86✔
104
        return $callers[$offset];
86✔
105
    }
106

107
    /**
108
     * Get calling script dir.
109
     * @api
110
     * @return string|null
111
     */
112
    public static function get_calling_script_dir($offset = 0)
85✔
113
    {
114
        $caller = self::get_calling_script_file($offset);
85✔
115
        if (!\is_null($caller)) {
85✔
116
            $pathinfo = PathHelper::pathinfo($caller);
85✔
117
            $dir = $pathinfo['dirname'];
85✔
118
            return $dir;
85✔
119
        }
120

121
        return null;
×
122
    }
123

124
    /**
125
     * returns an array of the directory inside themes that holds twig files
126
     * @return array the names of directories, ie: array('__MAIN__' => ['templates', 'views']);
127
     */
128
    public static function get_locations_theme_dir()
427✔
129
    {
130
        if (\is_string(Timber::$dirname)) {
427✔
131
            return [
416✔
132
                Loader::MAIN_NAMESPACE => [Timber::$dirname],
416✔
133
            ];
416✔
134
        }
135
        return Timber::$dirname;
11✔
136
    }
137

138
    /**
139
     * @deprecated since 2.0.0 Use `add_filter('timber/locations', $locations)` instead.
140
     * @return array
141
     */
142
    protected static function get_locations_user()
427✔
143
    {
144
        $locs = [];
427✔
145
        if (isset(Timber::$locations)) {
427✔
146
            if (\is_string(Timber::$locations)) {
427✔
147
                Timber::$locations = [Timber::$locations];
407✔
148
            }
149
            foreach (Timber::$locations as $tloc => $namespace_or_tloc) {
427✔
150
                if (\is_string($tloc)) {
413✔
151
                    $namespace = $namespace_or_tloc;
6✔
152
                } else {
153
                    $tloc = $namespace_or_tloc;
409✔
154
                    $namespace = null;
409✔
155
                }
156

157
                $tloc = \realpath($tloc);
413✔
158
                if (\is_dir($tloc)) {
413✔
159
                    if (!\is_string($namespace)) {
413✔
160
                        $locs[Loader::MAIN_NAMESPACE][] = $tloc;
409✔
161
                    } else {
162
                        $locs[$namespace][] = $tloc;
6✔
163
                    }
164
                }
165
            }
166
        }
167

168
        return $locs;
427✔
169
    }
170

171
    /**
172
     *
173
     * Converts the variable to an array with the var as the sole element. Ignores if it's already an array
174
     *
175
     * @param mixed $var the variable to test and maybe convert
176
     * @return array
177
     */
178
    protected static function convert_to_array(mixed $var)
423✔
179
    {
180
        if (\is_string($var)) {
423✔
181
            $var = [$var];
6✔
182
        }
183
        return $var;
423✔
184
    }
185

186
    /**
187
     * @param bool|string   $caller the calling directory
188
     * @param bool          $skip_parent whether to skip the parent theme
189
     * @return array
190
     */
191
    protected static function get_locations_caller($caller = false, bool $skip_parent = false)
427✔
192
    {
193
        $locs = [];
427✔
194
        if ($caller && \is_string($caller)) {
427✔
195
            $caller = \realpath($caller);
85✔
196
            $parent_theme = \get_template_directory();
85✔
197
            $parent_slug = \basename((string) $parent_theme);
85✔
198

199
            if ($skip_parent && \str_contains($caller, $parent_slug)) {
85✔
200
                return $locs;
×
201
            }
202

203
            if (\is_dir($caller)) {
85✔
204
                $locs[Loader::MAIN_NAMESPACE][] = $caller;
85✔
205
            }
206
            $caller = \trailingslashit($caller);
85✔
207
            foreach (LocationManager::get_locations_theme_dir() as $namespace => $dirnames) {
85✔
208
                $dirnames = self::convert_to_array($dirnames);
85✔
209
                \array_map(function ($dirname) use ($caller, $namespace, &$locs) {
85✔
210
                    $caller_sub = \realpath($caller . $dirname);
85✔
211
                    if (\is_dir($caller_sub)) {
85✔
212
                        $locs[$namespace][] = $caller_sub;
×
213
                    }
214
                }, $dirnames);
85✔
215
            }
216
        }
217

218
        return $locs;
427✔
219
    }
220

221
    /**
222
     * returns an array of the directory set with "open_basedir"
223
     * see : https://www.php.net/manual/en/ini.core.php#ini.open-basedir
224
     * @return array
225
     */
226
    protected static function get_locations_open_basedir()
427✔
227
    {
228
        $open_basedir = \ini_get('open_basedir');
427✔
229

230
        return [
427✔
231
            Loader::MAIN_NAMESPACE => [
427✔
232
                $open_basedir ? ABSPATH : '/',
427✔
233
            ],
427✔
234
        ];
427✔
235
    }
236
}
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