smarty help

Skinning and designing Serendipity (CSS, HTML, Smarty)
Post Reply
carl_galloway
Regular
Posts: 1331
Joined: Sun Dec 04, 2005 5:43 pm
Location: Andalucia, Spain
Contact:

smarty help

Post by carl_galloway »

Hi all,

I'm helping another user to customise my carl blue theme, we've changed the entries.tpl back to the default method, rather than my custom version, so now of course the entries that were posted on the same day all appear grouped. This is fine, but we were wondering if its possible to add a dividing line between these entries only, ie not between dates, just between entries of the same date. Here is the complete entries.tpl

Code: Select all

<!-- ENTRIES START -->
    {serendipity_hookPlugin hook="entries_header" addData="$entry_id"}

    {foreach from=$entries item="dategroup"}
    <div class="serendipity_Entry_Date">
        {if $dategroup.is_sticky}
        <h3 class="serendipity_date">{$CONST.STICKY_POSTINGS}</h3>
        {else}
        <h3 class="serendipity_date">{$dategroup.date|@formatTime:DATE_FORMAT_ENTRY}</h3>
        {/if}

        {foreach from=$dategroup.entries item="entry"}
        <h4 class="serendipity_title"><a href="{$entry.link}">{$entry.title}</a></h4>

        <div class="serendipity_entry serendipity_entry_author_{$entry.author|@makeFilename} {if $entry.is_entry_owner}serendipity_entry_author_self{/if}">
            {if $entry.categories}
            <span class="serendipity_entryIcon">
            {foreach from=$entry.categories item="category"}
                {if $category.category_icon}
                    <a href="{$category.category_link}"><img class="serendipity_entryIcon" title="{$category.category_name|@escape}{$category.category_description|@emptyPrefix}" alt="{$category.category_name|@escape}" src="{$category.category_icon}" /></a>
                {/if}
            {/foreach}
            </span>
            {/if}

            <div class="serendipity_entry_body">
                {$entry.body}
            </div>

            {if $entry.is_extended}
            <div class="serendipity_entry_extended"><a id="extended"></a>{$entry.extended}</div>
            {/if}

            {if $entry.has_extended and not $is_single_entry and not $entry.is_extended}
            <br /><a href="{$entry.link}#extended">{$CONST.VIEW_EXTENDED_ENTRY|@sprintf:$entry.title}</a><br /><br />
            {/if}

            <div class='serendipity_entryFooter'>
                {$CONST.POSTED_BY} <a href="{$entry.link_author}">{$entry.author}</a>
                {if $entry.categories}
                   {$CONST.IN} {foreach from=$entry.categories item="category" name="categories"}<a href="{$category.category_link}">{$category.category_name|@escape}</a>{if not $smarty.foreach.categories.last}, {/if}{/foreach}
                {/if}

                {if $dategroup.is_sticky}
                    {$CONST.ON}
                {else}
                    {$CONST.AT}
                {/if} <a href="{$entry.link}">{if $dategroup.is_sticky}{$entry.timestamp|@formatTime:DATE_FORMAT_ENTRY} {/if}{$entry.timestamp|@formatTime:'%H:%M'}</a>

                {if $entry.has_comments}
                    {if $use_popups}
                        | <a href="{$entry.link_popup_comments}" onclick="window.open(this.href, 'comments', 'width=480,height=480,scrollbars=yes'); return false;">{$entry.label_comments} ({$entry.comments})</a>
                    {else}
                        | <a href="{$entry.link}#comments">{$entry.label_comments} ({$entry.comments})</a>
                    {/if}
                {/if}

                {if $entry.has_trackbacks}
                    {if $use_popups}
                        | <a href="{$entry.link_popup_trackbacks}" onclick="window.open(this.href, 'comments', 'width=480,height=480,scrollbars=yes'); return false;">{$entry.label_trackbacks} ({$entry.trackbacks})</a>
                    {else}
                        | <a href="{$entry.link}#trackbacks">{$entry.label_trackbacks} ({$entry.trackbacks})</a>
                    {/if}
                {/if}

                {if $entry.is_entry_owner and not $is_preview}
                        | <a href="{$entry.link_edit}">{$CONST.EDIT_ENTRY}</a>
                {/if}

                {$entry.add_footer}
            </div>
        </div>
        <!--
        <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
                 xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
                 xmlns:dc="http://purl.org/dc/elements/1.1/">
        <rdf:Description
                 rdf:about="{$entry.link_rdf}"
                 trackback:ping="{$entry.link_trackback}"
                 dc:title="{$entry.title}"
                 dc:identifier="{$entry.rdf_ident}" />
        </rdf:RDF>
        -->
        {$entry.plugin_display_dat}

        {if $is_single_entry and not $use_popups and not $is_preview}
            {if $CONST.DATA_UNSUBSCRIBED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_UNSUBSCRIBED|@sprintf:$CONST.UNSUBSCRIBE_OK}</div><br />
            {/if}

            {if $CONST.DATA_TRACKBACK_DELETED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_TRACKBACK_DELETED|@sprintf:$CONST.TRACKBACK_DELETED}</div><br />
            {/if}

            {if $CONST.DATA_TRACKBACK_APPROVED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_TRACKBACK_APPROVED|@sprintf:$CONST.TRACKBACK_APPROVED}</div><br />
            {/if}

            {if $CONST.DATA_COMMENT_DELETED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_COMMENT_DELETED|@sprintf:$CONST.COMMENT_DELETED}</div><br />
            {/if}

            {if $CONST.DATA_COMMENT_APPROVED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_COMMENT_APPROVED|@sprintf:$CONST.COMMENT_APPROVED}</div><br />
            {/if}

            <div class="serendipity_comments">
                <br />
                <a id="trackbacks"></a>
                <div class="serendipity_commentsTitle">{$CONST.TRACKBACKS}</div>
                    <div class="serendipity_center">
                        <a rel="nofollow" style="font-weight: normal" href="{$entry.link_trackback}" onclick="alert('{$CONST.TRACKBACK_SPECIFIC_ON_CLICK|@escape:htmlall}'); return false;" title="{$CONST.TRACKBACK_SPECIFIC_ON_CLICK|@escape}">{$CONST.TRACKBACK_SPECIFIC}</a>
                    </div>
                    <br />
                        {serendipity_printTrackbacks entry=$entry.id}
            </div>
        {/if}

        {if $is_single_entry and not $is_preview}
            <div class="serendipity_comments">
                <br />
                <a id="comments"></a>
                <div class="serendipity_commentsTitle">{$CONST.COMMENTS}</div>
                <div class="serendipity_center">{$CONST.DISPLAY_COMMENTS_AS}
                {if $entry.viewmode eq $CONST.VIEWMODE_LINEAR}
                    ({$CONST.COMMENTS_VIEWMODE_LINEAR} | <a href="{$entry.link_viewmode_threaded}#comments">{$CONST.COMMENTS_VIEWMODE_THREADED}</a>)
                {else}
                    (<a href="{$entry.link_viewmode_linear}#comments">{$CONST.COMMENTS_VIEWMODE_LINEAR}</a> | {$CONST.COMMENTS_VIEWMODE_THREADED})
                {/if}
                </div>
                <br />
                    {serendipity_printComments entry=$entry.id mode=$entry.viewmode}

                {if $entry.is_entry_owner}
                    {if $entry.allow_comments}
                    <div class="serendipity_center">(<a href="{$entry.link_deny_comments}">{$CONST.COMMENTS_DISABLE}</a>)</div>
                    {else}
                    <div class="serendipity_center">(<a href="{$entry.link_allow_comments}">{$CONST.COMMENTS_ENABLE}</a>)</div>
                    {/if}
                {/if}
                <a id="feedback"></a>

                {foreach from=$comments_messagestack item="message"}
                <div class="serendipity_center serendipity_msg_important">{$message}</div>
                {/foreach}

                {if $is_comment_added}

                <br />
                <div class="serendipity_center serendipity_msg_notice">{$CONST.COMMENT_ADDED}</div>

                {elseif $is_comment_moderate}

                <br />
                <div class="serendipity_center serendipity_msg_notice">{$CONST.COMMENT_ADDED}<br />{$CONST.THIS_COMMENT_NEEDS_REVIEW}</div>

                {elseif not $entry.allow_comments}

                <br />
                <div class="serendipity_center serendipity_msg_important">{$CONST.COMMENTS_CLOSED}</div>

                {else}

                <br />
                <div class="serendipity_commentsTitle">{$CONST.ADD_COMMENT}</div>
                {$COMMENTFORM}

                {/if}
            </div>
        {/if}

        {$entry.backend_preview}
        {/foreach}
    </div>
    {foreachelse}
    {if not $plugin_clean_page}
        {$CONST.NO_ENTRIES_TO_PRINT}
    {/if}
    {/foreach}

    <div class='serendipity_entryFooter' style="text-align: center">
    {if $footer_prev_page}
        <a href="{$footer_prev_page}">« {$CONST.PREVIOUS_PAGE}</a>  
    {/if}

    {if $footer_info}
        ({$footer_info})
    {/if}

    {if $footer_next_page}
        <a href="{$footer_next_page}">» {$CONST.NEXT_PAGE}</a>
    {/if}

    {serendipity_hookPlugin hook="entries_footer"}
    </div>
