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

timber / timber / 5690593717

pending completion
5690593717

Pull #1617

github

web-flow
Merge f587ceffa into b563d274e
Pull Request #1617: 2.x

4433 of 4433 new or added lines in 57 files covered. (100.0%)

3931 of 4433 relevant lines covered (88.68%)

58.28 hits per line

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

99.27
/src/Pagination.php
1
<?php
2

3
namespace Timber;
4

5
use WP_Query;
6

7
/**
8
 * Class Pagination
9
 *
10
 * @api
11
 */
12
class Pagination
13
{
14
    public $current;
15

16
    public $total;
17

18
    public $pages;
19

20
    public $next;
21

22
    public $prev;
23

24
    /**
25
     * Pagination constructor.
26
     *
27
     * @api
28
     *
29
     * @param array           $prefs
30
     * @param WP_Query|null  $wp_query
31
     */
32
    public function __construct($prefs = [], $wp_query = null)
33
    {
34
        $this->init($prefs, $wp_query);
39✔
35
    }
36

37
    /**
38
     * Get pagination.
39
     *
40
     * @api
41
     * @param array   $prefs
42
     * @return array mixed
43
     */
44
    public static function get_pagination($prefs = [])
45
    {
46
        $pagination = new self($prefs);
16✔
47
        $pagination = \get_object_vars($pagination);
16✔
48
        return $pagination;
16✔
49
    }
50

51
    protected function init($prefs = [], $wp_query = null)
52
    {
53
        if (!$wp_query) {
39✔
54
            global $wp_query;
55
        }
56

57
        // use the current page from the provided query if available; else fall back to the global
58
        $paged = $wp_query->query_vars['paged'] ?? \get_query_var('paged');
39✔
59

60
        global $wp_rewrite;
61
        $args = [];
39✔
62
        // calculate the total number of pages based on found posts and posts per page
63
        $ppp = $wp_query->query_vars['posts_per_page'] ?? 10;
39✔
64

65
        $args['total'] = \ceil($wp_query->found_posts / $ppp);
39✔
66
        if ($wp_rewrite->using_permalinks()) {
39✔
67
            $url = \explode('?', \get_pagenum_link(0, false));
36✔
68
            if (isset($url[1])) {
36✔
69
                $query = [];
15✔
70
                \wp_parse_str($url[1], $query);
15✔
71
                $args['add_args'] = $query;
15✔
72
            }
73
            $args['format'] = $wp_rewrite->pagination_base . '/%#%';
36✔
74
            $args['base'] = \trailingslashit($url[0]) . '%_%';
36✔
75
        } else {
76
            $big = 999999999;
3✔
77
            $pagination_link = \get_pagenum_link($big, false);
3✔
78
            $args['base'] = \str_replace('paged=' . $big, '', $pagination_link);
3✔
79
            $args['format'] = '?paged=%#%';
3✔
80
        }
81

82
        $args['type'] = 'array';
39✔
83
        $args['current'] = \max(1, $paged);
39✔
84
        $args['mid_size'] = \max(9 - $args['current'], 3);
39✔
85
        if (\is_int($prefs)) {
39✔
86
            $args['mid_size'] = $prefs - 2;
1✔
87
        } else {
88
            $args = \array_merge($args, $prefs);
38✔
89
        }
90
        $this->current = $args['current'];
39✔
91
        $this->total = $args['total'];
39✔
92
        $this->pages = self::paginate_links($args);
39✔
93
        if ($this->total <= \count($this->pages)) {
39✔
94
            // decrement current so that it matches up with the 0 based index used by the pages array
95
            $current = $this->current - 1;
33✔
96
        } else {
97
            // $data['current'] can't be used b/c there are more than 10 pages and we are condensing with dots
98
            foreach ($this->pages as $key => $page) {
6✔
99
                if (!empty($page['current'])) {
5✔
100
                    $current = $key;
5✔
101
                    break;
5✔
102
                }
103
            }
104
        }
105

106
        // set next and prev using pages array generated by paginate links
107
        if (isset($current) && isset($this->pages[$current + 1]) && isset($this->pages[$current + 1]['link'])) {
39✔
108
            $this->next = [
36✔
109
                'link' => $this->pages[$current + 1]['link'],
36✔
110
                'class' => 'page-numbers next',
36✔
111
            ];
36✔
112
        }
113
        if (isset($current) && isset($this->pages[$current - 1]) && isset($this->pages[$current - 1]['link'])) {
39✔
114
            $this->prev = [
16✔
115
                'link' => $this->pages[$current - 1]['link'],
16✔
116
                'class' => 'page-numbers prev',
16✔
117
            ];
16✔
118
        }
119
        if ($paged < 2) {
39✔
120
            $this->prev = '';
23✔
121
        }
122
        if ($this->total === (float) 0) {
39✔
123
            $this->next = '';
×
124
        }
125
    }
126

127
    /**
128
     *
129
     *
130
     * @param array  $args
131
     * @return array
132
     */
133
    public static function paginate_links($args = [])
134
    {
135
        $defaults = [
39✔
136
            'base' => '%_%',
39✔
137
            // http://example.com/all_posts.php%_% : %_% is replaced by format (below)
138
            'format' => '?page=%#%',
39✔
139
            // ?page=%#% : %#% is replaced by the page number
140
            'total' => 1,
39✔
141
            'current' => 0,
39✔
142
            'show_all' => false,
39✔
143
            'prev_next' => false,
39✔
144
            'prev_text' => \__('&laquo; Previous'),
39✔
145
            'next_text' => \__('Next &raquo;'),
39✔
146
            'start_size' => -1,
39✔
147
            'end_size' => 1,
39✔
148
            'mid_size' => 2,
39✔
149
            'type' => 'array',
39✔
150
            'add_args' => [],
39✔
151
            // array of query args to add
152
            'add_fragment' => '',
39✔
153
        ];
39✔
154
        $args = \wp_parse_args($args, $defaults);
39✔
155

156
        $args = self::sanitize_args($args);
39✔
157

158
        // Who knows what else people pass in $args
159
        $args['total'] = \intval((int) $args['total']);
39✔
160
        if ($args['total'] < 2) {
39✔
161
            return [];
1✔
162
        }
163
        $args['current'] = (int) $args['current'];
38✔
164
        $args['end_size'] = 0 <= (int) $args['end_size'] ? (int) $args['end_size'] : 1; // Out of bounds?  Make it the default.
38✔
165
        $args['start_size'] = 0 <= (int) $args['start_size'] ? (int) $args['start_size'] : $args['end_size']; // Default to end_size for backwards compat
38✔
166
        $args['mid_size'] = 0 <= (int) $args['mid_size'] ? (int) $args['mid_size'] : 2;
38✔
167
        $args['add_args'] = \is_array($args['add_args']) ? $args['add_args'] : false;
38✔
168
        $page_links = [];
38✔
169
        $dots = true;
38✔
170
        for ($n = 1; $n <= $args['total']; $n++) {
38✔
171
            $n_display = \number_format_i18n($n);
38✔
172
            if ($n == $args['current']) {
38✔
173
                $page_links[] = [
38✔
174
                    'class' => 'page-number page-numbers current',
38✔
175
                    'title' => $n_display,
38✔
176
                    'text' => $n_display,
38✔
177
                    'name' => $n_display,
38✔
178
                    'current' => true,
38✔
179
                ];
38✔
180
                $dots = true;
38✔
181
            } else {
182
                if (
183
                    $args['show_all']
38✔
184
                    || (
185
                        $n <= (int) $args['start_size']
38✔
186
                        || (
38✔
187
                            $args['current']
38✔
188
                            && $n >= (int) $args['current'] - (int) $args['mid_size']
38✔
189
                            && $n <= (int) $args['current'] + (int) $args['mid_size']
38✔
190
                        )
38✔
191
                        || $n > (int) $args['total'] - (int) $args['end_size']
38✔
192
                    )
193
                ) {
194
                    $link = \str_replace('%_%', 1 == $n ? '' : $args['format'], $args['base']);
38✔
195
                    $link = \str_replace('%#%', $n, $link);
38✔
196

197
                    // we first follow the user trailing slash configuration
198
                    $link = URLHelper::user_trailingslashit($link);
38✔
199

200
                    // then we add all required querystring parameters
201
                    if ($args['add_args']) {
38✔
202
                        $link = \add_query_arg($args['add_args'], $link);
17✔
203
                    }
204

205
                    // last, we add fragment if needed
206
                    $link .= $args['add_fragment'];
38✔
207

208
                    $link = \apply_filters('paginate_links', $link);
38✔
209

210
                    $page_links[] = [
38✔
211
                        'class' => 'page-number page-numbers',
38✔
212
                        'link' => \esc_url($link),
38✔
213
                        'title' => $n_display,
38✔
214
                        'name' => $n_display,
38✔
215
                        'current' => $args['current'] == $n,
38✔
216
                    ];
38✔
217
                    $dots = true;
38✔
218
                } elseif ($dots && !$args['show_all']) {
5✔
219
                    $page_links[] = [
5✔
220
                        'class' => 'dots',
5✔
221
                        'title' => \__('&hellip;'),
5✔
222
                    ];
5✔
223
                    $dots = false;
5✔
224
                }
225
            }
226
        }
227

228
        return $page_links;
38✔
229
    }
230

231
    protected static function sanitize_url_params($add_args)
232
    {
233
        foreach ($add_args as $key => $value) {
39✔
234
            $add_args[$key] = \urlencode_deep($value);
17✔
235
        }
236
        return $add_args;
39✔
237
    }
238

239
    protected static function sanitize_args($args)
240
    {
241
        $format_args = [];
39✔
242

243
        $format = \explode('?', \str_replace('%_%', $args['format'], $args['base']));
39✔
244
        $format_query = isset($format[1]) ? $format[1] : '';
39✔
245

246
        \wp_parse_str($format_query, $format_args);
39✔
247

248
        // Remove the format argument from the array of query arguments, to avoid overwriting custom format.
249
        foreach ($format_args as $format_arg => $format_arg_value) {
39✔
250
            unset($args['add_args'][\urlencode_deep($format_arg)]);
5✔
251
        }
252

253
        $url_parts = \explode('?', $args['base']);
39✔
254

255
        if (isset($url_parts[1])) {
39✔
256
            // Find the query args of the requested URL.
257
            $url_query_args = [];
3✔
258
            \wp_parse_str($url_parts[1], $url_query_args);
3✔
259

260
            $args['add_args'] = \array_merge($args['add_args'], \urlencode_deep($url_query_args));
3✔
261
            $args['base'] = $url_parts[0] . '%_%';
3✔
262
        }
263

264
        if (isset($args['add_args'])) {
39✔
265
            $args['add_args'] = self::sanitize_url_params($args['add_args']);
39✔
266
        }
267
        return $args;
39✔
268
    }
269
}
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