Coded something up in Couch in an interesting way? Have a snippet or shortcode to share? Post it here for the community to benefit.
17 posts Page 2 of 2
Tomarnst wrote: mmm.... that should not be the case also those hidden ones should be clear for someone who doesn't read the source files.

I must correct myself then. In reality, CouchCMS doesn't have anything hidden - only undocumented :)
Snippets, on the contrary, have samples of usage, detailed explanation and a list of all parameters used in code. In fact, anyone can read couch code and see what is going on there without any php involved.
Seeing @trendoman's interest in using embeds behave as functions, I have created something that might make things a tad easier.

The current version of Couch from GitHub (https://github.com/CouchCMS/CouchCMS) now offers two new tags - <cms:func /> and <cms:call />.

Anyone willing to try out how the tags work, assuming you have the current GitHub version installed, try placing the following in any of your test template -

1.
Code: Select all
    <cms:func 'makecoffee' type='cappuccino' >
        Making a cup of <cms:show type />.<br />
    </cms:func>

    <cms:call 'makecoffee' />
    <cms:call 'makecoffee' '' />
    <cms:call 'makecoffee' 'espresso' />

Output:
Making a cup of cappuccino.
Making a cup of .
Making a cup of espresso.

As you can see, the <cms:func> defines a function named 'makecoffee' which accepts an optional single parameter named 'type'.
The <cms:call /> statements that follow show how the function can be invoked. Please note how the default value of 'type' is used when the function is called without any parameter.

2.
Code: Select all
    <cms:func 'makecoffee2' type='cappuccino' size='medium'>
        Making a <cms:show size /> cup of <cms:show type />.<br />
    </cms:func>

    <cms:call 'makecoffee2' />
    <cms:call 'makecoffee2' 'espresso' 'large' />
    <cms:call 'makecoffee2' size='small' type='espresso' />

Output:
Making a medium cup of cappuccino.
Making a large cup of espresso.
Making a small cup of espresso.

The next example above defines another function (named 'makecoffee2') that takes two parameters - 'type' and 'size'.
Please note the third <cms:call> statement above - it shows how we can pass parameters to the function in any order by explicitly using their names. If names are not used with the parameters then they have to be passed in strictly the same order as that defined by the function being called, as shown by the second <cms:call /> (i.e. first 'type' and then 'size').

3.
Code: Select all
    <cms:func 'recursion' count='0'>
        <cms:if count lt '20'>
            count: <cms:show count /><br>
            <cms:call 'recursion' "<cms:add count '1' />" />
        </cms:if>
    </cms:func>

    <cms:call 'recursion' />

Output:
count: 0
count: 1
count: 2
count: 3
count: 4
count: 5
..
..


Hopefully the simple examples above should be sufficient to illustrate how we can use <cms:func /> for creating resusable chunks of code.

I'd like to stress one point about <cms:func /> here - every parameter we define for it needs to have a default value (it may be blank but it has to be present) e.g. the following is incorrect
Code: Select all
    <cms:func 'makecoffee' type >

Following is the right syntax if the parameter has no visible default value -

Code: Select all
    <cms:func 'makecoffee' type='' >

Finally, you might find it more manageable to put all functions (or groups of related functions) as snippets e.g. I could create a snippet named 'funcs.html' as follows (the cms:hide allows me to freely use text as comments) -

Code: Select all
    <cms:hide>
        <!-- makes coffee (what else did you expect?) -->
        <cms:func 'makecoffee' type='cappuccino' >
            Making a cup of <cms:show type />.<br />
        </cms:func>

        <!-- make coffee version 2 -->
        <cms:func 'makecoffee2' type='cappuccino' size='medium'>
            Making a <cms:show size /> cup of <cms:show type />.<br />
        </cms:func>

        <!-- look Ma! I can recurse! -->
        <cms:func 'recursion' count='0'>
            <cms:if count lt '20'>
                count: <cms:show count /><br>
                <cms:call 'recursion' "<cms:add count '1' />" />
            </cms:if>
        </cms:func>
    </cms:hide>

And now my test template could embed the snippet somewhere at its beginning -

Code: Select all
    <cms:embed 'funcs.html' />

and then call the functions as usual -

Code: Select all
    <cms:call 'makecoffee' />
    <cms:call 'makecoffee' '' />
    <cms:call 'makecoffee' 'espresso' />

    <cms:call 'makecoffee2' />
    <cms:call 'makecoffee2' 'espresso' 'large' />
    <cms:call 'makecoffee2' size='small' type='espresso' />

    <cms:call 'recursion' />

Hope this helps.
Thanks, @KK.

8. A function that returns a remote page via server's cURL extension ( version with full cookie support viewtopic.php?f=8&t=11368&p=30503#p30503 ):

Code: Select all
<cms:func 'remote_url' url=k_site_link><cms:ignore>
   
        // Sample usage: <cms:call 'remote_url' url="https://www.couchcms.com/" />
   
    </cms:ignore>
    <cms:php>
        if( extension_loaded('curl') ){
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, "<cms:show url />" );
            curl_setopt($ch, CURLOPT_USERAGENT, 'CouchCMS <cms:show k_cms_version />');
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $output = curl_exec($ch);
            curl_close($ch);
            echo $output;
        }
    </cms:php>