<!-- ENTRIES END -->
If anyone could help, that would be great, and we might see a 'carl reloaded' theme being published soon.

Thanks again,
Carl
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Re: smarty help

Post by garvinhicking »

This is actually pretty easy.

You only need to replace the "central" foreach loop from this:

Code: Select all

        {foreach from=$dategroup.entries item="entry"}
to this:

Code: Select all

        {foreach name="dategroup" from=$dategroup.entries item="entry"}
It is required to give that foreach loop a name, so that you can later access it as a Smarty variable.

Then, just before the closing {/foreach} of that loop, you can add this construct:

Code: Select all

        {if $smarty.foreach.dategroup.iteration > 1}
            <div class="multi"></div>
        {/if}
This accesses the iteration count of the entry loop, and if it's larger than 1, it will output a spacing "div". Then you can style that div with your CSS to produce a seperator.

The full entries.tpl would look like this:

Code: Select all

<!-- ENTRIES START -->
    {serendipity_hookPlugin hook="entries_header" addData="$entry_id"}

    {foreach from=$entries item="dategroup"}
    <div class="serendipity_Entry_Date">
        {if $dategroup.is_sticky}
        <h3 class="serendipity_date">{$CONST.STICKY_POSTINGS}</h3>
        {else}
        <h3 class="serendipity_date">{$dategroup.date|@formatTime:DATE_FORMAT_ENTRY}</h3>
        {/if}

        {foreach name="dategroup" from=$dategroup.entries item="entry"}
        <h4 class="serendipity_title"><a href="{$entry.link}">{$entry.title}</a></h4>

        <div class="serendipity_entry serendipity_entry_author_{$entry.author|@makeFilename} {if $entry.is_entry_owner}serendipity_entry_author_self{/if}">
            {if $entry.categories}
            <span class="serendipity_entryIcon">
            {foreach from=$entry.categories item="category"}
                {if $category.category_icon}
                    <a href="{$category.category_link}"><img class="serendipity_entryIcon" title="{$category.category_name|@escape}{$category.category_description|@emptyPrefix}" alt="{$category.category_name|@escape}" src="{$category.category_icon}" /></a>
                {/if}
            {/foreach}
            </span>
            {/if}

            <div class="serendipity_entry_body">
                {$entry.body}
            </div>

            {if $entry.is_extended}
            <div class="serendipity_entry_extended"><a id="extended"></a>{$entry.extended}</div>
            {/if}

            {if $entry.has_extended and not $is_single_entry and not $entry.is_extended}
            <br /><a href="{$entry.link}#extended">{$CONST.VIEW_EXTENDED_ENTRY|@sprintf:$entry.title}</a><br /><br />
            {/if}

            <div class='serendipity_entryFooter'>
                {$CONST.POSTED_BY} <a href="{$entry.link_author}">{$entry.author}</a>
                {if $entry.categories}
                   {$CONST.IN} {foreach from=$entry.categories item="category" name="categories"}<a href="{$category.category_link}">{$category.category_name|@escape}</a>{if not $smarty.foreach.categories.last}, {/if}{/foreach}
                {/if}

                {if $dategroup.is_sticky}
                    {$CONST.ON}
                {else}
                    {$CONST.AT}
                {/if} <a href="{$entry.link}">{if $dategroup.is_sticky}{$entry.timestamp|@formatTime:DATE_FORMAT_ENTRY} {/if}{$entry.timestamp|@formatTime:'%H:%M'}</a>

                {if $entry.has_comments}
                    {if $use_popups}
                        | <a href="{$entry.link_popup_comments}" onclick="window.open(this.href, 'comments', 'width=480,height=480,scrollbars=yes'); return false;">{$entry.label_comments} ({$entry.comments})</a>
                    {else}
                        | <a href="{$entry.link}#comments">{$entry.label_comments} ({$entry.comments})</a>
                    {/if}
                {/if}

                {if $entry.has_trackbacks}
                    {if $use_popups}
                        | <a href="{$entry.link_popup_trackbacks}" onclick="window.open(this.href, 'comments', 'width=480,height=480,scrollbars=yes'); return false;">{$entry.label_trackbacks} ({$entry.trackbacks})</a>
                    {else}
                        | <a href="{$entry.link}#trackbacks">{$entry.label_trackbacks} ({$entry.trackbacks})</a>
                    {/if}
                {/if}

                {if $entry.is_entry_owner and not $is_preview}
                        | <a href="{$entry.link_edit}">{$CONST.EDIT_ENTRY}</a>
                {/if}

                {$entry.add_footer}
            </div>
        </div>
        <!--
        <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
                 xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
                 xmlns:dc="http://purl.org/dc/elements/1.1/">
        <rdf:Description
                 rdf:about="{$entry.link_rdf}"
                 trackback:ping="{$entry.link_trackback}"
                 dc:title="{$entry.title}"
                 dc:identifier="{$entry.rdf_ident}" />
        </rdf:RDF>
        -->
        {$entry.plugin_display_dat}

        {if $is_single_entry and not $use_popups and not $is_preview}
            {if $CONST.DATA_UNSUBSCRIBED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_UNSUBSCRIBED|@sprintf:$CONST.UNSUBSCRIBE_OK}</div><br />
            {/if}

            {if $CONST.DATA_TRACKBACK_DELETED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_TRACKBACK_DELETED|@sprintf:$CONST.TRACKBACK_DELETED}</div><br />
            {/if}

            {if $CONST.DATA_TRACKBACK_APPROVED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_TRACKBACK_APPROVED|@sprintf:$CONST.TRACKBACK_APPROVED}</div><br />
            {/if}

            {if $CONST.DATA_COMMENT_DELETED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_COMMENT_DELETED|@sprintf:$CONST.COMMENT_DELETED}</div><br />
            {/if}

            {if $CONST.DATA_COMMENT_APPROVED}
                <br /><div class="serendipity_center serendipity_msg_notice">{$CONST.DATA_COMMENT_APPROVED|@sprintf:$CONST.COMMENT_APPROVED}</div><br />
            {/if}

            <div class="serendipity_comments">
                <br />
                <a id="trackbacks"></a>
                <div class="serendipity_commentsTitle">{$CONST.TRACKBACKS}</div>
                    <div class="serendipity_center">
                        <a rel="nofollow" style="font-weight: normal" href="{$entry.link_trackback}" onclick="alert('{$CONST.TRACKBACK_SPECIFIC_ON_CLICK|@escape:htmlall}'); return false;" title="{$CONST.TRACKBACK_SPECIFIC_ON_CLICK|@escape}">{$CONST.TRACKBACK_SPECIFIC}</a>
                    </div>
                    <br />
                        {serendipity_printTrackbacks entry=$entry.id}
            </div>
        {/if}

        {if $is_single_entry and not $is_preview}
            <div class="serendipity_comments">
                <br />
                <a id="comments"></a>
                <div class="serendipity_commentsTitle">{$CONST.COMMENTS}</div>
                <div class="serendipity_center">{$CONST.DISPLAY_COMMENTS_AS}
                {if $entry.viewmode eq $CONST.VIEWMODE_LINEAR}
                    ({$CONST.COMMENTS_VIEWMODE_LINEAR} | <a href="{$entry.link_viewmode_threaded}#comments">{$CONST.COMMENTS_VIEWMODE_THREADED}</a>)
                {else}
                    (<a href="{$entry.link_viewmode_linear}#comments">{$CONST.COMMENTS_VIEWMODE_LINEAR}</a> | {$CONST.COMMENTS_VIEWMODE_THREADED})
                {/if}
                </div>
                <br />
                    {serendipity_printComments entry=$entry.id mode=$entry.viewmode}

                {if $entry.is_entry_owner}
                    {if $entry.allow_comments}
                    <div class="serendipity_center">(<a href="{$entry.link_deny_comments}">{$CONST.COMMENTS_DISABLE}</a>)</div>
                    {else}
                    <div class="serendipity_center">(<a href="{$entry.link_allow_comments}">{$CONST.COMMENTS_ENABLE}</a>)</div>
                    {/if}
                {/if}
                <a id="feedback"></a>

                {foreach from=$comments_messagestack item="message"}
                <div class="serendipity_center serendipity_msg_important">{$message}</div>
                {/foreach}

                {if $is_comment_added}

                <br />
                <div class="serendipity_center serendipity_msg_notice">{$CONST.COMMENT_ADDED}</div>

                {elseif $is_comment_moderate}

                <br />
                <div class="serendipity_center serendipity_msg_notice">{$CONST.COMMENT_ADDED}<br />{$CONST.THIS_COMMENT_NEEDS_REVIEW}</div>

                {elseif not $entry.allow_comments}

                <br />
                <div class="serendipity_center serendipity_msg_important">{$CONST.COMMENTS_CLOSED}</div>

                {else}

                <br />
                <div class="serendipity_commentsTitle">{$CONST.ADD_COMMENT}</div>
                {$COMMENTFORM}

                {/if}
            </div>
        {/if}

        {$entry.backend_preview}

        {if $smarty.foreach.dategroup.iteration > 1}
            <div class="multi"></div>
        {/if}

        {/foreach}
    </div>
    {foreachelse}
    {if not $plugin_clean_page}
        {$CONST.NO_ENTRIES_TO_PRINT}
    {/if}
    {/foreach}

    <div class='serendipity_entryFooter' style="text-align: center">
    {if $footer_prev_page}
        <a href="{$footer_prev_page}">« {$CONST.PREVIOUS_PAGE}</a>  
    {/if}

    {if $footer_info}
        ({$footer_info})
    {/if}

    {if $footer_next_page}
        <a href="{$footer_next_page}">» {$CONST.NEXT_PAGE}</a>
    {/if}

    {serendipity_hookPlugin hook="entries_footer"}
    </div>
