0

I wrote a function in an article override to search a folder for images and create a pagebreak behavior per image in an article. All works fine except for a 404 error being returned for each pagination link.

I determined that the error is caused by Joomla's pagebreak content plugin pagebreak.php where the condition is:

if (StringHelper::strpos($row->text, 'class="system-pagebreak') === false)
    {
        if ($page > 0)
        {
            throw new Exception(JText::_('JERROR_PAGE_NOT_FOUND'), 404);
        }

        return true;
    }

If I comment out the line throw new Exception(JText::_('JERROR_PAGE_NOT_FOUND'), 404); or disable the plugin the process works perfectly. However, being that the file is subject to overwriting on updates, that is not an ideal option.

My code is:

$pagebreak='';
if(preg_match('#\{pagebreakgallery=\"(.*?)\"\}#i', $item->text, $folder)) 
{
    $imagesDir = JPATH_ROOT.'/images/photogallery/'.$folder[1].'/';
    $images = str_replace(JPATH_ROOT, Juri::root(true), glob($imagesDir . '*.{jpg,jpeg,png,gif}', GLOB_BRACE));

    foreach($images as $image) {
      $page_break[] = '<img src="'.$image.'" />';
    }
    $item->text = str_replace($folder[0], '', $item->text);

    $pagenum = 0;
    if($app->input->get('start') != '')
        $pagenum = $app->input->getInt('start');

    $pages = count($page_break);
    if($pages > 0)
    {
        $pagelinks = new JPagination($pages, $pagenum, 1);
        $pagebreak .= $page_break[$pagenum];
        $pagebreak .= '
            <div class="paging">
                <div class="pagecount">' . $pagelinks->getPagesCounter() . '</div>
                <div class="pager">' . $pagelinks->getPagesLinks() . '</div>
            </div>
        ';
    }
}

How can I resolve this error occurrence?

1
  • @mickmackusa Yes $pagebreak is declared before the if() statement which wraps the entire script. I should have included that.
    – Nadal
    Commented Oct 30, 2018 at 18:56

3 Answers 3

2

As suggested before I can agree with the solution of turning off the pagebreak plugin and it will stay turned off in the case of updates too. But if you do not want to use that solution, then:

maybe you would like this solution a little more with which you can delete that Exception thrown in pagebreak.php file, with an override of that file. Many people, even in Joomla extension developers community, do not know that there are relatively easy ways to override, not only template/layout files, but Model, Controller and View files too in Joomla. So that way you could just 'delete' that unneeded Exception object.

The full write-up of how to override Joomla components' views, models, controllers is here: https://docs.joomla.org/How_to_override_the_component_mvc_from_the_Joomla!_core

Hope this can help you.

