Properties/Templates of categories with >1 categories

Creating and modifying plugins.
d_cee
Regular
Posts: 603
Joined: Wed Jan 18, 2006 6:32 pm
Location: UK
Contact:

Post by d_cee »

Hi Guys

how'r you doing Judebert?

Since I've wished for this fuctionality before, what you are doing here seems very useful so I thought I should add my two'pennorth.

Perhaps if the category is a parent category it could take priority otherwise would it be possible to use the first category selected. The only other way of choosing I can think of would be for there to be primary and secondary categories but I think this is a much bigger change.

cheers

Dave
Don Chambers
Regular
Posts: 3652
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

Jude - I finally had a chance to try your code. It works fine in category view, but not on single entry view.

Regarding Dave's mention of using a parent category, I know this does not presently work at all.... and if it did, I personally think that should only be an option.... not mandatory. I might want a parent to have a template, but deliberately not want a child category to inherit that setting.
=Don=
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

Jude - I finally had a chance to try your code. It works fine in category view, but not on single entry view.
WTH? I thought this would only be activated on single-entry view.

Great. Now I'm actually going to have to get involved. :roll: :wink:

Are you sure you cleared your browser cache before testing?

In any case, I'll set up my blog with a custom category template and give it a shot. At least temporarily. Should have something soon.
Perhaps if the category is a parent category it could take priority otherwise would it be possible to use the first category selected.
There's no concept of child or parent at this point in the code; to obtain that information would require at least one, possibly several, database lookups. I try to avoid database lookups for performance and resource reasons.

If there were a hierarchy at this point, I'd expect to use the closest parent's custom template -- almost exactly the opposite of what was recommended in this quote. Doing so would cover inheritance, too. If you wanted a child not to inherit, you'd just explicitly set its custom template to the default.

I've actually been thinking that we could cover inheritance at the point where we set custom templates in the backend: when you set a category's custom template, find all its children and set their custom templates, too. This also requires several database lookups, but that's really only a problem at display time. (You're allowed to spend a bunch of time and resources when you set things up, as long as it's fast when you actually try to use them.)
Judebert
---
Website | Wishlist | PayPal
Don Chambers
Regular
Posts: 3652
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

judebert wrote:WTH? I thought this would only be activated on single-entry view.
ONLY single entry view??? No - you would want it for both single entry, as well as all entries for a category.... right??
=Don=
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

The plugin certainly should work for both, but the chunk we were looking at deals mostly with single entries. That first if() returns the category id if we're looking at a category; everything in the second if() deals with a single entry.
Judebert
---
Website | Wishlist | PayPal
Don Chambers
Regular
Posts: 3652
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

Just making sure... :lol:
=Don=
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

That's always a good idea.

In any case, it's fixed now. The problem was that Garvin is a database genius, while I'm (at least relatively) an idiot. The serendipity_db_query() function returned the values in a slightly different format than I expected.

Additionally, my categorytemplates table was full of empty values.

Anyway, I modified the code to properly unpack the custom category IDs, and everything started working. You can check it out on my blog, at least for a day or so: I made the "Family" category use a custom template. (Incidentally, we need to turn that into a drop-down or something.)

If you open the Family category, you'll see it uses a different template than the rest of my blog. I think you need to advance to the second page before you finally find an entry in multiple categories; for instance, my online multiplication worksheet. It has the custom template applied as well, but this entry in a subcategory still gets the default template.

To check the multiple-category resolution, I made News a custom template, too. The News category has its own, different template, while an entry in both News and Family uses the default template.

Here's the code I used:

Code: Select all

    function getID() {
        global $serendipity;

        if ($serendipity['GET']['category'] && !isset($serendipity['GET']['id'])) {
            return (int)$serendipity['GET']['category'];
        }

        if ($serendipity['GET']['id']) {
            $entry = serendipity_fetchEntry('id', $serendipity['GET']['id']);

            // Find all the categories that have custom templates
            $dbcids = serendipity_db_query("SELECT categoryid FROM {$serendipity['dbPrefix']}categorytemplates WHERE template != ''");
            // Unpack the response
            $cids = array();
            if (is_array($dbcids)) {
                foreach ($dbcids AS $dbdatum) {
                    $cids[] = $dbdatum['categoryid'];
                }
            }

            // Find all the categories of this entry that have custom templates
            $custom = array();
            foreach($entry['categories'] AS $idx => $cat) {
                if (in_array($cat['categoryid'], $cids)) {
                  $custom[] = $cat['categoryid'];
                }
            }

            // Set up and return the custom category
            if (count($custom) == 1) {
                if (serendipity_db_bool($this->get_config('fixcat'))) {
                    $serendipity['GET']['category'] = (int)$custom[0];
                    header('X-FixEntry-Cat: true');
                }
                return (int)$custom[0];
            }
        }

        return 'default';
    }
To change the case of an entry with multiple custom categories, just modify that "if(count($custom) == 1)" bit. You've got a whole array of custom template categories to choose from; pick the first one we found, or the last, or a random one. Or compare them for precedence, as defined... however you like it.
Judebert
---
Website | Wishlist | PayPal
Don Chambers
Regular
Posts: 3652
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

Just checked it out Jude - seems to be working exactly as expected:

1) default template applied to all categories and views.
2) default template applied to all categories that do not define their own template.
3) Custom category template applied when defined for a entry with a single category.
4) Custom category template applied when entry assigned to more than one category, but only one of those categories has a defined template.
5) default template applied when entry applied to multiple categories that each have definted templates.

Did I miss anything yet?

Now for this:
To change the case of an entry with multiple custom categories, just modify that "if(count($custom) == 1)" bit. You've got a whole array of custom template categories to choose from; pick the first one we found, or the last, or a random one. Or compare them for precedence, as defined... however you like it.
What would the corresponding code be for those options, and would it be worthwhile to have those options listed in the backend for the plugin?
=Don=
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

Well, let's see what I can work out here. We're talking how to choose a custom template for displaying the single-entry view for entries with multiple categories that have custom templates defined. (Whew!) The shorter version: two or more categories are fighting to display their own custom template. Who will win?

Option 1: Everybody loses, use the default template.

This is the option being used right now. The code looks like this:

Code: Select all

            // Set up and return the custom category
            if (count($custom) == 1) {
                if (serendipity_db_bool($this->get_config('fixcat'))) {
                    $serendipity['GET']['category'] = (int)$custom[0];
                    header('X-FixEntry-Cat: true');
                }
                return (int)$custom[0];
            } 
Option 2: Whoever is mentioned first wins.

This option is a little unpredictable, since we don't know if the categories are sorted in any particular order. We don't know if it's dependent on the database, the category ID, or the category name. There's a lot we don't know. In any case, its code looks like this:

Code: Select all

            // Set up and return the custom category
            if (count($custom) >= 1) {
                if (serendipity_db_bool($this->get_config('fixcat'))) {
                    $serendipity['GET']['category'] = (int)$custom[0];
                    header('X-FixEntry-Cat: true');
                }
                return (int)$custom[0];
            }
No biggie; just changed from "if there's one" to "if there's at least one".

Option 3: The category with the highest (or lowest) ID wins.

This almost makes sense. If your blog's categories were all created at one shot, it's likely they're in some sort of order. The code would look like:

Code: Select all

            // Set up and return the custom category
            if (count($custom) >= 1) {
                array_reverse(sort($custom, SORT_NUMERIC));
                if (serendipity_db_bool($this->get_config('fixcat'))) {
                    $serendipity['GET']['category'] = (int)$custom[0];
                    header('X-FixEntry-Cat: true');
                }
                return (int)$custom[0];
            } 
The array_reverse() is necessary because sort() always sorts ascending. So if you want the lowest ID to win, just remove the array_reverse().

Option 4: The category with the alphabetically highest name wins.

This is tempting, because Serendipity's archive URLs ignore the category name if the category ID is specified. Therefore you could rename all your categories for the correct precedence, and your old URLs would still work. However, it requires some more extensive code changes, because our db query doesn't retrieve the category names, and the names aren't unpacked when we "unpack the response".