<!-- ENTRIES END --> 
HTH,
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/
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

I hate to gainsay Garvin, but it looks to me like that template will produce a "spacer" div after the second and greater entries, including the last one. In other words, the first and second entries will have no spacer, but the last one will have an additional spacer.

I'd like to recommend a different, albeit similar, solution. You'll still have to name the {foreach}, but you could use the Smarty "first" and "last" attributes -- http://smarty.php.net/manual/en/languag ... oreach.php -- of the foreach loop.

If you think a different bottom-border would be sufficient, you could do the job with template and CSS like the following:

Code: Select all

    {foreach name="dategroup" from=$dategroup.entries item="entry"}
        <h4 class="serendipity_title"><a href="{$entry.link}">{$entry.title}</a></h4>

        <div class="serendipity_entry serendipity_entry_author_{$entry.author|@makeFilename} {if $entry.is_entry_owner}serendipity_entry_author_self{/if} {if not $smarty.foreach.dategroup.last}entry_separator{/if}">
             ...
        </div>
        ...
    {/foreach}
Followed by CSS to provide a different bottom border, or extra margin:

Code: Select all

.entry_separator {
   border-bottom: double black 10px;
   margin-bottom: 20px;
}
 
Of course, you could also add Garvin's div at the bottom, with its own if statement:

