change <title> element in plugin

Creating and modifying plugins.
Post Reply
Don Chambers
Regular
Posts: 3657
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

change <title> element in plugin

Post by Don Chambers »

I am working on modifications to the metadesc plugin. That plugin provides the ability to customize meta keyword and meta description tags for each individual entry. I have extended that functionality to also provide a unique <title> element for any entry, plus have default meta keywords and meta descriptions that apply to all other pages. Defaults work great, and the new entry <title> element works great PROVIDED that a smarty condition is used in a template's index.tpl. My original method was to emit something like echo '<title>' . $meta_head_title . '</title>, if $meta_head_title was not blank. Again, worked fine, as long as I then used a smarty condition to suppress an index.tpl's usual <title>blah blah </title>.

But this only works, as mentioned, with a template modification. I want this functionality to be template-independent.... so I need the plugin to output what I want using the normal index.tpl title element of <title>{$head_title|@default:$blogTitle}{if $head_subtitle} - {$head_subtitle}{/if}</title>. In other words, I need to set $head_title to my extended field/variable of meta_head_title and set $head_subtitle to blank..... and ONLY on single entry pages.

Many thanks to Judebert and Grischa for helping me to get this far, but I think we might have collectively run into a wall and I now need further assistance.

The plugin currently emits to the frontend, and determines a single entry output, by the following:

Code: Select all

