setBlockWrapper if block type.

Permalink 2 users found helpful
Hello

I'm really stuck with my theme,

Heres the code I have in full.php
$a = new Area('Main');
      $start = '<article class="content clearfix">';
      $end = '</article>';
      $a->setBlockWrapperStart($start);
      $a->setBlockWrapperEnd($end);
      $a->display($c);


What I would like to do is add an if statement that only adds the block wrapper if the block name isn't "title" a block I made with Designer content.

Pasically is there a way to get the blocks name in theme?
The php if part I can probably muster up myself.

Is something like this possible?

 
Mnkras replied on at Permalink Reply
Mnkras
the only way is to loop through all the blocks, an easier way is to make a new area, or pull that info from somewhere else (an attribute)
onebit replied on at Permalink Reply
Thank You for the info. I'll just have to make an Area for each block then because the title and content blocks are going to be in turns
JohntheFish replied on at Permalink Reply
JohntheFish
Why not just modify the view of the block to include the wrapper? Or create a second view, so you have one without the wrapper and one with?
onebit replied on at Permalink Reply
The thing is I need the wrapper for all other block types besides the title one. So I would need to make a new view for every block besides title.
jordanlev replied on at Permalink Reply
jordanlev
I understand the problem, I've run into the same issue when trying to make jquery nav tabs or accordions. I wish there were a way to set a "title" for each block, but unfortunately there is not.