</cms:func>


Example 1. Output some remote url's content:
Code: Select all
<cms:abort>
    <cms:call 'remote_url' url="https://www.couchcms.com/" />
</cms:abort>


Example 2. Show latest 5 commits for CouchCMS repo on GitHub:
Code: Select all
<cms:capture into='commits' is_json='1' >
    <cms:call 'remote_url' url='https://api.github.com/repos/CouchCMS/CouchCMS/commits?per_page=5' />
</cms:capture>

<cms:each commits as='entry' startcount='1'>
    <cms:html_encode>
        <cms:date date=entry.commit.committer.date format='j M' />: <cms:show entry.commit.message />
    </cms:html_encode>
    <br/>
</cms:each>


Output as of today:
20 Mar: Fix json in advanced relations
20 Mar: Add 'adjust' param to cms:pages (for non-uniform pagination needs)
19 Mar: Add tag <cms:func_exists>
17 Mar: Add setting repeatable-regions using JSON in DataBound Forms
16 Mar: Add tags <cms:func> and <cms:call>
Nice :)
9. A function for extended search by page titles with support of patterns and wildcards.

Code: Select all
<cms:func 'search_by_title' masterpage=k_template_name key='*' strictly='0' 
          orderby='page_title' order='asc' limit='1000'
          show_unpublished='0' show_future_entries='0'
          return_sql='0' condition='' sql=''><cms:ignore>
       
            // 1. Builds an sql query to search for pages by title.
            // 2. Returns either query results or query itself (return_sql = '1')       
            //
            // Samples:
            //
            //
            // b (exactly). Such cases should be handled by parameter strictly='1' instead!
            // <cms:call 'search_by_title' masterpage='data.php, index.php' key='b' />
            //
            // b* (starts with 'b')
            // <cms:call 'search_by_title' masterpage='data.php, index.php' key='b*' />
            //
            // *b (ends with 'b')
            // <cms:call 'search_by_title' masterpage='data.php, index.php' key='*b' />
            //
            // *b* (has 'b' somewhere)
            // <cms:call 'search_by_title' masterpage='data.php, index.php' key='*b*' />
            //
            // b**** (5-letter word, starting with 'b')
            // <cms:call 'search_by_title' masterpage='data.php, index.php' key='b****' />   
            //
            // ***b (4-letter word ending with 'b')
            // <cms:call 'search_by_title' masterpage='data.php, index.php' key='***b' />   
   
    </cms:ignore>
   
    <cms:ignore> // fool-proof empty values to avoid freaking sql errors.</cms:ignore>
    <cms:if "<cms:not masterpage />" ><cms:set masterpage = k_template_name scope='parent'/></cms:if>
    <cms:if "<cms:not orderby />" ><cms:set orderby = 'page_title' scope='parent'/></cms:if>
    <cms:if "<cms:not order />" ><cms:set order = 'asc' scope='parent'/></cms:if>
   
    <cms:php>
        global $DB, $CTX;
       
        $text = $CTX->get('key');
        $need_like_expr = !$CTX->get('strictly');
       
        if( $need_like_expr ){
            $pattern = '/\*{2,}+/'; // multiple '*' go to _underscore '_'
       
            $text = preg_replace_callback(
                            $pattern,
                            function($match) {
                                for( $x=0; $x<strlen($match[0]); $x++ ){ $str .= '_'; }
                                return $str;
                            },   
                            $text
            );
        }
                                                                 
        $text = str_replace('*', '%', $text); // single '*' goes to '%'
        $CTX->set( 'key', $DB->sanitize( $text ), 'parent' );
       
    </cms:php>
   
    <cms:capture into='condition' scope='parent'>
        <cms:if strictly = '1' >
        p.page_title = '<cms:show key />'
        <cms:else />
        p.page_title LIKE '<cms:show key />'
        </cms:if>   
    </cms:capture>
   
   
    <cms:capture into='sql' scope='parent'>
        SELECT p.id AS `k_page_id`, p.page_title AS `k_page_title`, p.page_name AS `k_page_name`
        FROM <cms:php>echo K_TBL_PAGES;</cms:php> p
        INNER JOIN <cms:php>echo K_TBL_TEMPLATES;</cms:php> t ON t.id = p.template_id
        WHERE t.name IN (<cms:each masterpage as='tpl' sep=','>'<cms:show tpl />'<cms:if "<cms:not k_last_item />" >,</cms:if></cms:each>)
        AND <cms:show condition />
        AND p.parent_id=0
        <cms:if "<cms:not show_future_entries />" >AND p.publish_date < '<cms:date format="Y-m-d H:i:s" />' </cms:if>
        <cms:if "<cms:not show_unpublished />">AND NOT p.publish_date = '0000-00-00 00:00:00'    </cms:if>
        ORDER BY p.<cms:show orderby /> <cms:show order />
    </cms:capture>
   
   
    <cms:if "<cms:not return_sql />" ><cms:ignore>
       
            // Run query    </cms:ignore>
       
        <cms:query sql=sql limit=limit >
            <cms:ignore>
               
                // Tweak html for the output below     </cms:ignore>
           
            <cms:ignore>#############################################</cms:ignore>
           
            <cms:if k_paginated_top><h3>Total pages found: <cms:show k_total_records /></h3></cms:if>
            <cms:show k_count />: <cms:show k_page_title /> (id#<cms:show k_page_id />)<br/>
           
            <cms:no_results>
                <h3>Nuthin, sry..</h3>
            </cms:no_results>
           
            <cms:ignore>#############################################</cms:ignore>
           
           
        </cms:query>
       
    <cms:else /><cms:ignore>
       
            // Or show query    </cms:ignore>   
       
        <cms:nl2br>
            <cms:show sql />
        </cms:nl2br>
       
    </cms:if>
   
</cms:func>


Sample use:
Code: Select all
<h1>TESTS:</h1>
<p>Try on template(s) with a lot of pages.</p>       
       
<cms:nl2br>
       
            // b* (starts with 'b')
   
</cms:nl2br>
<cms:call 'search_by_title' key='b*' /><hr/>

<cms:nl2br>
       
            // *b (ends with 'b')
   
</cms:nl2br>
<cms:call 'search_by_title' key='*b' /><hr/>

<cms:nl2br>
       
            // *b* (has 'b' anywhere)
   
</cms:nl2br>
<cms:call 'search_by_title' key='*b*' /><hr/>

<cms:nl2br>
       
            // b**** (5-letter word, starting with 'b')
   
</cms:nl2br>
<cms:call 'search_by_title' key='b****' /><hr/>

<cms:nl2br>
       
            // ***b (4-letter word ending with 'b')
   
</cms:nl2br>
<cms:call 'search_by_title' key='***b' /><hr/>

<cms:nl2br>
       
            // b (exactly). Such cases are better (faster) handled by adding parameter: strictly='1'
   
</cms:nl2br>
<cms:call 'search_by_title' key='b' /><hr/>


Regards
10. A function that gets a remote url, with support of logged-in user's cookie (if used on the same domain)

This is an extension of previous code to make sure requests are done in the name of current user. Also a new option is available - fake_ajax, which helps to make a request as if it was done via ajax.

Code: Select all

<cms:func 'remote_url' url=k_page_link fake_ajax='0'><cms:ignore>
   
        // Sample usage:
        //  <cms:call 'remote_url' url="https://www.couchcms.com/" />
        //  <cms:call 'remote_url' url=k_site_link />
        //  <cms:call 'remote_url' url=k_template_link />
        //  <cms:call 'remote_url' url=k_page_link fake_ajax='1' />
        //  <cms:call 'remote_url' url="<cms:link masterpage='index.php' />" />
   
    </cms:ignore>
    <cms:if "<cms:not url />"><cms:set url=k_page_link /></cms:if>
    <cms:php>
        $url = "<cms:show url />";
        if( extension_loaded('curl') ){
            global $DB;
       
            session_write_close();
            $DB->commit( 1 );
       
            $http_header = array();
            $http_header[] = "Expect:";
            $http_header[] = "Accept: */*";
            if( "<cms:show fake_ajax />" ) 
            $http_header[] = "X-Requested-With: XMLHttpRequest";         
       
            $ch = curl_init();
       
            // include cookies only for internal link
            $internal_link = ( strpos($url, K_SITE_URL)===0 ) ? 1 : 0;
       
            if( $internal_link ){
                $cookie = array();
                foreach( $_COOKIE as $key => $value ){
                    if( $key != 'Array' )  $cookie[] = $key . '=' . $value;
                }
                $cookies = implode("; ", $cookie);
       
                curl_setopt( $ch, CURLOPT_COOKIE, $cookies );
            }
       
            curl_setopt($ch, CURLOPT_URL, $url );
            curl_setopt($ch, CURLOPT_REFERER, "<cms:show k_page_link />");
            curl_setopt($ch, CURLOPT_USERAGENT, 'CouchCMS <cms:show k_cms_version />');
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $http_header);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_TIMEOUT, 1);
            $output = curl_exec($ch);
            curl_close($ch);
            echo $output;
       
            session_start();
        }
    </cms:php>
</cms:func>

<cms:call 'remote_url' url="<cms:link masterpage='index.php' />" fake_ajax='1' />


It is helpful in connection to this topic viewtopic.php?f=8&t=11459
Regards
11. A function encodeURIComponent that should work as in Javascript

Code: Select all
<cms:func 'encodeURIComponent' str=''><cms:ignore>
   
        // A bit of JS in PHP
        // Sample: <cms:call 'encodeURIComponent' str=nonce />

    </cms:ignore>
    <cms:php>
        global $CTX;
        $revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
        echo strtr(rawurlencode( $CTX->get('str') ), $revert);
    </cms:php>
</cms:func>
17 posts Page 2 of 2

Who is online

In total there are 2 users online :: 0 registered, 0 hidden and 2 guests
(based on users active over the past 5 minutes)

Users browsing this forum: No registered users and 2 guests