Code: Select all

{if not $smarty.foreach.dategroup.last}
<div class="entry_separator"></div>
{/if}
...which would require its own CSS to give it the separator line. Heck, you could even make it a literal <hr> and it'd still work.

This way you get separators between each entry, without an additional separator at the end.

By using the "first" attribute (instead of "last") you could use border-top, margin-top, or a div right after the foreach, instead of at the bottom:

Code: Select all

    {foreach name="dategroup" from=$dategroup.entries item="entry"}
      {if not $smarty.foreach.dategroup.first}<div class="entry_separator"></div>{/if}">
    ...
    {/foreach}
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Judebert, thanks for pointing this all out so well. I indeed did misread the original question. :-)

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/
carl_galloway
Regular
Posts: 1331
Joined: Sun Dec 04, 2005 5:43 pm
Location: Andalucia, Spain
Contact:

oh boy

Post by carl_galloway »

I feel a terrible headache coming on, why can't this stuff be in plain english?

I suspect its gonna take me a couple of days to get my head around this even though I could just copy and paste your solutions. If I'm going to use this solution and then support it in a theme I feel an obligation to understand it. Now I can see why Marc aka Col Kurtz wants a simple guide to theming.

Anyway thanks guys, for anyone else watching this thread, I should have a brand new 100% s9y theme (based on carl blue) avail for download soon.