If the content other than the "title" blocks are just going to be text and images, you could make a new Designer Content block that has both the title and the WYSIWYG editor and handle it that way. But if you want to be able to put in any kind of block type after each title, then it's very tricky. Your idea for different areas is probably the easiest to implement, but it's not ideal because you need to artificially limit the amount of content on the page. If you want to try manually looping through all the blocks as Mnkras suggests, you could do it like this:
<?php
if ($c->isEditMode()) {
    $a = new Area('Main');
    $a->display($c);
} else {
    $mainBlocks = $c->getBlocks('Main');
    foreach ($mainBlocks as $b) {
        if ($b->btHandle == 'title') {
            $b->display();
        } else {
            echo '<article class="content clearfix">';
            $b->display();
            echo '</article>';
        }
    }


Good luck!

-Jordan
onebit replied on at Permalink Reply
Yes that looks exactly the thing I need. Thank You very much
JohntheFish replied on at Permalink Reply
JohntheFish
I see, got it the wrong way round.

Another approach is to do it back to front. Wrap all blocks regardless. Add a bit of jQuery to the view for the title block to unwrap it. This would sort out any appearance issues, but would not work for those with script disabled and Google would see the wrapped block.

Something like this (untested)

<script type="text/javascript">
$(document).ready(function(){
      $('.a-unique-class-in-title-block').each(function(){
      var content = $(this).closest('article').html();
      $(this).closest('article').replaceWith(content);
    });
 });
</script>


There is also a jQuery unwrap function that can be used to similar effect, but requires a bit more precision with selecting the content to be unwrapped.
onebit replied on at Permalink Reply
Thought about using javascript. But felt a server side solution would be more fool proof.
aghouseh replied on at Permalink Reply
aghouseh
Block or Area-level attributes would be so nice in this situation!
Mnkras replied on at Permalink Reply
Mnkras
@aghouseh shush!
jordanlev replied on at Permalink Reply
jordanlev
I concur -- all I need is one freaking textfield for each block and so many of my sites would be way less complicated to develop and maintain. (But I could understand how it might be a can of worms -- adding a lot of complication to something that's not as important as other areas of the system perhaps.)
aghouseh replied on at Permalink Reply
aghouseh
Yeah, I get that it's not the priority, but boy it would be nice :)
aghouseh replied on at Permalink Reply
aghouseh
Jordanlev,

I noticed with 5.5.1 they allow a 'name' text input for blocks via the Custom Template pop-up on the block in edit mode. Which then made me dig into this as well..

https://github.com/concrete5/concrete5/blob/master/web/concrete/mode...

This seems VERY useful. Now to just extend it to include the full capability of the attribute system, and I would be in heaven. :)
jordanlev replied on at Permalink Reply
jordanlev
Yes, I added that feature to support things like accordions and jquery tab areas, as well as applying different styles to each block in an area (e.g. zebra stripe background colors or different borders on the top block in the area).

I have a couple of free addons and a blog post almost ready to demonstrate this (it's *really* awesome), but I won't be able to get those out for another week or two due to a big relocation I'm in the middle of.

Note that the block name textbox (which was put in by @mkly) serves the purpose that block names in the global scrapbook served in 5.4 and below (to facilitate Block::getByName('whatever')->display() code in page type templates).

Finally, I wouldn't hold your breath for custom attributes on blocks -- it is an order of magnitude more difficult to implement than the "name" textbox was, and even if someone could implement it, it's arguably a UI nightmare that will overcomplicate the editing interface and be a data entry burden for users. (That's just my opinion though, not a hard fact).

-Jordan
mkly replied on at Permalink Reply
mkly
About block attributes.

I already have most of that working on a test box, but it's a lot of code that I know will never get accepted so I just moved on to other stuff.
aghouseh replied on at Permalink Reply
aghouseh
I both love and hate you so strongly.
arrestingdevelopment replied on at Permalink Reply
arrestingdevelopment
I have a couple of free addons and a blog post almost ready to demonstrate this (it's *really* awesome), but I won't be able to get those out for another week or two due to a big relocation I'm in the middle of.

Jordan,

I'm a little late to this conversation... and (typically) have nothing to contribute to the OP's issue... but I CAN chime in and say "Please post back to this discussion when you've had the time to get the Add-ons and blog post done!" I'd love to see what you've got on this... as this is a problem I've run into since getting started with C5 (what... like 2 months ago?!?! LOL!).

Thanks!

- John
jordanlev replied on at Permalink Best Answer Reply 2 Attachments
jordanlev
Guh... yeah, I have two addons mostly ready but haven't had time to test them better. I also want to try simplifying a bit, and also write a blog post about how they work. Hoping I can get to all C5 related things next week...

In the meantime, I'm attaching what I've got so far. One is called "tabbed_area" and the other is "accordion_area". These will only work with 5.5.1+

And they are "designer tools" more than plug-and-play addons (hoping to simplify a bit -- if you can give me some feedback that would be great). Here's how to use them:

1) Install the addons (one or the other or both -- they are independent of each other, just two different examples of the same code technique)

2) Add the following code to your theme's header, *before* the <?php Loader::element('header_required'); ?> line:
<?php
$html = Loader::helper('html');
$this->addHeaderItem($html->css('jquery.ui.css'));
$this->addFooterItem($html->javascript('jquery.ui.js'));
$this->addFooterItem($html->javascript('jquery.ui.tabs.js', 'tabbed_area')); //<--remove this line if not using tabbed_area
$this->addFooterItem($html->javascript('jquery.ui.accordion.js', 'accordion_area')); //<--remove this line if not using accordion_area
?>

Note that we're loading the whole jquery.ui.css and jquery.ui.js files on every front-end page load (usually they're only loaded by C5 when someone is logged in with editing privileges) -- this may affect site performance (this is what I'm hoping to simplify and clean up before I put it up on the marketplace).

3) In your page type template, instead of doing this:
$a = new Area('Main');
$a->display($c);

...do this for a tabbed area:
Loader::model('tabbed_area', 'tabbed_area');
$wrapper_id = 'tabs-main';
$a = new TabbedArea('Main');
$a->display($c, $wrapper_id);
?>
<script type="text/javascript">
$(document).ready(function() {
   $('#<?php echo $wrapper_id; ?>').tabs();
});
</script>

...OR do this for accordion area:
Loader::model('accordion_area', 'accordion_area');
$wrapper_id = 'accordion-main';
$a = new TabbedArea('Main');
$a->display($c, $wrapper_id);
?>
<script type="text/javascript">
$(document).ready(function() {
   $('#<?php echo $wrapper_id; ?>').accordion();
});
</script>


For eventual marketplace release, I'll probably try to find a more self-contained tab or accordion plugin so I don't have to load the entire jquery UI kitten-kaboodle on every page. Or maybe not... let me know what you think.

Thanks for reminding me about this.
JohntheFish replied on at Permalink Reply
JohntheFish
I think it is more reliable to simply load the entire jQuery.ui than just part of it. Less likely to get namespace clashes with other addons using jQuery.ui. Could be more efficient too if the site is already using other parts of jQuery.ui.

A neat solution and tidy code subclassing Area. I can see theme developers adding extra page types with such areas and taking care of the the theming of the tabs.

Without theme developers incorporating it, jQuery.ui will need further work creating locally scoped ui themes, otherwise tabs/accordion would be tied to the C5 theme.
jordanlev replied on at Permalink Reply
jordanlev
Hi John,
Thanks for your thoughts on loading the entire jquery ui. Having to make the tradeoff between performance vs. compatibility feels kind of icky to me (I mean, it's fine to make that decision for a specific site if you're the designer/developer of that site, but for a general purpose addon it seems like a difficult situation).

And you're right about the styling -- my purpose here was really just to show designers how to incorporate something like this in their theme. Ideally, any tabs or accordion js plugin should work (assuming they operate on 1 wrapper div with sub-elements structured similarly to how jquery UI does it).

This does make me think the ideal solution is to use a non-jquery-ui plugin instead (although the jquery ui ones are easier to theme because of ThemeRoller). Hmm... definitely some food for thought.
arrestingdevelopment replied on at Permalink Reply
arrestingdevelopment
What about referencing the jQuery UI from Google's CDN (http://code.google.com/apis/libraries/devguide.html#jquery... )? Run a check to see (1) if you're in edit mode and (2) if jQuery UI is already being loaded... if not, reference it from Google?

Would help to speed loading, at least a little bit, since lots of users probably already have it cached.

Maybe add a way to allow the user to select a "package" of the files downloaded from jQuery UI's ThemeRoller and then include the appropriate referencing to it all?

Totally n00b out-of-the-box thinking (sometimes NOT knowing things helps, LOL!).

- John
JohntheFish replied on at Permalink Reply
JohntheFish
Hi Jordan

I have been looking at this with a view to using a similar method of inheriting from Area adapted for displaying (or not) blocks that have a wrapper set by the area/theme or a design.

The objective is:. When not in edit mode, if a block has no content (or the content is white space), then do not display the block or the wrapper, or any design applied to the empty block.

I can get my head around looping and buffering blocks 1 by 1 and only outputting if they have content. But am stuck at what happens when it is a stack rather than a block that is getting wrapped.
jordanlev replied on at Permalink Reply
jordanlev
Hi John,
I don't know too many details of how the Stacks work in this context because they're so new. But what I have discovered is that C5 treats an entire stack as a block when looping through an area's blocks. These stacks have a specific blockTypeHandle of 'core_stack_display' -- so in your loop, you'll want to check for that blockTypeHandle, and if you come across it, you'll then need to loop through *that* stack's blocks too.

I don't know the code for looping through a stack. I vaguely remember seeing it in another forum post a few weeks back, but can't find it now. I do know that Stacks are kinda-sorta treated as Pages/Collections, so I think maybe you can do this:
$stack = Stack::getByID($block->getInstance()->stID);

...and now $stack is basically like a PAGE object, so you can call getCollectionID() on it, or look through that collection's areas.

UPDATE: You can get the name of the area in a "stack" collection using the STACKS_AREA_NAME constant (it's currently defined in the core system as 'Main', but you should use the constant for it).

Sounds like you'll want some kind of recursive function that accepts a collection ID and does the looping through blocks of a given area, so you can pass each stack to the function again to "unwind" its sub-blocks as you go through.

Hope this stream-of-consciousness makes sense.

UPDATE 2: I don't know if you're allowed to put a stack into a stack. You'll want to test this out, and if so, you'll definitely need to write a recursive function for checking them.
ScottC replied on at Permalink Reply
ScottC
have you looked at $area->setCustomTemplate() method ?

This would work for a site-wide kinda thing, I think that some concrete5 blocks look at it for a scrapbook.php when displaying a scrapbook, so you could probably go for something like that on a site you are giving to someone else.
aghouseh replied on at Permalink Reply
aghouseh
Except that I've found a bug where setting the custom template for a BlockType within an Area does not propagate to a Stack placed within that Area. I do love that method, though, as it allows for a little bit smoother client-side experience by setting default templates, but also allows for them to override, if needed.
ScottC replied on at Permalink Reply
ScottC
you can also pass in a field named bFilename that used to get passed to the block controller upon save, it probably still does.

There's a function there that will list the custom templates available for a block and if present then you can have them select one there in one step instead of two.
Mnkras replied on at Permalink Reply
Mnkras
yep its still passed and that does work,
aghouseh replied on at Permalink Reply
aghouseh
Wow, that's really nice, and way more intuitive. Thanks for the heads up!
JohntheFish replied on at Permalink Reply
JohntheFish
Thanks for the ideas. I now have some pointers to work with.