├── .editorconfig ├── .gitignore ├── LICENSE.md ├── README.md ├── composer.json └── src ├── LengthAwarePaginator.php ├── Pagi.php ├── PagiFacade.php ├── PagiServiceProvider.php └── resources └── views └── pagination.blade.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.php] 15 | indent_size = 4 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.lock 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Brandon Nifong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pagi 2 | 3 | ![Latest Stable Version](https://img.shields.io/packagist/v/log1x/pagi?style=flat-square) 4 | ![Total Downloads](https://img.shields.io/packagist/dt/log1x/pagi?style=flat-square) 5 | ![Build Status](https://img.shields.io/github/actions/workflow/status/log1x/pagi/compatibility.yml?branch=master&style=flat-square) 6 | 7 | A better WordPress pagination utilizing [Laravel's Pagination](https://laravel.com/docs/master/pagination). 8 | 9 | ## Requirements 10 | 11 | - [Sage](https://github.com/roots/sage) >= 10.0 12 | - [PHP](https://secure.php.net/manual/en/install.php) >= 8.0 13 | - [Composer](https://getcomposer.org/download/) 14 | 15 | ## Installation 16 | 17 | Install via Composer: 18 | 19 | ```bash 20 | $ composer require log1x/pagi 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### Basic Usage 26 | 27 | ```php 28 | use Log1x\Pagi\PagiFacade as Pagi; 29 | 30 | $pagination = Pagi::build(); 31 | 32 | return $pagination->links(); 33 | ``` 34 | 35 | ### Customization 36 | 37 | To customize the view, simply publish it: 38 | 39 | ```bash 40 | $ wp acorn vendor:publish --provider='Log1x\Pagi\PagiServiceProvider' 41 | ``` 42 | 43 | To use the newly generated view: 44 | 45 | ```php 46 | return $pagination->links('components.pagination'); 47 | ``` 48 | 49 | For additional configuration, check out the [Laravel Pagination](https://laravel.com/docs/master/pagination) documentation. 50 | 51 | ## Bug Reports 52 | 53 | If you discover a bug in Pagi, please [open an issue](https://github.com/log1x/pagi/issues). 54 | 55 | ## Contributing 56 | 57 | Contributing whether it be through PRs, reporting an issue, or suggesting an idea is encouraged and appreciated. 58 | 59 | ## License 60 | 61 | Pagi is provided under the [MIT License](https://github.com/log1x/pagi/blob/master/LICENSE.md). 62 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "log1x/pagi", 3 | "type": "package", 4 | "license": "MIT", 5 | "description": "A better WordPress pagination.", 6 | "authors": [ 7 | { 8 | "name": "Brandon Nifong", 9 | "email": "brandon@tendency.me" 10 | } 11 | ], 12 | "keywords": [ 13 | "wordpress", 14 | "sage", 15 | "roots", 16 | "laravel", 17 | "pagination" 18 | ], 19 | "support": { 20 | "issues": "https://github.com/log1x/pagi/issues" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "Log1x\\Pagi\\": "src/" 25 | } 26 | }, 27 | "require": { 28 | "php": "^8.0", 29 | "illuminate/pagination": "^9.0|^10.0|^11.0|^12.0" 30 | }, 31 | "require-dev": { 32 | "squizlabs/php_codesniffer": "^3.5" 33 | }, 34 | "extra": { 35 | "acorn": { 36 | "providers": [ 37 | "Log1x\\Pagi\\PagiServiceProvider" 38 | ], 39 | "aliases": { 40 | "Pagi": "Log1x\\Pagi\\PagiFacade" 41 | } 42 | } 43 | }, 44 | "scripts": { 45 | "lint": [ 46 | "phpcs --ignore=vendor,src/resources --extensions=php --standard=PSR12 ." 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/LengthAwarePaginator.php: -------------------------------------------------------------------------------- 1 | query) > 0) { 41 | return $url . 42 | (Str::contains($url, '?') ? '&' : '?') . 43 | Arr::query($this->query) . 44 | $this->buildFragment(); 45 | } 46 | 47 | return $url; 48 | } 49 | 50 | /** 51 | * Get the URL for the next page. 52 | * 53 | * @return string|null 54 | */ 55 | public function nextPageUrl() 56 | { 57 | global $paged; 58 | 59 | if (is_single()) { 60 | return; 61 | } 62 | 63 | $paged = empty($paged) ? 1 : $paged; 64 | 65 | $nextPage = (int) $paged + 1; 66 | $maxPages = count($this->items); 67 | 68 | if (! $maxPages || $maxPages >= $nextPage) { 69 | return get_pagenum_link($nextPage, false); 70 | } 71 | } 72 | 73 | /** 74 | * Get the URL for the previous page. 75 | * 76 | * @return string|null 77 | */ 78 | public function previousPageUrl() 79 | { 80 | global $paged; 81 | 82 | if (is_single()) { 83 | return; 84 | } 85 | 86 | $nextPage = (int) $paged - 1; 87 | $nextPage = $nextPage < 1 ? 1 : $nextPage; 88 | 89 | return get_pagenum_link($nextPage, false); 90 | } 91 | 92 | /** 93 | * Render the paginator using the given view. 94 | * 95 | * @param string|null $view 96 | * @param array $data 97 | * @return \Illuminate\Contracts\Support\Htmlable 98 | */ 99 | public function links($view = null, $data = []) 100 | { 101 | return $this->render($view, $data); 102 | } 103 | 104 | /** 105 | * Render the paginator using the given view. 106 | * 107 | * @param string|null $view 108 | * @param array $data 109 | * @return \Illuminate\Contracts\Support\Htmlable 110 | */ 111 | public function render($view = null, $data = []) 112 | { 113 | return new HtmlString(static::viewFactory()->make($view ?: static::$defaultView, array_merge($data, [ 114 | 'pagi' => $this, 115 | ]))->render()); 116 | } 117 | 118 | /** 119 | * Get the array of elements to pass to the view. 120 | * 121 | * @return array 122 | */ 123 | public function elements() 124 | { 125 | return parent::elements(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Pagi.php: -------------------------------------------------------------------------------- 1 | query)) { 45 | $this->query = collect( 46 | Arr::get($GLOBALS, 'wp_query')->query_vars ?? [] 47 | )->filter(); 48 | 49 | $this->items = collect()->range(1, Arr::get($GLOBALS, 'wp_query')->found_posts); 50 | } 51 | 52 | if ($this->query->isEmpty()) { 53 | return; 54 | } 55 | 56 | $this->perPage = $this->query->get('posts_per_page', 1); 57 | $this->currentPage = max(1, absint(get_query_var('paged'))); 58 | } 59 | 60 | /** 61 | * Build the WordPress pagination. 62 | * 63 | * @return \Illuminate\Pagination\LengthAwarePaginator 64 | */ 65 | public function build() 66 | { 67 | $this->prepare(); 68 | 69 | return new LengthAwarePaginator( 70 | $this->items, 71 | $this->items->count(), 72 | $this->perPage, 73 | $this->currentPage 74 | ); 75 | } 76 | 77 | /** 78 | * Set the WordPress query. 79 | * 80 | * @param \WP_Query 81 | * @return void 82 | */ 83 | public function setQuery($query) 84 | { 85 | $this->items = collect()->range(1, $query->found_posts); 86 | $this->query = collect( 87 | $query->query_vars ?? [] 88 | )->filter(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/PagiFacade.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__ . '/resources/views', 'pagi'); 18 | 19 | $this->publishes([ 20 | __DIR__ . '/resources/views' => $this->app->resourcePath('views/components'), 21 | ], 'pagi'); 22 | 23 | Paginator::viewFactoryResolver(function () { 24 | return $this->app->make('view'); 25 | }); 26 | } 27 | 28 | /** 29 | * Register any application services. 30 | * 31 | * @return void 32 | */ 33 | public function register() 34 | { 35 | $this->app->singleton('pagi', function () { 36 | return new Pagi(); 37 | }); 38 | 39 | return $this->app->make('pagi'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/resources/views/pagination.blade.php: -------------------------------------------------------------------------------- 1 | @if ($pagi->hasPages()) 2 | 53 | @endif 54 | --------------------------------------------------------------------------------