Cheers
Carl
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

I'd like to take a shot at explaining, in plain English, if that's even possible. Feel free to read it sometime when you don't have a headache. I could start off on explaining all of Smarty, but we'll stick to the topic at hand for now. And I'll keep it pretty basic, since other people with no experience might be reading.

First, let's state the problem: we want separators between articles that appear in groups, like so:

DATE
article
---
article
---
article

DATE
article

...and so on. When I look at this pattern, I see that there's a separator beneath every article except the last one.

Now, articles consist of a lot of different pieces: title, body, footer, etc. There's even a div surrounding (almost) the whole thing. But, for simplicity, we'll actually add a separate separator. The HTML tag designed for this is <HR>, which puts a horizontal line (a "Horizontal Rule", literally) on the screen. We don't even need CSS!

Since the template is where we generate our HTML, we'll need to modify the template. We know entries.tpl is where the HTML for entries is generated (hence the name), and so that's where we go.

Smarty pays attention to things in {}. Everything else is plain HTML. Stripping out all the stuff we don't care about, we see something like this:

Code: Select all

{foreach from=$entries item="dategroup"}
    <div class="serendipity_Entry_Date">
        {if $dategroup.is_sticky}
        <h3 class="serendipity_date">{$CONST.STICKY_POSTINGS}</h3>
        {else}
        <h3 class="serendipity_date">{$dategroup.date|@formatTime:DATE_FORMAT_ENTRY}</h3>
        {/if}

        {foreach from=$dategroup.entries item="entry"}
        <h4 class="serendipity_title"><a href="{$entry.link}">{$entry.title}</a></h4>

        <div class="serendipity_entry serendipity_entry_author_{$entry.author|@makeFilename} {if $entry.is_entry_owner}serendipity_entry_author_self{/if}">
        ... entry stuff ...
        </div>
        {/foreach}
        ... other stuff ...
    </div>
    {foreachelse}
    {if not $plugin_clean_page}
        {$CONST.NO_ENTRIES_TO_PRINT}
    {/if}
    {/foreach}
