Customise the CLinkPager

By default the CLinkPager Widget produces the following HTML:


Go to page: <ul id="yw0" class="yiiPager">

<li class="first hidden"><a href="/search/results.html">&lt;&lt; First</a></li>

<li class="previous hidden"><a href="/search/results.html">&lt; Previous</a></li>

<li class="page selected"><a href="/search/results.html">1</a></li>

<li class="page"><a href="/search/results.html?page=2">2</a></li>

I want to customize the HTML to be output as follows:


<a class="next-previous serif" href="/search/results.html" title="Go to Previous Page of Results">&lt; Previous</a>

<ul>

<li><a class="pagination-current" href="/search/results.html" title="Page 1 of Results">1</a></li>

<li><a href="/search/results.html" title="Page 2 of Results">2</a></li>

</ul>

<a class="next-previous serif" href="/search/results.html" title="Go to Next Page of Results">&lt; Next</a>

How do I do this?

Make a new class (Ej: MyLinkPager) that sublcass CLinkPager andoverride the render() method. If you see the actual implementation you will see that is simple to override.

Aniway you can see here: CLinkPager

Don’t forgot to import it in /config/main.php

en el import, somethig like that:




'import'=>array(

   'application.models.*',

   'application.components.*',

   'ext.MyLinkPager'

   // ohter imports

),



Later you can usa the same as CLinkPager, but where you usually put CLinkPager now you must put MyLinkPager

There isn’t an easier way of doing this? For example in the arguments list?

You can tune CLinkPager in many ways… check again the link.

But actually just some thing can be tuned…

For wath you want the best bet is to subclass…

No, with arguments you can override only css classes and tests, but you have different HTML structure. But it is really easy to extend standard pager - just look it’s code in framework folder (yii\framework\web\widgets\pagers\CLinkPager.php). Possibly you will need to define only createPageButton() method in your subclass.

I have no idea how to override the methods, or create a subclass. Can someone provide a sample solution please?

Create a class in protected/extensions

File name: MyLinkPager.php

To declare the class use




class MyLinkPager extends CLinkPager {

     //.... your methods


     public function render(){

          // here you override the method making your own implementation

    }

}



Then you import you new class in cpnfig/main.php




'import'=>array(

   'application.models.*',

   'application.components.*',

   'ext.MyLinkPager'

   // ohter imports

),



And then, in places where are actually using CLinkPager, you must use MyLinkPager

Thats all…

I did as you have advised above, and then I modified the page where the pager is displayed:


<?php $this->widget('MyLinkPager',array('pages'=>$pages)); ?>

But I get error message: require(MyLinkPager.php) [<a href=‘function.require’>function.require</a>]: failed to open stream: No such file or directory

did you import it?

what version are you using?

you can try too:

<?php $this->widget(‘ext.MyLinkPager’,array(‘pages’=>$pages)); ?>

Yeh I did import it. I’m using v1.0

I tried your suggestion above and that seems to have worked…

Does anyone know what defines “hidden” pages? I’m trying to override the createPageButton() method and I’m having some difficulty as it is displaying the “first” and “last” page buttons.

If I remember this correctly "hidden" is used for "previous" and "next" links when there is no previous (we are on the first page now) or no next page (we are on last).

I did following implementation where "previous" and "next" shown with text (no link) in this case:




class ExtLinkPager extends CLinkPager

{

    protected function createPageButton($label,$page,$class,$hidden,$selected)

    {

        if($hidden || $selected)

            $class.=' '.($hidden ? self::CSS_HIDDEN_PAGE : self::CSS_SELECTED_PAGE);


        if (!$hidden) return '<li class="'.$class.'">'.CHtml::link($label,$this->createPageUrl($page)).'</li>';


        return '<li class="'.$class.'">'.'</li>';

    }


}



Cheers seb, that helped a bit but I still cannot get this to output exactly how I want it to. Can anyone advise?

Why? With custom CLinkPager::createPageButton() implementation you should get desired <ul> structure.

You maybe need to override also CLinkPager::run() method to output custom widget header / footer:




    public function run()

    {

        // SET CUSTOM $this->header and $this->footer here

        $this->header = '...'; 

        $this->footer = '...';


        return CLinkPager::run();

    }



