Go Back   vb.org Archive > vBulletin 4 Discussion > vB4 Programming Discussions
  #1  
Old 07-01-2011, 02:37 PM
Diblo Dk Diblo Dk is offline
 
Join Date: Jun 2011
Posts: 6
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default Custom template tags

How do I add a custom template tags; {vb:tag}.?
Reply With Quote
  #2  
Old 07-01-2011, 05:01 PM
kh99 kh99 is offline
 
Join Date: Aug 2009
Location: Maine
Posts: 13,185
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

I'm not sure because I've never done it, but includes/template_curly_defs.php seems to have a bunch of classes, one for each type of curly tag, all derived from class vB_TemplateParser_Curly (which is also in that file), and the classes are used in includes/class_template_parser.php, with the class name built from the tag name. So maybe if you did something like:

Code:
require_once("includes/template_curly_defs.php");

class vB_TemplateParser_CurlyFoo extends vB_TemplateParser_Curly
{
    public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
    {
        // some code            
    }
    public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
    {
        //more code
    }
}

then somehow get that included before the template parser is called. (ETA: actually, I'm not sure if you even need to include the base class before defining a subclass, or include the class def before using it).

--------------- Added [DATE]1309550427[/DATE] at [TIME]1309550427[/TIME] ---------------

Got curious so decided to try it - the answer to both the above questions is "yes", you do need those things defined before they're used. So I used this code at hook admin_global:

Code:
require_once("includes/template_curly_defs.php");

class vB_TemplateParser_CurlyFoo extends vB_TemplateParser_Curly
{
    public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
    {
        return array();
    }
    public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
    {
        return "Foo";
    }
}

and then putting {vb:Foo} in a template resulted in Foo being inserted at that point. Of course the validate function should check the arguments and the compile function will probably do something more complicated, but you can look at the existing classes to figure that out.

On a side note, you know what turns out to be a bad idea? Creating a plugin using hook admin_global that has an error in it. I had to go to the database and edit the datastore value before I could get back to the plugin manager. ETA: but now that I think about it, it would have been easier just to temporarily comment out the fetch_hook call.
Reply With Quote
  #3  
Old 07-02-2011, 08:08 AM
Diblo Dk Diblo Dk is offline
 
Join Date: Jun 2011
Posts: 6
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

It works.

Can you help with why that I get this error?

Code:
Warning: Invalid argument supplied for foreach() in [path]/includes/functions.php on line 3433

The following error occurred when attempting to evaluate this template:
%1$s
This is likely caused by a malformed conditional statement. It is highly recommended that you fix this error before continuing, but you may continue as-is if you wish.

Template: (vbcms_page)
HTML Code:
...
{vb:raw footer}
{vb:jsinline header.js}
</body>
</html>

Template: (header.js)
HTML Code:
test

Plugin: (JavaScript templates - Hook: admin_global)
PHP Code:
require_once(DIR '/includes/template_curly_defs.php');

class 
vB_TemplateParser_CurlyJsinline extends vB_TemplateParser_Curly
{
    public static function 
validate(vB_Node $main_nodevB_TemplateParser $parser)
    {
        
$errors = array();

        if (!
array_key_exists(0$main_node->attributes))
        {
            
$errors[] = 'no_variable_specified';
        }

        return 
$errors;
    }

    public static function 
compile(vB_Node $main_nodevB_TemplateParser $parser)
    {
        
$output '';

        foreach (
$main_node->attributes AS $template)
        {
            if ( 
strripos($template'.js') )
            {
                
$output .= vB_Template::create($template)->render();
            }
        }

        return 
$output;
    }


Plugin: (Cache javaScript templates - Hook: cache_templates)
PHP Code:
$cache[] = 'header.js'

--------------- Added [DATE]1309599418[/DATE] at [TIME]1309599418[/TIME] ---------------

Yesterday I remove the error without solving the problem by adding to the $output 'Test', but it does not work today. The $output contains comments with the template name.

I can only see that it would be the wrong hook to do both things.
Reply With Quote
  #4  
Old 07-02-2011, 09:26 AM
kh99 kh99 is offline
 
Join Date: Aug 2009
Location: Maine
Posts: 13,185
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

I was just figuring out the same thing. As it turns out, the compile function is supposed to return php code that results in a string. I think maybe my example worked by accident because a single word is a 'bare word' that gets interpreted as a string. So sorry about that.

So I changed your compile function to be like this:

Code:
    public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
    {
        $output = "'";

        foreach ($main_node->attributes AS $template)
        {
            if ( strripos($template, '.js') )
            {
                $output .= vB_Template::create($template)->render();
            }
        }

        return $output . "'";
    }

and the error goes away, but there's still no output. I get this in the output:

Code:
<!-- BEGIN TEMPLATE: headerjs -->
 
<!-- END TEMPLATE: headerjs -->

as you pointed out. I don't know know why the '.' is missing from the template name.

At this point I'm confused about what's going on.

BTW, you probably know that your tag code only runs when the template is compiled, so if you use that code to insert another template then that other template gets changed, it won't be reinserted unless you go back and edit the template with the tag. Maybe what you want to do is something like some of the other curly tag functions do - insert a call to a function that will render the .js template, then it will be called when template with the jsinline tag is rendered.

ETA: actually that seems to work, although I don't really understand why. This is what I ended up with:

Code:
require_once(DIR . '/includes/template_curly_defs.php');

class vB_TemplateParser_CurlyJsinline extends vB_TemplateParser_Curly
{
    public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
    {
        $errors = array();
        if (!array_key_exists(0, $main_node->attributes))
        {
            $errors[] = 'no_variable_specified';
        }

        return $errors;
    }

    public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
    {
        $output = '';

        foreach ($main_node->attributes AS $template)
        {
            if ( strripos($template, '.js') )
            {
                $output .= 'vB_Template::create(\'' . $template . '\')->render()';
            }
        }

        return $output;
    }
}
Reply With Quote
  #5  
Old 07-02-2011, 01:19 PM
Diblo Dk Diblo Dk is offline
 
Join Date: Jun 2011
Posts: 6
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Yes you are absolutely right.
If we also look in the file template_curly_defs.php we can see that they all return a php code.

If you look after vB_Template and vB_Template_Runtime in file class_core.php it becomes really exciting and I found the solution with the template comment is to send the value true with the render.

PHP Code:
$output .= 'vB_Template::create("'.$template.'")->render(True)'
--------------- Added [DATE]1309619386[/DATE] at [TIME]1309619386[/TIME] ---------------

Or just use fetch_template_raw.

PHP Code:

$output 
.= '(($GLOBALS[\'vbulletin\']->options[\'addtemplatename\']) ? "/* TEMPLATE: '.$template.' */\n" : "").vB_Template::fetch_template_raw(\''.$template.'\')'
Reply With Quote
  #6  
Old 07-03-2011, 05:36 PM
Diblo Dk Diblo Dk is offline
 
Join Date: Jun 2011
Posts: 6
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Can you tell what brings escaped to the lead sentence in header.js?
- I have no problems with header.css template.

--------------- Added [DATE]1309718238[/DATE] at [TIME]1309718238[/TIME] ---------------

PHP Code:
require_once(DIR '/includes/template_curly_defs.php');

class 
vB_TemplateParser_CurlyJsinline extends vB_TemplateParser_Curly
{
    public static function 
validate(vB_Node $main_nodevB_TemplateParser $parser)
    {
        
$errors = array();

        if (!
array_key_exists(0$main_node->attributes))
        {
            
$errors[] = 'no_variable_specified';
        }

        return 
$errors;
    }

    public static function 
compile(vB_Node $main_nodevB_TemplateParser $parser)
    {
        global 
$vbulletin;
        
$output '';

        foreach (
$main_node->attributes AS $template)
        {
            if ( 
strripos($template'.js') )
            {
                if (
$vbulletin->options['addtemplatename'])
                {
                    
$output .= '"\n/* TEMPLATE: '.$template.' */\n".';
                }
                
$output .= 'vB_Template::fetch_template_raw("'.$template.'").';
            }
        }
        return 
'\'\';$final_rendered .= '.$output.'""';
    }
}

class 
vB_TemplateParser_CurlyCssinline extends vB_TemplateParser_Curly
{
    public static function 
validate(vB_Node $main_nodevB_TemplateParser $parser)
    {
        
$errors = array();

        if (!
array_key_exists(0$main_node->attributes))
        {
            
$errors[] = 'no_variable_specified';
        }

        return 
$errors;
    }

    public static function 
compile(vB_Node $main_nodevB_TemplateParser $parser)
    {
        global 
$vbulletin;
        
$output '';

        foreach (
$main_node->attributes AS $template)
        {
            if ( 
strripos($template'.css') )
            {
                if (
$vbulletin->options['addtemplatename'])
                {
                    
$output .= '"\n/* TEMPLATE: '.$template.' */\n".';
                }
                
$output .= 'vB_Template::fetch_template_raw("'.$template.'").';
            }
        }

        return 
'\'\';$final_rendered .= preg_replace(\'#@charset .*#i\', \'\', '.$output.'"")';
    }

--------------- Added [DATE]1309718689[/DATE] at [TIME]1309718689[/TIME] ---------------

Tempate: header.css
Code:
#quick7{background:url("image.png") no-repeat}

Tempate: header.js
Code:
var test="";

Tempate: vbcms_page
Code:
...
<style type="text/css">/*<![CDATA[*/ <!-- {vb:cssinline header.css} --> /*]]>*/</style> 
</head>
<body>

...

<script type="text/javascript">/*<![CDATA[*/ <!--
{vb:jsinline header.js}
// --> /*]]>*/</script>
</body>
</html>
Reply With Quote
  #7  
Old 07-03-2011, 06:03 PM
kh99 kh99 is offline
 
Join Date: Aug 2009
Location: Maine
Posts: 13,185
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

I'm not sure - are you saying that you need the javascript to be escaped? There is already a class vB_TemplateParser_CurlyEscapeJS class in template_curly_defs.php for escaping javascript, it inserts this:

PHP Code:
return 'vB_Template_Runtime::escapeJS(' .$arguments ')'
Reply With Quote
  #8  
Old 07-04-2011, 08:58 AM
Diblo Dk Diblo Dk is offline
 
Join Date: Jun 2011
Posts: 6
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Forget about that question.

Can you find a hook for this code? - or equivalent.
PHP Code:
class vB_Template_Runtime_template extends vB_Template_Runtime
{
    
/**
     * @param array
     * @return string
     */
    
public static function jsinline($templater)
    {
        global 
$vbulletin;
        
$comments = array();
        
$output = array();

        
$i=0;
        foreach (
$templater AS $template)
        {
            
$comments[$i] = "\n/* TEMPLATE: $template */\n";
            
$i++;
            
$output[$i] = vB_Template::create($template)->render(true);
            
$i++;
        }

        
$output str_replace(array("\r""\n""\t"), ''preg_replace('/\/\*((?!\*\/).*?)\*\//s'''$output));

        if (
$vbulletin->options['addtemplatename'])
        {
            
$output =  $comments $output;
            
ksort($output);
        }

        return 
implode(''$output);
    }

    
/**
     * @param array
     * @return string
     */
    
public static function cssinline($templater)
    {
        global 
$vbulletin;
        
$comments = array();
        
$output = array();

        
$i=0;
        foreach (
$templater AS $template)
        {
            
$comments[$i] = "\n/* TEMPLATE: $template */\n";
            
$i++;
            
$output[$i] = vB_Template::create($template)->render(true);
            
$i++;
        }

        
$output str_replace(array("\r""\n""\t"), ''preg_replace(array('/@charset .*/i''/\/\*((?!\*\/).*?)\*\//s''/\s[\s]+/s'), array(''''' '), $output));

        if (
$vbulletin->options['addtemplatename'])
        {
            
$output =  $comments $output;
            
ksort($output);
        }

        return 
implode(''$output);
    }



You know this code.
Hook: admin_global
PHP Code:
require_once(DIR '/includes/template_curly_defs.php');

class 
vB_TemplateParser_CurlyJsinline extends vB_TemplateParser_Curly
{
    public static function 
validate(vB_Node $main_nodevB_TemplateParser $parser)
    {
        
$errors = array();

        if (!
array_key_exists(0$main_node->attributes))
        {
            
$errors[] = 'no_variable_specified';
        }

        return 
$errors;
    }

    public static function 
compile(vB_Node $main_nodevB_TemplateParser $parser)
    {
        
$output = array();

        foreach (
$main_node->attributes AS $template)
        {
            if ( 
strripos($template'.js') )
            {
                
$output[] = $template;
            }
        }

        return 
'vB_Template_Runtime_template::jsinline(array("'.implode('","'$output).'"))';
    }
}

class 
vB_TemplateParser_CurlyCssinline extends vB_TemplateParser_Curly
{
    public static function 
validate(vB_Node $main_nodevB_TemplateParser $parser)
    {
        
$errors = array();

        if (!
array_key_exists(0$main_node->attributes))
        {
            
$errors[] = 'no_variable_specified';
        }

        return 
$errors;
    }

    public static function 
compile(vB_Node $main_nodevB_TemplateParser $parser)
    {
        
$output = array();

        foreach (
$main_node->attributes AS $template)
        {
            if ( 
strripos($template'.css') )
            {
                
$output[] = $template;
            }
        }

        return 
'vB_Template_Runtime_template::cssinline(array("'.implode('","'$output).'"))';
    }

--------------- Added [DATE]1309782484[/DATE] at [TIME]1309782484[/TIME] ---------------

Quote:
At this point I'm confused about what's going on.

BTW, you probably know that your tag code only runs when the template is compiled, so if you use that code to insert another template then that other template gets changed, it won't be reinserted unless you go back and edit the template with the tag. Maybe what you want to do is something like some of the other curly tag functions do - insert a call to a function that will render the .js template, then it will be called when template with the jsinline tag is rendered.
vBulletin builds a list of work to be done and then send it to eval(), it is reasons why I can not send a text and make template before it is done.
So I have change when to call the template create and it has solved template tags in the named templates and escapes. As you pointed out.

--------------- Added [DATE]1309783945[/DATE] at [TIME]1309783945[/TIME] ---------------

Answers to your questions above is that there were problems with 'var test="";' was print out as 'var test=\"\";'. But it is solved with the new code.

--------------- Added [DATE]1309802492[/DATE] at [TIME]1309802492[/TIME] ---------------

Plugin is finished so I close the post.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 05:08 PM.


Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2024, vBulletin Solutions Inc.
X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.04063 seconds
  • Memory Usage 2,325KB
  • Queries Executed 13 (?)
More Information
Template Usage:
  • (1)SHOWTHREAD
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (1)ad_showthread_beforeqr
  • (1)ad_showthread_firstpost
  • (1)ad_showthread_firstpost_sig
  • (1)ad_showthread_firstpost_start
  • (9)bbcode_code
  • (2)bbcode_html
  • (8)bbcode_php
  • (1)bbcode_quote
  • (1)footer
  • (1)forumjump
  • (1)forumrules
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (1)navbar
  • (3)navbar_link
  • (120)option
  • (8)post_thanks_box
  • (8)post_thanks_button
  • (1)post_thanks_javascript
  • (1)post_thanks_navbar_search
  • (8)post_thanks_postbit_info
  • (8)postbit
  • (8)postbit_onlinestatus
  • (8)postbit_wrapper
  • (1)spacer_close
  • (1)spacer_open
  • (1)tagbit_wrapper 

Phrase Groups Available:
  • global
  • inlinemod
  • postbit
  • posting
  • reputationlevel
  • showthread
Included Files:
  • ./showthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/functions_bigthree.php
  • ./includes/class_postbit.php
  • ./includes/class_bbcode.php
  • ./includes/functions_reputation.php
  • ./includes/functions_post_thanks.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_postinfo_query
  • fetch_postinfo
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • showthread_start
  • showthread_getinfo
  • forumjump
  • showthread_post_start
  • showthread_query_postids
  • showthread_query
  • bbcode_fetch_tags
  • bbcode_create
  • showthread_postbit_create
  • postbit_factory
  • postbit_display_start
  • post_thanks_function_post_thanks_off_start
  • post_thanks_function_post_thanks_off_end
  • post_thanks_function_fetch_thanks_start
  • post_thanks_function_fetch_thanks_end
  • post_thanks_function_thanked_already_start
  • post_thanks_function_thanked_already_end
  • fetch_musername
  • postbit_imicons
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • postbit_display_complete
  • post_thanks_function_can_thank_this_post_start
  • tag_fetchbit_complete
  • forumrules
  • navbits
  • navbits_complete
  • showthread_complete