Support

Account

Home Forums ACF PRO Admin Area: Repeater Pagination

Solving

Admin Area: Repeater Pagination

  • Hello everyone,

    I am using the Repeater functionality to list images and some meta-data associated with them. The problem is, some posts have 500-600 images (crazy, I know!) but the client wants to have all of them listed on the post page for a couple of reasons.

    So, unfortunately, there is no workaround for the huge number of repeater items associated with some posts.

    Is there any way I could add pagination, in the admin area, for the ACF box? Loading hundred of images with their data takes forever and sometimes the browsers crashes or doesn’t display the page at all.

    Ideally, I would like to show ~50 items and then browse through the rest ajax-style or even with a page reload, it doesn’t matter.

    Any advice on how I could do that? Is there any filter / action that I could use to limit the number of repeater items shown?

    Thanks!

  • UPDATE:

    I managed to implement a very crude version of what I want to achieve, in case someone else needs it or wants to expand on it.

    I hardcoded the file advanced-custom-fields-pro/pro/fields/repeater.php, adding something like

    if($i < $lmin) continue;
    if($i > $lmax) continue;

    around line ~300, in the foreach( $field[‘value’] as $i => $row ) loop.

    $lmin and $lmax are URL parameters.

    Below the repeater listing I added “pagination” links

    <a href="URL[+]&lmin=0&lmax=50>See results 0-50</a>
    <a href="URL[+]&lmin=51&lmax=100>See results 51-100</a>
    ...

    I’ll keep looking into ACF’s beautifully written code to see if I can do this more elegantly, maybe without a page refresh.

    The bad thing is that these edits will be overwritten if the plugin is upgraded, so if someone can suggest a way to do this without meddling with the plugin code, that would be great.

    Some kind of hook like pre_get_posts for $field[‘value’] would be really useful.

  • Hi @atreidex

    Have you tried to re-save the repeater with your code? Looking at your code, I believe it will delete the entries that are not showing up on the current page.

    You can also do it by using the acf/prepare_field hook to remove certain values from the list, but it will delete the hidden entries when you update the post/page.

    If you want, you can open a new ticket to submit a feature request here: https://support.advancedcustomfields.com/new-ticket.

    Thanks!

  • Hi James,

    Thanks for the heads up – indeed, saving the post will erase all repeater fields, except for the ones shown.

    I’ll open a new ticket, maybe there’s an easier way to do this.

  • My variant page-nav plugin:

    Create folder xakplag and file xakplag.php

    <?php
    
    /**
     * @package Xakplag
     */
    /*
    Plugin Name: Xakplag
    Plugin URI:
    Description: Xakplag
    Version: 0.1.0
    Author:
    Author URI: https://xakplant.ru/
    License: GPLv2 or later
    Text Domain: xakplag
    */
    use JasonGrimes\Paginator;
    
    define( 'XAKPAG_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    
    require_once XAKPAG_PLUGIN_DIR . 'Paginator.php';
    
    $xakpag_count;
    
    function add_repeater_query_var(){
        global $wp;
        $wp->add_query_var('program-course-abroad-settings');
    }
    /* Rewrite rules albums pagination */
    function add_repeter_rewrite_rule() {
    
    // page=program-course-abroad-settings - change
        add_rewrite_rule('^/page/([0-9]+)/?$', '/wp-admin/admin.php?page=program-course-abroad-settings&page=$matches[1]', 'top');
    }
    add_filter('init', 'add_repeater_query_var');
    add_action('init', 'add_repeter_rewrite_rule');
    add_action('init', 'xakpag_query_page');
    function xakpag_query_page(){
    // change
        if($_GET['page'] == 'program-course-abroad-settings' && !$_GET['xp']){
    
            function prepare($field){
    
                $field['value'] = array_slice($field['value'], 0, 30);
    
                return $field;
            }
    // Your field name
            add_filter('acf/prepare_field/name=get_program_course_abroad_settings', 'prepare');
    
        } elseif ($_GET['page'] == 'program-course-abroad-settings' && $_GET['xp']){
    
            function prepare($field){
    
                global $xakpag_count;
    
                $xakpag_count = count($field['value']);
    
                $offset = intval($_GET['xp']);
    
                $offset = ($offset - 1) * 30;
    
                $field['value'] = array_slice($field['value'], $offset, 30);
    
                return $field;
            }
    
    // Chande field name
    
            add_filter('acf/prepare_field/name=get_program_course_abroad_settings', 'prepare');
    
        }
    }
    
    add_action('acf/render_fields', 'xakpag_print_nav', 30);
    function xakpag_print_nav($post){
    
        global $xakpag_count;
    
        $totalItems = $xakpag_count;
    
        $itemsPerPage = 30;
        $currentPage = getCurrentPage();
    
    // Your url pattern
        $urlPattern = 'https://expertno1.com/wp-admin/admin.php?page=program-course-abroad-settings&xp=(:num)';
    
        $paginator = new Paginator($totalItems, $itemsPerPage, $currentPage, $urlPattern);
    
        $screen = get_current_screen();
        if($screen->id == 'nastrojki-programm_page_program-course-abroad-settings'){
            ?>
    
                <div class="xakpag-pagination" style="display: flex">
    
    <?php echo $paginator->toHtml(); ?>
    
                    <style>
                        .active a {
                            font-weight: 900;
                        }
                    </style>
                </div>
    
            <?php
        }
    
    }
    function getCurrentPage(){
        if($_GET['xp']){
            return intval($_GET['xp']);
        } else {
            return 1;
        }
    }
    
    function gerCoutRepeater($repeter){
        if( have_rows($repeter) ):
            $i = 0;
            while( have_rows($repeter) ): the_row();
                if( get_sub_field($repeter) ) $i++;
            endwhile;
            $tCount = $i;
        endif;
    
        return $tCount;
    }
    
    

    create file Paginator.php

    
    <?php
    
    namespace JasonGrimes;
    
    class Paginator
    {
        const NUM_PLACEHOLDER = '(:num)';
    
        protected $totalItems;
        protected $numPages;
        protected $itemsPerPage;
        protected $currentPage;
        protected $urlPattern;
        protected $maxPagesToShow = 10;
        protected $previousText = 'Previous';
        protected $nextText = 'Next';
    
        /**
         * @param int $totalItems The total number of items.
         * @param int $itemsPerPage The number of items per page.
         * @param int $currentPage The current page number.
         * @param string $urlPattern A URL for each page, with (:num) as a placeholder for the page number. Ex. '/foo/page/(:num)'
         */
        public function __construct($totalItems, $itemsPerPage, $currentPage, $urlPattern = '')
        {
            $this->totalItems = $totalItems;
            $this->itemsPerPage = $itemsPerPage;
            $this->currentPage = $currentPage;
            $this->urlPattern = $urlPattern;
    
            $this->updateNumPages();
        }
    
        protected function updateNumPages()
        {
            $this->numPages = ($this->itemsPerPage == 0 ? 0 : (int) ceil($this->totalItems/$this->itemsPerPage));
        }
    
        /**
         * @param int $maxPagesToShow
         * @throws \InvalidArgumentException if $maxPagesToShow is less than 3.
         */
        public function setMaxPagesToShow($maxPagesToShow)
        {
            if ($maxPagesToShow < 3) {
                throw new \InvalidArgumentException('maxPagesToShow cannot be less than 3.');
            }
            $this->maxPagesToShow = $maxPagesToShow;
        }
    
        /**
         * @return int
         */
        public function getMaxPagesToShow()
        {
            return $this->maxPagesToShow;
        }
    
        /**
         * @param int $currentPage
         */
        public function setCurrentPage($currentPage)
        {
            $this->currentPage = $currentPage;
        }
    
        /**
         * @return int
         */
        public function getCurrentPage()
        {
            return $this->currentPage;
        }
    
        /**
         * @param int $itemsPerPage
         */
        public function setItemsPerPage($itemsPerPage)
        {
            $this->itemsPerPage = $itemsPerPage;
            $this->updateNumPages();
        }
    
        /**
         * @return int
         */
        public function getItemsPerPage()
        {
            return $this->itemsPerPage;
        }
    
        /**
         * @param int $totalItems
         */
        public function setTotalItems($totalItems)
        {
            $this->totalItems = $totalItems;
            $this->updateNumPages();
        }
    
        /**
         * @return int
         */
        public function getTotalItems()
        {
            return $this->totalItems;
        }
    
        /**
         * @return int
         */
        public function getNumPages()
        {
            return $this->numPages;
        }
    
        /**
         * @param string $urlPattern
         */
        public function setUrlPattern($urlPattern)
        {
            $this->urlPattern = $urlPattern;
        }
    
        /**
         * @return string
         */
        public function getUrlPattern()
        {
            return $this->urlPattern;
        }
    
        /**
         * @param int $pageNum
         * @return string
         */
        public function getPageUrl($pageNum)
        {
            return str_replace(self::NUM_PLACEHOLDER, $pageNum, $this->urlPattern);
        }
    
        public function getNextPage()
        {
            if ($this->currentPage < $this->numPages) {
                return $this->currentPage + 1;
            }
    
            return null;
        }
    
        public function getPrevPage()
        {
            if ($this->currentPage > 1) {
                return $this->currentPage - 1;
            }
    
            return null;
        }
    
        public function getNextUrl()
        {
            if (!$this->getNextPage()) {
                return null;
            }
    
            return $this->getPageUrl($this->getNextPage());
        }
    
        /**
         * @return string|null
         */
        public function getPrevUrl()
        {
            if (!$this->getPrevPage()) {
                return null;
            }
    
            return $this->getPageUrl($this->getPrevPage());
        }
    
        /**
         * Get an array of paginated page data.
         *
         * Example:
         * array(
         *     array ('num' => 1,     'url' => '/example/page/1',  'isCurrent' => false),
         *     array ('num' => '...', 'url' => NULL,               'isCurrent' => false),
         *     array ('num' => 3,     'url' => '/example/page/3',  'isCurrent' => false),
         *     array ('num' => 4,     'url' => '/example/page/4',  'isCurrent' => true ),
         *     array ('num' => 5,     'url' => '/example/page/5',  'isCurrent' => false),
         *     array ('num' => '...', 'url' => NULL,               'isCurrent' => false),
         *     array ('num' => 10,    'url' => '/example/page/10', 'isCurrent' => false),
         * )
         *
         * @return array
         */
        public function getPages()
        {
            $pages = array();
    
            if ($this->numPages <= 1) {
                return array();
            }
    
            if ($this->numPages <= $this->maxPagesToShow) {
                for ($i = 1; $i <= $this->numPages; $i++) {
                    $pages[] = $this->createPage($i, $i == $this->currentPage);
                }
            } else {
    
                // Determine the sliding range, centered around the current page.
                $numAdjacents = (int) floor(($this->maxPagesToShow - 3) / 2);
    
                if ($this->currentPage + $numAdjacents > $this->numPages) {
                    $slidingStart = $this->numPages - $this->maxPagesToShow + 2;
                } else {
                    $slidingStart = $this->currentPage - $numAdjacents;
                }
                if ($slidingStart < 2) $slidingStart = 2;
    
                $slidingEnd = $slidingStart + $this->maxPagesToShow - 3;
                if ($slidingEnd >= $this->numPages) $slidingEnd = $this->numPages - 1;
    
                // Build the list of pages.
                $pages[] = $this->createPage(1, $this->currentPage == 1);
                if ($slidingStart > 2) {
                    $pages[] = $this->createPageEllipsis();
                }
                for ($i = $slidingStart; $i <= $slidingEnd; $i++) {
                    $pages[] = $this->createPage($i, $i == $this->currentPage);
                }
                if ($slidingEnd < $this->numPages - 1) {
                    $pages[] = $this->createPageEllipsis();
                }
                $pages[] = $this->createPage($this->numPages, $this->currentPage == $this->numPages);
            }
    
            return $pages;
        }
    
        /**
         * Create a page data structure.
         *
         * @param int $pageNum
         * @param bool $isCurrent
         * @return Array
         */
        protected function createPage($pageNum, $isCurrent = false)
        {
            return array(
                'num' => $pageNum,
                'url' => $this->getPageUrl($pageNum),
                'isCurrent' => $isCurrent,
            );
        }
    
        /**
         * @return array
         */
        protected function createPageEllipsis()
        {
            return array(
                'num' => '...',
                'url' => null,
                'isCurrent' => false,
            );
        }
    
        /**
         * Render an HTML pagination control.
         *
         * @return string
         */
        public function toHtml()
        {
            if ($this->numPages <= 1) {
                return '';
            }
    
            $html = '<ul class="pagination" style="display: flex">';
            if ($this->getPrevUrl()) {
                $html .= '<li><a style="    text-decoration: #444;
        display: block;
        padding: 8px 12px;
        color: #fff;
        background: #0085ba;
    " href="' . htmlspecialchars($this->getPrevUrl()) . '">&laquo; '. $this->previousText .'</a></li>';
            }
    
            foreach ($this->getPages() as $page) {
                if ($page['url']) {
                    $html .= '<li' . ($page['isCurrent'] ? ' class="active"' : '') . '><a style="    text-decoration: #444;
        display: block;
        padding: 8px 12px;
        color: #fff;
        background: #0085ba;
    " href="' . htmlspecialchars($page['url']) . '">' . htmlspecialchars($page['num']) . '</a></li>';
                } else {
                    $html .= '<li class="disabled"><span style="    text-decoration: #444;
        display: block;
        padding: 8px 12px;
        color: #fff;
        background: #0085ba;
    ">' . htmlspecialchars($page['num']) . '</span></li>';
                }
            }
    
            if ($this->getNextUrl()) {
                $html .= '<li><a style="    text-decoration: #444;
        display: block;
        padding: 8px 12px;
        color: #fff;
        background: #0085ba;
    " href="' . htmlspecialchars($this->getNextUrl()) . '">'. $this->nextText .' &raquo;</a></li>';
            }
            $html .= '</ul>';
    
            return $html;
        }
    
        public function __toString()
        {
            return $this->toHtml();
        }
    
        public function getCurrentPageFirstItem()
        {
            $first = ($this->currentPage - 1) * $this->itemsPerPage + 1;
    
            if ($first > $this->totalItems) {
                return null;
            }
    
            return $first;
        }
    
        public function getCurrentPageLastItem()
        {
            $first = $this->getCurrentPageFirstItem();
            if ($first === null) {
                return null;
            }
    
            $last = $first + $this->itemsPerPage - 1;
            if ($last > $this->totalItems) {
                return $this->totalItems;
            }
    
            return $last;
        }
    
        public function setPreviousText($text)
        {
            $this->previousText = $text;
            return $this;
        }
    
        public function setNextText($text)
        {
            $this->nextText = $text;
            return $this;
        }
    }
    

    activate plugin.

    come to my site xakplant.ru

  • Dear xakplant
    Your code is does not working.
    Please, can you give a normal version of this plugin?

Viewing 6 posts - 1 through 6 (of 6 total)

The topic ‘Admin Area: Repeater Pagination’ is closed to new replies.