Yeh I’ve tried customizing the CLinkPager, but as you can see the output I wish to acheive involves more than one change, for example the previous/next buttons are hyperlinks and not LI elements. I think I need several IF statements and return values but can’t seem to figure out how to do this.

It seems I was wrong in my previous post with suggesting to set header / footer. I have looked one more to your code and it seems you need to override CLinkPager::run() and CLinkPager::createPageButtons() method. Here is changed default implementation with my comments (I not tested this, it is only an idea):




    public function run()

    {

        if($this->nextPageLabel===null)

            $this->nextPageLabel=Yii::t('yii','Next &gt;');

        if($this->prevPageLabel===null)

            $this->prevPageLabel=Yii::t('yii','&lt; Previous');

        if($this->firstPageLabel===null)

            $this->firstPageLabel=Yii::t('yii','&lt;&lt; First');

        if($this->lastPageLabel===null)

            $this->lastPageLabel=Yii::t('yii','Last &gt;&gt;');

        if($this->header===null)

            $this->header=Yii::t('yii','Go to page: ');


        $buttons=$this->createPageButtons();


        if(empty($buttons))

            return;


        $this->registerClientScript();


        $htmlOptions=$this->htmlOptions;

        if(!isset($htmlOptions['id']))

            $htmlOptions['id']=$this->getId();

        if(!isset($htmlOptions['class']))

            $htmlOptions['class']='yiiPager';

        echo $this->header;


        list($beginPage,$endPage)=$this->getPageRange();

        $currentPage=$this->getCurrentPage(false);

        if(($prevPage=$currentPage-1)<0)

            $prevPage=0;

        if(($nextPage=$currentPage-1)<0)

            $nextPage=0;


        // previous page link

        echo CHtml::link($this->prevPageLabel, $this->createPageUrl($prevPage)),array(/*add other link options here*/));

        echo CHtml::tag('ul',$htmlOptions,implode("\n",$buttons));

        //next page link

        echo CHtml::link($this->prevPageLabel, $this->createPageUrl($nextPage)),array(/*add other link options here*/));

        echo $this->footer;

    }




 protected function createPageButtons()

    {

        if(($pageCount=$this->getPageCount())<=1)

            return array();


        list($beginPage,$endPage)=$this->getPageRange();

        $currentPage=$this->getCurrentPage(false); // currentPage is calculated in getPageRange()

        $buttons=array();


        // Commented out first / prev page (these added in run())

        // first page

        //$buttons[]=$this->createPageButton($this->firstPageLabel,0,self::CSS_FIRST_PAGE,$beginPage<=0,false);

        // prev page

        //if(($page=$currentPage-1)<0)

        //    $page=0;

        //$buttons[]=$this->createPageButton($this->prevPageLabel, $page,self::CSS_PREVIOUS_PAGE,$currentPage<=0,false);


        // internal pages

        for($i=$beginPage;$i<=$endPage;++$i)

            $buttons[]=$this->createPageButton($i+1,$i,self::CSS_INTERNAL_PAGE,false,$i==$currentPage);


        // Commented out next/last page (these added in run()) 

        // next page

        //if(($page=$currentPage+1)>=$pageCount-1)

        //    $page=$pageCount-1;

        //$buttons[]=$this->createPageButton($this->nextPageLabel,$page, self::CSS_NEXT_PAGE,$currentPage>=$pageCount-1,false);

        // last page

        //$buttons[]=$this->createPageButton($this->lastPageLabel,$pageCount-1,self::CSS_LAST_PAGE,$endPage>=$pageCount-1,false);


        return $buttons;

    }



How come you moved that bit of code from the createPageButtons() function to the run() function?

I’ve managed to get it half working actually, the only thing that doesn’t seem to be working is the “next” button - it goes backwards instead of forwards. Can you have a look at this? Thanks.

EDIT: I got it working. Thanks!

The CLinkPager inserts the array key into its generated URLs:

/results.html?location[0]=UK&location[1]=US&yt11_x=51&yt11_y=10&yt11=submit&page=3

