Textpattern CMS support forum
You are not logged in. Register | Login | Help
- Topics: Active | Unanswered
How to create a table cross-referencing content by cats on 2 axes
Hi!
I’m working on a section landing page for a knowledge base section of a website. The majority of content in this section is tagged with two categories, so that one category indicates the topic and one category indicates the audience. What I’m trying to create is a table like this (using HTML table markup, not pipes):
| cat1 | cat2 | cat3 |
--------|-------|-------|-------|
catA | [A-1] | [A-2] | [A-3] |
catB | [B-1] | [B-2] | [B-3] |
catC | [C-1] | [C-2] | [C-3] |
The idea is that the category headings along the top share a parent, and the category headings along the left share a different parent. Listing those is no trouble at all. The puzzle I’m trying to figure out is how to list articles in each row so that it shows one link per category pair, linking to content in that section tagged with both categories. The other part is how to generate an empty cell if there isn’t a single article tagged with both categories.
I’d be grateful for any thoughts or ideas. Is this possible? Thanks!
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
What about using an identical output_form
container for each cell and try to fill in the data with yield
? Never did this but on a 1st fast look your problem might be a use case for yield
.
Empty cell: The mentioned form will stay empty if there is no output.
Get all online mentions of Textpattern via OPML subscription: TXP Info Sources: Textpattern RSS feeds as dynamic OPML
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
Not thought it through fully, but if you’re not averse to another smd_* plugin wasting space in your installation I wonder if you could bend smd_macro into a shape that suits your needs? Define a tag to represent a cell and maybe one or two to represent the X and Y axes and put your own code in. Then build it up with a bunch of tag calls and attributes.
It’s like Markus’ idea but with more control as you can pass more then one attribute in; somethjing you can’t do with <txp:yield />
(unless you want to split the parameter manually inside the output_form). If you set the cell macro up with category (or cat1/cat2) attributes you could perhaps feed the correct cat in that way and have it build the correct article tag.
Might be a red herring, but I’ve played with (a simpler version of) something similar and it worked OK.
The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.
Txp Builders – finely-crafted code, design and Txp
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
Well, TXP 5 needs spreadsheet features :)
Get all online mentions of Textpattern via OPML subscription: TXP Info Sources: Textpattern RSS feeds as dynamic OPML
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
Thanks Markus, Stef!
I looked into the smd_macro plugin, and I can’t imagine how to get the results I want. It looks like smd_macro allows you to define your own tags based on core functionality (plus any active plugins), but I don’t know how to achieve this with vanilla TXP tags.
Is it possible to create a URL that lists articles belonging to two categories? So if I tag some articles with cat3 in the “Category 1” dropdown, and catA in the “Category 2” dropdown, how could I list the articles that share those categories on the public site?
The links in this table should all be pointing to pages like that, listing articles that are tagged with the specified category on the X axis AND the specified category on the Y axis.
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
Bloke wrote:
Might be a red herring, but I’ve played with (a simpler version of) something similar and it worked OK.
Stef, would you be willing to post an example of what you have in mind, even a simpler version?
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
johnstephens wrote:
would you be willing to post an example of what you have in mind, even a simpler version?
Actually, the macro was a red herring. Too complicated. It’s probably simpler to do it in an article_custom loop:
<table>
<tr>
<th> </th>
<txp:hide> topic is the parent for category2 </txp:hide>
<txp:category_list parent="topic" break="th" exclude="topic" />
</tr>
<tr>
<txp:article_custom section="johnq" limit="999" sort="Category1,Category2">
<txp:if_different></tr><tr><td class="label"><txp:category1 /></td></txp:if_different>
<txp:smd_if field="category1,category2" operator="isused,isused">
<td><txp:body /></td>
<txp:else />
<td> </td>
</txp:smd_if>
</txp:article_custom>
</tr></table>
You can replace the <txp:body />
tag with anything you like from the article to make your link to the section.
EDIT: You do get one empty row with this technique at the start of the table body so if you care about validation you might have to add some empty <td>s above the start of the article_custom
EDIT2: and it gets more complicated with more than one article per category-pair because you have to make sure they all go ‘in’ the same <td>, even if you’re only outputting a single link to that group. You probably need another if_different (or an smd_if / txp:variable combo) to detect the end of the group.
Last edited by Bloke (2011-03-28 18:38:58)
The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.
Txp Builders – finely-crafted code, design and Txp
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
Thank you, Stef!
This is tricky. It seems to be generating a variable number of empty cells, and the cells aren’t lined up according to the header row. And although it was easy enough to switch the txp:body
tags out in favor of <txp:permlink><txp:title/></txp:permlink>
, I don’t know how to get a link to a page showing all articles associated with both categories.
Here’s the code I developed prior to posting the query here:
<table>
<thead>
<tr><th> </th><th colspan="6">Commentaries by branch</tr>
<tr>
<th>General Fact Sheets</th>
<txp:category_list break="th" exclude="branches" parent="branches" wraptag=""><txp:category title="1"/></txp:category_list>
</tr>
</thead>
<tbody>
<txp:category_list
break="tr"
categories='<txp:category_list break="," exclude="X-topics" parent="X-topics"><txp:category/></txp:category_list>,<txp:category_list break="," exclude="Y-topics" parent="Y-topics"><txp:category/></txp:category_list>'
wraptag=""><th><txp:category link="1" section='<txp:section/>' title="1"/></th>
<txp:article_custom
section='<txp:section/>'
category='<txp:category/>'
limit="9999"
sort="category2"><txp:if_article_category name='<txp:category_list break="," exclude="branches" parent="branches"><txp:category/></txp:category_list>'><td><txp:permlink><txp:title/></txp:permlink></td></txp:if_article_category></txp:article_custom></txp:category_list>
</tbody>
</table>
This gives me valid table markup, and it outputs the table cells in the proper order. What it doesn’t do is account for junctions that don’t have an article associate with both topics— instead of outputting an empty cell, it just gives me the next article, giving me a link that’s one cell left of where it should be (affecting every subsequent cell in the row). It also outputs links to individual articles (since that’s what I’ve told it to do), instead of a list of all articles that fit both categories.
I guess the first issue I need to resolve is whether it’s possible for Textpattern to display a set of articles that belong to two specified categories. Looking at your code sample suggests that it’s possible to do this with smd_if, but I’m not sure how to generate a link to such a list from a table like this.
The second issue is how to generate empty cells in the right places. I’m thinking that the reason it didn’t work in my test of this code snippet is that it was showing an empty cell for every article it found that didn’t have the required categories, instead of generating one empty cell based on some (as-yet) magical understanding of the table’s structure.
Can Textpattern process a URL that specifies two categories and show a list of articles that are tagged with both? Is there any way to generate such a URL without engaging in ancient forbidden rituals involving blood sacrifice?
Thanks always for your willingness to wrangle with these outside-the-box cases!
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
I think I may have figured out the fist issue; I’ll update this thread shortly with results. The second issue lingers.
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
johnstephens wrote:
I don’t know how to get a link to a page showing all articles associated with both categories.
The only way I can think of doing this is with smd_query. If you generate your URLs like this:
site.com/category/article/{topic}/{audience}
Then TXP puts you in category context and dutifully shows you articles in the {topic} category. The key to this URL structure is that TXP ignores {audience}. Incidentally you need to specify /article/
otherwise the new context system would see two ‘things’ after the /category/
, assume the first was you mis-typing article, image, file or link, defaulting to ‘article’ and then showing an article list from {audience}.
Thus, inside a suitable <txp:if_category>
construct on your landing page, don’t use an article tag. Sure TXP will complain, but ignore it. Instead split the $_SERVER['REQUEST_URI']
at slash and take the last two items then plug those into smd_query WHERE section='<txp:section />' AND category1 IN ('{topic}', '{audience}') AND category2 IN ('{topic}','{audience}')
.
That will then give you a list of articles that contain both. Any similar URL structure will do — you could even direct landing pages to a dedicated site.com/section/article/{topic}/{audience}
and use the same technique. If you wanted to take advantage of adi_gps and save yourself having to manually split the REQUEST_URI, how about using gbp_pl or an htaccess rule to turn the pretty URL into site.com/section/article/?topic={topic}&audience={audience}
?
So that’s part 1 out of the way. Part 2 — the table — is the difficult bit. As you’ve found out, your code is fine until you have no article assigned to either category and your table ‘slips’. That’s why I approached it differently by using article_custom to order your articles by cat1 then cat2 and iterating over them. All items in any row share a common cat1 thus the if_different outputs the next row when the cat1 changes. Everything else must belong to one of the cat2 columns but we don’t know which. The only thing we do know is that they are in order so we can process them left to right.
What my code should have done (as I alluded to in the 2nd edit) is use another if_different inside the smd_if to only trigger a <td> when cat2 changes. At all other times in the branch, we’re dealing with another article that has the same cat1-cat2 combination as the last article and we can ignore it. The smd_if just takes care of the eventuality that one (or both) of the categories is empty and outputs an empty cell. However, a subtelty arises here: since we’re ordering by cat1, cat2
any time cat1 is ‘empty’ it’ll appear at the start of the list (if cat2 is also empty) or start of a row otherwise. This’ll foul up your table so my solution isn’t really that practical after all, sorry.
Only way that I can think of to possibly mitigate this is to bypass article_custom and use smd_query again, perhaps considering MySQL’s UNION statement to join two SELECTS — one for each category? Just a random guess.
Not sure if that’ll get you anywhere near where you’re going but it’ll keep you out of mischief for a bit :-)
Last edited by Bloke (2011-03-29 20:54:56)
The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.
Txp Builders – finely-crafted code, design and Txp
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
This sounds like it could be a lot better than the method I hacked together, but it’s a fur piece beyond my technical know-how at the moment. Here’s what I did:
For the table, I used the code posted here, slightly modified, to spit out links to articles that share both categories.
Then, within the form that displays the individual article, I have the following manic soup of tags [nesting added for clarity]:
<txp:variable name="this_topic1"><txp:category1/></txp:variable>
<txp:variable name="this_topic2"><txp:category2/></txp:variable>
<txp:article_custom
break=""
category='<txp:variable name="this_topic1"/>,<txp:variable name="this_topic2"/>'
wraptag=""
limit="9999"
section='<txp:section/>'
sort="posted asc">
<txp:if_article_category name='<txp:variable name="this_topic1"/>'>
<txp:if_article_category name='<txp:variable name="this_topic2"/>'>
<!-- Article output -->
</txp:if_article_category>
</txp:if_article_category>
</txp:article_custom>
This, of course, works magnificently: it displays every article in the section tagged with both categories. Only trouble is, this output would be identical for the URL for each of those articles, which means I have to make sure all those other URLs are suppressed in the site map and any other listing.
By comparison, your site.com/category/article/{topic}/{audience}
URL structure looks pretty sharp and elegant, and I think I could suss out how to do the smd_query and adi_gps bits. I don’t know anything about splitting the REQUEST_URI, though, and I can’t figure out how to use gbp_permanent_links at all. I’m totally happy to add a rewrite rule to my .htaccess file, but I don’t know how to make the rule dynamic enough to handle any {topic}/{audience}. Is that easy?
Thanks a bunch, Stef!
Offline
Re: How to create a table cross-referencing content by cats on 2 axes
johnstephens wrote:
I don’t know anything about splitting the REQUEST_URI
A jot of (untested) PHP should do the trick:
<txp:if_category type="article">
<txp:php>
global $variable;
$req = serverSet('REQUEST_URI');
$reqparts = explode('/', $req);
if (count($reqparts)==5) {
// We have site.com/category/article/{topic}/{audience}
$variable['topic'] = $reqparts[3];
$variable['audience'] = $reqparts[4];
}
</txp:php>
<txp:hide> In here, do smd_query and use <txp:variable name="topic" />
(or "audience"), or use the smd_query '?' notation to access the
txp:variables we just created in PHP. </txp:hide>
</txp:if_category>
Alternatively, the rewrite rule approach would work, but I’m not the world’s greatest .htaccess whiz. It’ll probably be based around:
RewriteRule ^/category/article/(.*)/(.*)$ /some_section/some_article?topic=$1&audience=$2 [L]
Then in your some_section/some_article
article you can use adi_gps to read in the vars and do the smd_query in there. If you make sure that your some_section is hidden from view to everyone you might even get away without it being indexed.
There are probably more inventive ways to achieve this (txp:output_form being a candidate), but I think posting back to the /category page will fail as it’ll get confused or, at best, only show one of the categories. Might be wrong.
EDIT: actually, as long as you don’t use a txp:article tag in that if_category conditional you might get away with it.
Last edited by Bloke (2011-04-05 19:57:22)
The smd plugin menagerie — for when you need one more gribble of power from Textpattern. Bleeding-edge code available on GitHub.
Txp Builders – finely-crafted code, design and Txp
Offline