Therefore, I'm not providing code for this option unless we decide this is what we really want.

Option 5: Specify the precedence of the category where we specify the template.

The easiest and most intuitive way to do this is to add an additional text field after the category template field, on the category page. The new field would be the "Precedence", and we'd add code to check it when multiple categories were found.

The problems with this option include that it's still possible to set categories with equal precedence, leading to the problem not actually being solved; there's a lot of code to modify (so again, I'm not working it out unless we decide this is the way to go); the database schema needs to be changed so the precedence field is included; and it's impossible to see all the categories' precedences at the same time.

Option 6: Specify the precedence of the categories on the plugin configuration page.

This is probably the best of our available options. It's going to be a bit of a pain to code, though. My idea is that the plugin configuration page would include a list of all the categories that have custom templates and allow you to drag them up and down until they're in the order you like. I'd want to steal the code from the plugin page to do this (the code that lets you drag plugins to the appropriate place in your sidebar, for instance).

Whenever you assign a custom template to a category, I'd insert it at the top of the list (most important), so your new changes are certain to take effect.

This keeps all the categories in an unambiguous order. All the heavy processing is done when the templates are assigned or the plugin is reconfigured, so the retrieval can be as fast as possible. It may not require a change to the database: if this can be made into an "ordered list" option, it could be placed into a configuration variable instead -- and it might be useful for templates or other plugins that need an ordered list.

The only drawback is that it's a LOT of code. But, if you can find a programmer dumb enough... uh, I mean, interested enough to take it on, it would be pretty slick.

Oh, I forgot Option 7: pick randomly.

Just replace the array_reverse(sort($custom)) with shuffle($custom) and carry on. This is probably the most capricious of all the available options.

Discussion?
Judebert
---
Website | Wishlist | PayPal
Don Chambers
Regular
Posts: 3652
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

Option 6 is probably the only one that makes any sense, but I do not want to burden you with excessive work Jude... Also, Garvin has not weighed in on the matter yet, so what we have working right now has not even been committed AFAIK. It does, however, work great.... as long as only one category for a given entry has a defined template. In fact, I think it works great!!!!! And maybe it is really enough!!! Ya think??!!
=Don=
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Hi!

IMHO option 6 is the only viable option to go with, if the precendence is coded into the plugin. Manual configuration really sucks, interface wise.

But I fully agree with Judebert: It's a lot of code, and at least too much for me. If I were in the position to need to choose different categories, I'd instead code my own event plugin to do that with customized code, and that's what I'D also do for clients that want this flexibility. Certain stuff can only be reached with customized programming, and not with generic coding - generic coding is a real pain for complex matters like this.

Having said that: I'd love if someone coded this. :)

I agree with you Don, that the code to pick the template of a category that has been given a specific template is already a large improvement over current code, and that it should be committe.d :)

Regards,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
blog.brockha.us
Regular
Posts: 695
Joined: Tue Jul 03, 2007 3:34 am
Location: Berlin, Germany
Contact:

Post by blog.brockha.us »

garvinhicking wrote:I agree with you Don, that the code to pick the template of a category that has been given a specific template is already a large improvement over current code, and that it should be committe.d :)
Did you already? :-)
- Grischa Brockhaus - http://blog.brockha.us
- Want to make me happy? http://wishes.brockha.us/
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

I just did. :)
Judebert
---
Website | Wishlist | PayPal
Don Chambers
Regular
Posts: 3652
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

Thanks for committing Jude, and thanks also Garvin for your input. At first, this didn't seem like it was going anywhere, but now we have another valuable dimension to templates for categories!!
=Don=
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

And it's getting better. I've completed the Javascript version of the sequence editing widget. I've added it to the serendipity_event_advtypes plugin, and I'm testing it on my website. It works for both theme and plugin options.

The options require a bit of setup, but I'm working to eliminate that. A little bit of cleanup is also required.

The big effort at the moment, however, is figuring out how to make it work without Javascript. We don't have the modify-up and modify-down processing in the configuration save section, so I'm going to have to figure something else out.
Judebert
---
Website | Wishlist | PayPal
Post Reply