The first {foreach} loops through every item in $entries, which is the array of articles Serendipity fills out for us. It groups the articles according to date, so really we're looping once for each date. It will call each date a "dategroup". For each dategroup, it creates a div, then prints the date (or "Sticky Posts" if it's a sticky group).

The dategroups may have multiple articles. The next {foreach} loop goes through each article individually, calling each article an "entry". It creates a div with multiple classes, prints the entry stuff, and eventually reaches the bottom of the loop ({/foreach}) and goes back up for another entry.

If we want to insert something at the end of each article, this is the place to do it. Any HTML we type will be included after every article. So if we inserted an <hr> here, we'd get separators. Here's a code snippet:

Code: Select all

        ... entry stuff ...
        </div>
        <hr>
        {/foreach}
        ... comment stuff ...
    </div>
    {foreachelse}
This would work, but because we put the <hr> after every article, they'd look like this:

DATE
article
---
article
---

DATE
article
---

See the extra separator after the last article? We don't need that. Let's take it out.

If you look at the code we've already got, you'll see the {if} statement. We create an <H3> containing the STICKY_POSTINGS text if the date is the sticky date, otherwise we create an <H3> with the date. We also use an {if} to add the class "serendipity_entry_author_self" if the viewer is the article author. Pretty keen.

We just need to add our own {if}, with some way to tell if the article is the first one. If it's not the first one in the loop, we need to add a separator. If there's only one article, it's automatically the first in the loop, so we'll skip the separator.

