Search

Hi,

I've got two sections, Articles and Blog. In each, I've a checkbox for featured articles, that will be pulled from the database for display on the frontpage.

As I've set up things, with separate sections for articles and blogs, there is no easy way to order the featured articles over section boundaries. Either I have the featured articles go first, or the featured blog posts. But if I combine to two sections into one, I could have a Feature checkbox and a Order field as well.

Since most fields are in both sections, that solution wouldn't add to much to UI clutter. But since Articles and Blogs are different "at heart", I still would like to keep 'em separated.

Any ideas on how (if?) that could be achived, separate sections but still mix'n'match between featured content from each?

I can think of a couple of solutions. The first is Section based, the second is purely XSL based.

Firstly, you could add a third section called "Featured", which has three fields: Order (textfield), Post ID (textfield) and Type (select box, static values "Article" or "Blog"). To feature an Article or Blog post, create a new entry in Featured and type in the ID of the Article or Post entry. To print out your featured list, you'd need to create a DS for this section (Features) with an output parameter ($ds-features) of this Post ID field. Your Articles and Posts data sources then filter by this $ds-features. The XSL would then have a template to select each //features/entry, and depending on whether the Type is article or blog, call the template to write the correct content.

The second is probably a more elegant solution and doesn't require another fiddly section. Keep the featured checkbox and order field. Just make sure that your order numbers are used between each section (e.g. order 1, 2 and 4 might in Articles, but 3 might be in Blog). Use the two data sources to fetch the selected entries from each section. With XSL you can then combine the output of these two DS into one XML nodeset that can then be ordered with the Order field.

You'll need to use the EXSL extension to create a nodeset, so start by including this namespace in your stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl" exclude-result-prefixes="math">

You can then create a template who's sole purpose is to return a fresh XML nodeset of combined posts and articles. This template will loop through both sections, copying the entry nodes into a variable. The entries in this variable are then sorted and the XML returned.

<xsl:template name="generate-ordered-entries">

    <!-- Create a variable of all posts and articles -->
    <xsl:variable name="entries">

        <!-- Loop through all post entries -->
        <xsl:for-each select ="/data/blog-posts/entry">
            <!-- copy the entry node -->
            <xsl:copy-of select="." />
        </xsl:for-each>

        <!-- Loop through all article entries -->
        <xsl:for-each select ="/data/articles/entry">
            <!-- copy the entry node -->
            <xsl:copy-of select="." />
        </xsl:for-each>

    </xsl:variable>

    <!-- Loop through all entries in the $entries variable -->
    <xsl:for-each select="exsl:node-set($entries)/entry">
        <!-- Order by the "order" field in both sections -->                
        <xsl:sort select="order" order="ascending" data-type="number" />    
        <!-- copy the entry node -->
        <xsl:copy-of select="." />
    </xsl:for-each>

</xsl:template>

Then where you want to write these entries out to your page, you'll want to create a variable to call this template.

<xsl:variable name="ordered-entries">
    <xsl:call-template name="generate-ordered-entries" />
</xsl:variable>

You can then use an xsl:apply-templates or xsl:for-each to loop through and write out the common fields for both:

<xsl:for-each select="exsl:node-set($ordered-entries)/entry">       
    <h2><xsl:value-of select="title" /></h2>
</xsl:for-each>

Others may be able to refine the code and the method, but this is a solution I've used several times to combine and then re-order XML nodesets.

Ah. Beautiful! A bit over my head at the moment, but I'll read through again later today, and see if I get it. At least, I get to overall idea and am pleased that I don't have to abandon my dual-section setup.

There is an even simpler solution. You can combine and sort the entries of both sections using the union operator "|", like this:

<xsl:apply-templates select ="blog-posts/entry | articles/entry">
  <xsl:sort select="order" order="ascending" data-type="number" />    
</xsl:apply-templates>

(You do not need EXSLT for this.)

You might as well sort your entries by date, for example:

<xsl:apply-templates select ="blog-posts/entry | articles/entry">
  <xsl:sort select="concat(substring(date,1,4), substring(date,6,2), substring(date,9,2))"
    data-type="number"
    order="descending"
    />
</xsl:apply-templates>

Great. Thanks.

D'uh! I wasn't aware you could use the union and sort together — presumed it would sort the first batch then sort the secon batch. Great! Ignore my code then :-)

@ nickdunn: In the end we will all be Ninja coders!

:-)

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