case 'frontend_header':
    if ($serendipity['GET']['id'] && isset($GLOBALS['entry'][0]['body'])) {
    // Only emit in Single Entry Mode
Now, I CAN set my entry <title> element in this case as other variables are set here with this:

Code: Select all

if (!empty($GLOBALS['entry'][0]['properties']['meta_head_title'])) {
    $meta_head_title = $GLOBALS['entry'][0]['properties']['meta_head_title'];
}
but that is not helping me because I cannot seem to change $head_title or $head_subtitle within this "frontend_header" case like this:

Code: Select all

$serendipity['head_title'] = htmlspecialchars($meta_head_title);
$serendipity['head_subtitle'] = '';
Now, I CAN add a new event hook/case of genpage.... and that case WILL allow me to change $serendipity['head_title'] and $serendipity['head_subtitle'].... but that case will NOT let me do what I am trying to do with $meta_head_title, which is my entry-specific "alternate" title element.

So, I have one event hook/case that will allow me to set $meta_head_title, and a different one that will allow me to manipulate $serendipity['head_title'], but NEITHER will do BOTH!

This is how I have defined $meta_head_title:

Code: Select all

    function introspect(&$propbag) {
        global $serendipity;
( this is not code - other stuff removed to shorten post......)
        $this->supported_properties = array('meta_description', 'meta_keywords', 'meta_head_title');
Hopefully, my objective is understood. Input appreciated, but here is a summary:
  • I have an extended entry value for meta_head_title
    I am successfully presenting this to the backend and saving it. Not a problem
    For single entry - and only single entry - pages, I need to set the <title> element to this value so no index.tpl smarty condition is necessary.
=Don=
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

I've finally got an extra hour to put into it, and this time I'm not sleepy, hungry, distracted, or dehydrated.

Unfortunately, I'm still verbose.

The problem we have is that only the 'genpage' hook gets called before the title is emitted. But at that point, the entry properties haven't been populated. There was a secondary problem with figuring out whether a page was an 'entry' page or a multiple-entry page.

With a little debugging, I found that Garvin had already provided a variable in the $addlData of the 'genpage' hook that fixes the secondary problem: if $addData['view'] == 'entry', we're looking at a single entry.

The primary problem was getting the properties. That can be done by finding the entry ID in $serendipity['GET']['id'], then using it in serendipity_fetchEntryProperties($id). That means an extra database lookup, but if there's a better way, I don't know what it is.

All fixed! Expect a new version from Don soon.
Judebert
---
Website | Wishlist | PayPal
Don Chambers
Regular
Posts: 3657
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

I cannot thank Judebert enough!!! His suggestions all worked. He hung in there with me late last night, early this morning, and again this evening until the problem was finally solved. I cannot tell you how frustrating it is to get 99% done, then blocked by a single problem and not be able to solve it yourself!!!

Then... I cannot begin to explain how great it is to have someone step up and help you through that problem until you reach a resolution!!!!!! Great to see this kind of assistance... I try to do it myself when I can, but php pushes the limits of my ability..... Thanks again Judebert!!! And thanks also to Grischa who also offered to assist with an earlier problem!

I still have much to clean up.. I will do that asap. I have just noticed a slight problem which needs to be fixed then I will possibly get a few of you to test the final version, and then commit.

Judebert - be sure you check your email for a better explanation of something I just observed.....
=Don=
carl_galloway
Regular
Posts: 1331
Joined: Sun Dec 04, 2005 5:43 pm
Location: Andalucia, Spain
Contact:

Post by carl_galloway »

Looking forward to it
Don Chambers
Regular
Posts: 3657
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

This is the code judebert came up with to solve my problem above. I'm leaving the comments in tact for a better explanation.

Code: Select all

        if (isset($hooks[$event])) {
            switch($event) {
                case 'genpage':
                    // The 'genpage' hook is our last chance to modify Smarty
                    // variables before the template is called for the header.

                    // Only modify the title on single-entry pages
                    if ($addlData['view'] == 'entry')
                    {
                        // Get the properties for this entry
                        $myid = $serendipity['GET']['id'];
                        // Requires a database fetch, but the only other way
                        // get the entry properties is to wait until we
                        // generate the entry; by the time that hook is 
                        // called, the <title> tag has already been emitted.
                        // We need those properties now!
                        $property = serendipity_fetchEntryProperties($myid);
                        // Set a title, if one was defined for this entry
                        if (!empty($property['meta_head_title'])) {
                            // Make the variable a little less unwieldy
                            $meta_title = $property['meta_head_title'];
                            $serendipity['head_title'] = htmlspecialchars($meta_title);
                            // Clear the subtitle (many templates use it along with the title)
                            $serendipity['head_subtitle'] = '';
                        }
                    }
                    return true;
                    break;
Now using most template's method of displaying a a <title> element:

Code: Select all

<title>{$head_title|@default:$blogTitle} {if $head_subtitle} - {$head_subtitle}{/if}</title>
$head_title becomes our $meta_title, $head_subtitle is blank, thereby making our <title> element ONLY $head_title.... which is EXACTLY what I wanted.

HOWEVER, I forgot to take something into consideration because I have been testing this in a template that does not use banner/header links to the title and subtitle.

This is the normal code for banner/header links:

Code: Select all

    <h1><a class="homelink1" href="{$serendipityBaseURL}">{$head_title|@default:$blogTitle}</a></h1>
    <h2><a class="homelink2" href="{$serendipityBaseURL}">{$head_subtitle|@default:$blogDescription}</a></h2>
On a normal single entry page, the banner links are entry title, followed by blog name. The code we have used to generate the <title> element has unfortunately affected these bannner links..... the first link, normally an entry title, is now our alternative <title> element. The second link, normally our blog name (in single entry mode) is now the blog description because $head_subtitle is blank, and it is using the @default:blogDescription.

So, for this to really function as I want it to, I now need to find a way to create the <title> element so it is emitted with our alternate version, but somehow get reset to normal so that single entry banner/header links display normally.

Is this possible????
=Don=
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

It *might* be possible. I'll take a look at the hooks when I get home later tonight. If the Smarty templates call the hooks, it's possible. If the code calls the Smarty templates... well, then we're trying to make the same variable have two different values at the same time.

In that case, a template change would be needed.
Judebert
---
Website | Wishlist | PayPal
Don Chambers
Regular
Posts: 3657
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

I think I am part way there Judebert....

This changes what I want to change, without affecting the <title> element...

Code: Select all

            $serendipity['smarty']->assign(
                array(
                    'head_title'     => 'don',
                    'head_subtitle' => 'chambers'
                )
            );
Now I need to actually set the title to the entry title, and the subtitle to the blog description. I cannot seem to get these values in frontend_header, but can I get them in genpage or elsewhere, and save them for later use in frontend_header??
=Don=
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Hi!

You can fetch variables with $serendipity['smarty']->get_template_vars('head_title') (of course, before you assign the value with your new value ;))

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/
Don Chambers
Regular
Posts: 3657
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

That does not seem to work in genpage. However, in frontend_header, I was able to use it to get the blogTitle. How do I now get the entry title?

Either that, or how exactly do I get/set a variable to the headtitle and subtitle before we change it in genpage, then use that variable in frontend_header?
=Don=
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Hi!

Hm, try a:

die(print_r($GLOBALS));

in the php code. There you'll see all variables that you can access.

Sorry, can't give you the proper variable, don't have the time for checking that right now.

I haven't read the whole thread, but can't you read head_title using get_var() just before you set it? In frontend_header you should be able to read and change all smarty variables, plus fetch the entry data displayed on-template.

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/
Don Chambers
Regular
Posts: 3657
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

Thanks Garvin. This accomplishes my objective..... but is it the best approach? EDIT: Needed to make a slight change, so post has been updated to reflect that. Most concerned about my use of gloabal for $save_data and $meta_title, which seems to be the only way I can used these in both the genpage and frontend_header cases. This code is not the entire function - only the part I am concerned about.

Code: Select all

        function event_hook($event, &$bag, &$eventData, &$addlData) {
        global $serendipity, $save_title, $meta_title;

        $hooks = &$bag->get('event_hooks');

        if (isset($hooks[$event])) {
            switch($event) {
                case 'genpage':
                    // The 'genpage' hook is our last chance to modify Smarty
                    // variables before the template is called for the header.

                    // Only modify the title on single-entry pages
                    if ($addlData['view'] == 'entry')
                    {
                        // Get the properties for this entry
                        $myid = $serendipity['GET']['id'];
                        // Requires a database fetch, but the only other way
                        // get the entry properties is to wait until we
                        // generate the entry; by the time that hook is 
                        // called, the <title> tag has already been emitted.
                        // We need those properties now!
                        $property = serendipity_fetchEntryProperties($myid);
                        // Set a title, if one was defined for this entry
                        if (!empty($property['meta_head_title'])) {
                            // Make the variable a little less unwieldy
                            $meta_title = $property['meta_head_title'];
                            $save_title=$serendipity['head_title'];
                            $serendipity['head_title'] = htmlspecialchars($meta_title);
                            // Clear the subtitle (many templates use it along with the title)
                            $serendipity['head_subtitle'] = '';
                        }
                    }
                    return true;
                    break;
                case 'frontend_header':
                    $default_description = $this->get_config('default_description');
                    $default_keywords = $this->get_config('default_keywords');

                    if ($serendipity['GET']['id'] && isset($GLOBALS['entry'][0]['body'])) {
                        // Only emit in Single Entry Mode

                        if (!empty($meta_title)) {
                            // if we do have an entry-specific title element,
                            // set smarty variables for banner to normal "entry title - blog description"
                            // because we modified head_title and blanked out head_subtitle in genpage to get custom title element
                            // but do not want those values in our banner
                            $serendipity['smarty']->assign(
                                array(
                                'head_title'     => $save_title,
                                'head_subtitle' => $serendipity['smarty']->get_template_vars('blogTitle')
                                )
                            );
                        }
=Don=
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

Actually, that's about the perfect solution. Saving the old value is a tried-and-true programming trick -- hardly worth calling a trick.

And the $serendipity['smarty']->assign() is something I tried in one of my earlier attempts. It worked, but assigning the variable directly in genpage was more elegant (after genpage, the variables get copied with exactly that same code in the s9y core anyway). I admit it looks clunky, but it's reliable and won't be a huge performance hog.
Judebert
---
Website | Wishlist | PayPal
Don Chambers
Regular
Posts: 3657
Joined: Mon Feb 13, 2006 2:40 am
Location: Chicago, IL, USA
Contact:

Post by Don Chambers »

I'm too tired to go into specifcs right now, but Judebert and I were on the telephone this evening for several hours and probably have a final solution to this matter..... I'll review everything one last time tomorrow (wednesday) and post back. Just wanted to thank everyone for their input!!!!!
=Don=
Post Reply