Textpattern tips, tutorials and code snippets

Archive tree with article counts

Someone on TXP Forum asked for a simple way to construct a tree of articles sorted by year/month, with article counts, like this:

…and so on. trenc came out with an elegant solution for the tree, presented below with small modifications. We have added empty span placeholders for counts and put the tree into the archive variable for further needs.

The code

<txp:variable name="archive">
<txp:article_custom sort="Posted desc" limit="999">

	<txp:variable name="year" value='<txp:if_different><txp:posted format="%Y" /></txp:if_different>' />
	<txp:variable name="month" value='<txp:if_different><txp:posted format="%Y-%m" /></txp:if_different>' />

	<txp:if_first_article>
		<li><txp:posted format="%Y" /> (<span></span>)<ul>
		<li><txp:posted format="%b" /> (<span></span>)<ul>
	<txp:else />
		<txp:if_variable name="month" value=""><txp:else />
			</ul></li>
			<txp:if_variable name="year" value=""><txp:else />
				</ul></li>
				<li><txp:posted format="%Y" /> (<span></span>)<ul>
			</txp:if_variable>
			<li><txp:posted format="%b" /> (<span></span>)<ul>
		</txp:if_variable>
	</txp:if_first_article>

	<li class="article"><txp:permlink><txp:title /></txp:permlink></li>

	<txp:if_last_article>
		</ul></li></ul></li>
	</txp:if_last_article>

</txp:article_custom>
</txp:variable>

Roughly speaking, every time a new month/year is encountered, we close the current article list and open the next one.

Counters

But the problem of counters remains – see these empty () spans? A natural solution is to query the database for article counts for each year/month, but this would take time. And actually the articles are already retrieved – we only have to count them.

Use etc_query to replace the empty span tags

This is the very job for etc_query plugin, which does it in one line:

<txp:etc_query data='<txp:variable name="archive" />' query="li" replace=".//span={count(..//li[@class='article'])}" wraptag="ul" />

How it works? It takes the archive list, retrieves the top li elements (years), and replaces each span placeholder with the number of all li with class="article" found inside its parent. Could it be any easier?

4 Comments Comment feed

Thanks for this tutorial! It is my first time working with the etc_query plugin. The above code is giving me the following error:

Tag error: <txp:etc_query data=’<txp:variable name=“archive” />’ wraptag=“ul” query=“li” replace=”.//span=$[{count(..//li[@class=‘article’])}]$”/> -> Warning: DOMDocument::saveHTML() expects exactly 0 parameters, 1 given on line 410
textpattern/lib/txplib_misc.php(653) : eval()‘d code:410 DOMDocument->saveHTML()
textpattern/lib/txplib_misc.php(653) : eval()‘d code:222 etc_evaluate_string()
textpattern/publish.php:1188 etc_query()
textpattern/publish.php:1100 processTags()
textpattern/publish.php:538 parse()
index.php:45 textpattern()

Am I doing something wrong, or is there a typo in the code?

  • etc
  • 17 July 2012

Hi Stacey,

this probably means that your php version is prior to 5.3.8 required by etc_query. The only solution in this case will be to upgrade, I’m afraid.

  • etc
  • 18 September 2012

The etc_query syntax has a little changed in v.0.97(?), these $[]$ are not needed anymore.

Here is a version of the etc_query snippet that would add the class “current” (while keeping any existing class to all ancestor <li>s of currently viewed page. This could let you do some cool stying and/or scripting.

<txp:etc_query data='<txp:variable name="archive" />' class="news-list" replace='ul//ul^= <span>({count(..//li[@class="article"])})</span>;//a[@href="<txp:page_url  />"]/ancestor::li@@class={concat(@class," current")}' />

Add a comment

Use Textile help to style your comments