(I have not checked this override method on plugins though, but according to the override helper plugin developer, it works on plugins' classes too).

1

Disabling the plugin would work - it won't be re-enabled on updates.

But what you're doing is wrong in general. There's a fine line between making layout overrides and hacking them to a point where they no longer should be layouts. For this purpose you should try to make your own component or find a 3rd party component that meets your needs.

To use Pagination class without causing conflicts with current component's links, pass the fourth argument when instantiating the class. This is a prefix to be used for generating links. Use the same prefix when getting input variables.

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;
use Joomla\CMS\Pagination\Pagination;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Uri\Uri;
use Joomla\Filesystem\Folder;

class PlgContentPagebreakgallery extends CMSPlugin
{
    protected $app;

    public function onContentPrepare($context, &$item, &$params, $itemPage = 0)
    {
        if (!preg_match('#\{pagebreakgallery=\"(.*?)\"\}#i', $item->text, $folder))
        {
            // Shortcode not found.
            return true;
        }

        // Remove the shortcode.
        $item->text = str_replace($folder[0], '', $item->text);

        // Check that we are on article view.
        if ($this->app->input->get('option') !== 'com_content' || $this->app->input->get('view') !== 'article')
        {
            return true;
        }

        $imagesDir = '/images/' . $folder[1] . '/';

        try
        {
            $images = Folder::files(JPATH_ROOT . $imagesDir, '(?i:.(jpg|jpeg|png|gif))$');
        }
        catch(\Exception $e)
        {
            // Directory doesn't exist.
            return true;
        }

        if (!$pages = count($images))
        {
            // No images.
            return true;
        }

        // Prefix used for pagination links.
        $prefix = 'pagebreakgallery_';
        $page   = $this->app->input->getInt($prefix . 'limitstart', 0);

        if ($page > $pages - 1 || $page < 0)
        {
            // Image doesn't exist.
            throw new \Exception(Text::_('JERROR_PAGE_NOT_FOUND'), 404);
        }

        $item->text = '<img src="' . Uri::root(true) . $imagesDir . $images[$page] . '" />';
        $pagination = new Pagination($pages, $page, 1, $prefix);

        $item->text .= '
            <div class="paging">
                <div class="pagecount">' . $pagination->getPagesCounter() . '</div>
                <div class="pager">' . $pagination->getPagesLinks() . '</div>
            </div>';
    }
}
5
  • I don't see any practical logic to creating a component of many files and hundreds of code lines just to handle a simple task. I am not trying to develop a photo gallery extension. The client was achieving the goal successfully by inserting page break between images but it was quite tedious. A plugin would be more applicable and was considered but with so few lines of code it was just an overkill. It would be more practical to write a separate pagination method, just that I prefer to plug into Joomla's framework. Your suggestion implies that it's impossible and I doubt that.
    – Nadal
    Commented Oct 30, 2018 at 23:44
  • It's not impossible. It's just wrong to do something like this in a layout. At least a plugin should be used. To answer your question directly - you need to pass the fourth argument to JPagination. It's a prefix to be used for generating pagination links. But you also need to handle non-existing pages with broken images. That's another thing that doesn't belong in a layout.
    – Sharky
    Commented Oct 31, 2018 at 8:28
  • That plugin you posted is fine for global use. For my client it was solely for use in Joomla article and it works quite fine and simple. I don't see why you consider it "wrong" to have such a process in a layout file. Please elaborate on that so we all can understand. I read the same API document link which you read and nothing implies that it was not applicable to a layout file. I posted the final working code that was used in the article override, default.php
    – Nadal
    Commented Nov 6, 2018 at 0:09
  • Everything has its place. Layouts are for rendering only. Content manipulation such as this belongs in a content plugin. Having this in a layout is unmaintainable. It does not work with alternative layouts and different templates.
    – Sharky
    Commented Nov 6, 2018 at 8:19
  • Your point is valid accepted.
    – Nadal
    Commented Nov 8, 2018 at 3:57
0

The following code works correctly with the method from J3xAPI at https://api.joomla.org/cms-3/classes/Joomla.CMS.Pagination.Pagination.html#property_prefix

$pagebreak='';
if( preg_match('#\{pagebreakgallery=\"(.*?)\"\}#i', $this->item->text, $folder) ) 
{
    $imagesDir = JPATH_ROOT.'/images/photogallery/'.$folder[1].'/';
    $imgfiles = glob($imagesDir . '*.{jpg,JPG,jpeg,JPEG,png,PNG,gif,GIF}', GLOB_BRACE);
    $images = str_replace(JPATH_ROOT, Juri::root(true), $imgfiles);

    foreach($images as $image) {
      $page_break[] = '<img src="'.$image.'" />';
    }
    $this->item->text = str_replace($folder[0], '[pbgal]', $this->item->text);

    $pagenum = 0;
    if( $app->input->get('pg-limitstart') !='' )
      $pagenum = $app->input->getInt('pg-limitstart');

    $pages = count($page_break);

    if( $pages > 0 )
    {
      $pagelinks = new JPagination($pages, $pagenum, 1, 'pg-');
      $pagebreak .= $page_break[$pagenum];

      $pagebreak .= '
      <div class="paging">
        <div class="pagecount">'.$pagelinks->getPagesCounter().'</div>
        <div class="pager">'.$pagelinks->getPagesLinks().'</div>
      </div>
      ';
    }
}

The $pagebreak variable is output along with other modified processes within an array used in a str_replace() method. eg:

$this->item->text = str_replace(['[pbgal]','[refs]'], [$pagebreak,$refs], $this->item->text);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.