Search

Hi there

At first a big thanks to the symphony-team - I just started to play around with symphony a few days ago and already am completely in love with the whole concept.

While building my first symphony-page I came to question how to handle something like a "next article" / "previous article" -option.

With my little knowledge of symphony and xslt I don't seem to be capable to build an easy solution, so maybe someone around here already has solved this problem in an elegant manner...?

MORE SPECIFIC:

  • I have an Article-Page with one Article and the $ds-article (System ID) parameter

  • I'd like to build custom datasources which fetch the next (or previous) article based on that parameter

  • I don't understand the syntax to use in the filter-section of the DS to build something like

filter article by System ID: > {$ds-article}

As far as I understand by what I've read about date-filtering these filter-options are a custom symphony-syntax, but except for the options available for the date-field-type I couldn't find any hints of what is possible and what not. Is there any kind of documentation about the whole filter-concept or is it possible to explain it in a few words...?

I think I could solve the next/previous-problem by working with date-filtering, but this somehow seems to be way too complicated for a rather simple task like that...

So if anyone could raise my understanding of advanced filtering in symphony I'd be quite thankful...

I've been playing with an article data source too and can't get it to produce an entry with the previous and next sequential entries (if they exist).

I remember this post for Symphony 1.7, but I doubt that solution will work with S2.

I'm pretty close to launching my Web site and this is a feature I'd really like to have. The DS creator is so robust, that I have a hard time believing that it can't be done!

For now, a recent entries list will do fine, but when I start to get a lot of entries, the next/previous links would be ideal.

I haven't had a chance to fully read through this post but couldn't this be done with setting up pagination and have the entry limit by 1? i.e. page one would be the most recent entry, page 2 would be a previous entry, etc.

i think allen's solution is probably the easiest one to implement.

Usually, your entry URLs look like this:

www.yoursite.com/articles/article-title

If you do pagination, they would look like this (and you would loose your clean URL):

www.yoursite.com/articles/2

I'd want this pagination (prev/next links) to be on every individual article page. How would the system know what page to link to if you clicked on an article in the archive?

Here's an alternative:

  1. Create 3 data sources
  2. First data source to produce the "focus article". This is your main data source that you would normally produce for your article page (filter by $article).
  3. Second data source to produce the next entry's handle (filter by $article, limit 2, sort descending)
  4. Third data source to produce the previous entry's handle (filter by $article, limit 2, sort ascending)

For data sources 2 and 3, you'll each get one redundant element, being the focus article's handle.

Nice idea. I don't mind a few redundant entries and I can reduce the number of elements #3 and #4 pull.

I'll give it a try. Thanks!

Just an idea.
It could be possible to rewrite Number Field extension make it automatically save entry id and filter entries with simple math.
Then you could use smth like {$ds-articles} + 1, {$ds-articles} - 1 in DS Filter Results options.

Or, maybe, it's possible to make such an addition to existent System ID filtering rules.

You would need to filter by date. IDs don't always go in order.

Yes, and math applied to Date I've talked about here.

I agree that it would be nice to have Math operations for filters.

Allen, your idea in post #6 above doesn't quite work that way in the DS. It looks like a custom data source is going to be needed.

I'll wait patently for some documentation on that subject after the beta period is over. If anyone knows how the DS works and wants to tackle this, let me know! :-)

If you'd like to apply simple math operations to article ids try this: Create a file called data.neighbours.php in your workspace folder with the following content.

<?php

    require_once(TOOLKIT . '/class.datasource.php');

    Class datasourceneighbours extends Datasource{

        function about(){
            return array('name' => 'Neighbours');   
        }

        function allowEditorToParse(){
            return false;
        }

        function grab(&$param_pool){
            $param_pool['ds-neighbours'][] = intval($param_pool['ds-article'][0]) - 1;
            $param_pool['ds-neighbours'][] = intval($param_pool['ds-article'][0]) + 1;
        }

    }

?>

Set up another data source using the data source editor called Article that outputs the current article id ($ds-article). Associate both data sources with your page.

You'll now see a new parameter in the pool called $ds-neighbours that includes the previous and the next id that can be used as a filter for data sources.

Please note that this data source does not check if the generated ids really exist.

That works just like you said. Thanks.

Only, my article IDs don't always go in order of post date. For this to work, I'd need to have it get the previous and next articles by publish date.

I'd like to make a webcomic site and for me to be able to use Symphony, I'd need this type of functionality. Pagination is close, but not quite right.

Give this a go. You will need to replace XXX with the ID of your date field:

$entry_id = (int)$param_pool['ds-article'][0];
$entry_date = $this->_Parent->Database->fetchVar('local', 0, "SELECT `local` FROM `sym_entries_data_XXX` WHERE `entry_id` = $entry_id LIMIT 1");

$sql = "SELECT `entry_id` FROM `sym_entries_data_XXX` WHERE `local` < $entry_date ORDER BY `local` DESC LIMIT 1";
$param_pool['ds-neighbours'][] = $this->_Parent->Database->fetchVar('entry_id', 0, $sql);