Fortunately, Smarty provides exactly this capability. Unfortunately, this is not something we can ask the "entry" or "dategroup" about. We need to ask the {foreach}. To talk about it, and not some other {foreach}, we need to give it a unique name. And of course, Smarty provides this capability, as well.

So now we must do two things:
1) We have to name our {foreach}.
2) We have to ask our {foreach} if we're on the first loop, and skip the separator if we are.

Simple enough. Here's how we name our foreach:

Code: Select all

        {foreach name="dategroup" from=$dategroup.entries item="entry"}
We simply added the "name" attribute. Any name will do, but "dategroup" seems simple. That makes the actual, full name of the {foreach} $smarty.foreach.dategroup.

Now we need to ask if we're on the first entry of the group (the first loop). That's as simple as checking the "first" attribute of our foreach, like this:

Code: Select all

        {if $smarty.foreach.dategroup.first}
        <!-- No separator for this! -->
        {else}
        <hr>
        {/if}
That'll work. There's a simpler way, of course. Since we only want the separator when it's not the first loop, we can just add the "not" to our {if} and lose the {else} altogether:

Code: Select all

        {if not $smarty.foreach.dategroup.first}
        <hr>
        {/if}
Smaller code is better, because it's faster (minutely, in this case, but hey... I'm making a point here).

We could, of course, use other HTML than <hr>. We could add a complete div, a span, an image, whatever. And if you understand CSS, you could just add an extra class to the appropriate div, then give it extra border, bigger margin, a different color, or what-have-you. But this is already long enough for now.

And there it is, in plain English, with some Smartysh notes for reference.

Incidentally, Carl, I admire your desire to understand what you're doing. Anybody can cut-and-paste, but it takes a hacker (in the good, hacker's sense) to understand what he's doing. Hope this helps.
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Judebert, thanks a lot for your explanation! May I put this entry within our s9y.org documentation on a place like "Tutorial: Understanding the entries.tpl Smarty foreach loop"?

Best 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/
judebert
Regular
Posts: 2478
Joined: Sat Oct 15, 2005 6:57 am
Location: Orlando, FL
Contact:

Post by judebert »

Be my guest. In fact, I'm flattered.

You may also make any modifications you like.
garvinhicking
Core Developer
Posts: 30022
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Post by garvinhicking »

Thanks! I just put it onto http://www.s9y.org/121.html

The formatting is not yet right, but I'm out of time to check it. :-)

Best 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/
Post Reply