How can I disable that, so it generates the URL as normal (without the array key):

/results.html?location[]=UK&location[]=US&yt11_x=51&yt11_y=10&yt11=submit&page=3

Anyone able to help regarding the previous post?

Hello,

Thanks to this post I’ve managed to customize my pager.

What I wanted is to display first and last links and to put the page number also on the first page, that by default it leaves it do nothing, I mean, if you want to go to the first page the url is controller/list, but I wanted it to be controller/list/page/1.

So this is what I’ve done:

Created two extensions for CLinkPager and for CPagination and I have made a copy of the pager.css for myself.

Copy framework/web/widgets/pagers/pager.css to your folder for css files, and then change the following that hides the first and last links.




/**

 * Hide first and last buttons by default.

 */

ul.yiiPager .first,

ul.yiiPager .last

{

	/* display:none; */

}



MyLinkPager




<?php

class MyLinkPager extends CLinkPager {


  // Add my custom pager css where I remove the hidden property from the first and the last item.

  public function __construct() {

    $this->cssFile = Yii::app()->request->baseUrl.'/css/pager.css';

  }

  

  /**

	 * Creates the page buttons.

	 * @return array a list of page buttons (in HTML code).

	 */

	protected function createPageButtons()

	{

		if(($pageCount=$this->getPageCount())<=1)

			return array();


		list($beginPage,$endPage)=$this->getPageRange();

		$currentPage=$this->getCurrentPage(false); // currentPage is calculated in getPageRange()

		$buttons=array();


		// first page

		$buttons[]=$this->createPageButton($this->firstPageLabel,0,self::CSS_FIRST_PAGE,false,false);


		// prev page

		if(($page=$currentPage-1)<0)

			$page=0;

		$buttons[]=$this->createPageButton($this->prevPageLabel,$page,self::CSS_PREVIOUS_PAGE,$currentPage<=0,false);


		// internal pages

		for($i=$beginPage;$i<=$endPage;++$i)

			$buttons[]=$this->createPageButton($i+1,$i,self::CSS_INTERNAL_PAGE,false,$i==$currentPage);


		// next page

		if(($page=$currentPage+1)>=$pageCount-1)

			$page=$pageCount-1;

		$buttons[]=$this->createPageButton($this->nextPageLabel,$page,self::CSS_NEXT_PAGE,$currentPage>=$pageCount-1,false);


		// last page

		$buttons[]=$this->createPageButton($this->lastPageLabel,$pageCount-1,self::CSS_LAST_PAGE,$endPage>=$pageCount-1,false);


		return $buttons;

	}


  /**

	 * Creates the default pagination.

	 * This is called by {@link getPages} when the pagination is not set before.

	 * @return CPagination the default pagination instance.

	 */

	protected function createPages()

	{

		return new MyPagination;

	}


}

?>



MyPagination




<?php

class MyPagination extends CPagination {

  

  /**

	 * Creates the URL suitable for pagination.

	 * This method is mainly called by pagers when creating URLs used to

	 * perform pagination. The default implementation is to call

	 * the controller's createUrl method with the page information.

	 * You may override this method if your URL scheme is not the same as

	 * the one supported by the controller's createUrl method.

	 * @param CController the controller that will create the actual URL

	 * @param integer the page that the URL should point to. This is a zero-based index.

	 * @return string the created URL

	 */

	public function createPageUrl($controller,$page)

	{

		$params=$this->params===null ? $_GET : $this->params;

    // All of the pages get the page number parameter now, even if it's page one

    $params[$this->pageVar]=$page+1;

		return $controller->createUrl($this->route,$params);

	}

}

?>



Then loaded both in my config by loading all the app. extensions:




// autoloading model and component classes

'import'=>array(

  'application.models.*',

  'application.components.*',

  'application.helpers.*',

  'application.extensions.*', ### <-- added this for loading extensions ###

),



Then I went and modified my list.php view to use the new pager:




<?php $this->widget('MyLinkPager',array('pages'=>$pages)); ?>



And then I went to my controller actionList and made the pagination use my new pagination class:




$pages=new MyPagination($count);



Hope this helps someone, if you got any trouble you can contact me and maybe I can help!