$sql = "SELECT `entry_id` FROM `sym_entries_data_XXX` WHERE `local` > $entry_date ORDER BY `local` ASC LIMIT 1";
$param_pool['ds-neighbours'][] = $this->_Parent->Database->fetchVar('entry_id', 0, $sql);

I think that should do it.

Sweet! I'll test it out soon. Thanks!

Now we're getting closer! That DS pulls articles in the correct order and returns nothing if a prev/next article doesn't exist.

~BUT~

It breaks down if you create a draft article and throw that in the mix.

Is there a way to ad an 'if' statement selecting published articles before you do the sorts? I guess that data is in another table, so it might be a little bit difficult getting at it to create an array?

It breaks down if you create a draft article and throw that in the mix.

This is why next/prev is so difficult. At any given time your articles might be filtered by any number of arbitrary things, and matching that up with a next/prev DS is really tricky.

To solve your specific problem, you will need to do a LEFT JOIN to pull in the 'draft' field table. This is what the next SQL might look like (change the > to < for previous):

### NEXT
$sql = "SELECT t1.`entry_id` 
             FROM `sym_entries_data_XXX` AS t1
             LEFT JOIN `sym_entries_data_YYY` AS t2 ON t1.entry_id = t2.entry_id
             WHERE t1.`local` > $entry_date 
             AND t2.value = 'yes'
             ORDER BY t1.`local` ASC LIMIT 1";

That assumes your 'draft' field is a checkbox. You will need to set YYY to the ID of your 'draft' field.

Hope that does the trick.

Now I completely understand why this is difficult to do with data sources. Thanks a ton for helping me figure this out!

I'll try to implement it soon and report back.

Yes! It appears to be working just right. Thank you, Alistair.

Here's the finished DS that will give you the 'next' and 'previous' article IDs as a page param. Then you can use the system IDs it returns in another DS using {$ds-neighbours} under 'Filter results' and filter by 'system ID'.

<?php

    require_once(TOOLKIT . '/class.datasource.php');

    Class datasourceneighbours extends Datasource{

        function about(){
            return array('name' => 'Neighbours');   
        }

        function allowEditorToParse(){
            return false;
        }

        function grab(&$param_pool){
            $entry_id = (int)$param_pool['ds-articles'][0];
            $entry_date = $this->_Parent->Database->fetchVar('local', 0, "SELECT `local` FROM `sym_entries_data_29` WHERE `entry_id` = $entry_id LIMIT 1");

            ### PREVIOUS
            $sql = "SELECT t1.`entry_id` 
                         FROM `sym_entries_data_XXX` AS t1
                         LEFT JOIN `sym_entries_data_YYY` AS t2 ON t1.entry_id = t2.entry_id
                         WHERE t1.`local` < $entry_date 
                         AND t2.value = 'yes'
                         ORDER BY t1.`local` DESC LIMIT 1";
            $param_pool['ds-neighbours'][] = $this->_Parent->Database->fetchVar('entry_id', 0, $sql);

            ### NEXT
            $sql = "SELECT t1.`entry_id` 
                         FROM `sym_entries_data_XXX` AS t1
                         LEFT JOIN `sym_entries_data_YYY` AS t2 ON t1.entry_id = t2.entry_id
                         WHERE t1.`local` > $entry_date 
                         AND t2.value = 'yes'
                         ORDER BY t1.`local` ASC LIMIT 1";
            $param_pool['ds-neighbours'][] = $this->_Parent->Database->fetchVar('entry_id', 0, $sql);
        }

    }

?>

With the default install of Symphony, the date field and publish checkbox are already set up for the article section. The table name with the default install is sym_entries_data_### where ### is the number for the table. You may have to change the prefix, sym to the one you used when you installed Symphony.

You will need to set XXX to the ID of your 'date' field and YYY to the ID of your 'published' field. The 'published' field must be a checkbox where 'yes' means published and 'no' means draft.

With my default Symphony install, the ID for the date field was 29 and the published checkbox was 30.

Glad its working. Couple of things I should mention.

You're making a call to the pooled params array, so it's a good idea to declare a dependency to ds-articles. Use the following:

const articlesDSHandle = 'articles';

function __construct(&$parent, $env=NULL, $process_params=true){
    parent::__construct($parent, $env, $process_params);
    $this->_dependencies = array('$ds-' . self::articlesDSHandle);
}

and change $entry_id = (int)$param_pool['ds-articles'][0]; to

$entry_id = (int)$param_pool['ds-' . self::articlesDSHandle][0];

The table name with the default install is symentriesdata_### where ### is the number for the table.

I would suggest setting up some constants in the class to make it easier to modify.

const dateFieldID = 'X';
const publishFieldID = 'Y';

then use self::dateFieldID and self::publishFieldID in the SQL, which will look something like:

 FROM `sym_entries_data_".self::dateFieldID."` AS t1
 LEFT JOIN `sym_entries_data_".self::publishFieldID."` AS t2 ON t1.entry_id = t2.entry_id

You may have to change the prefix, sym to the one you used when you installed Symphony.

Leave it as sym_ and Symphony will automatically replace it with the table prefix defined in config.php

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details