Programmatically add a Block to a Page Area

Permalink 4 users found helpful
Does anyone know if it's possible to programmatically add a block to an area of a specific page? What I'm looking for something like:

$page = Page::getByID($pid);
$block = BlockType::getByHandle('some_block');
// ...define additional block attributes...
$page->addBlock('Area Name', $block);


The result of which would add the programmatically generated block to the page permanently. This differs from programmatically adding a block to a page_type in that the block would only exist for the given page.

Or is the only way to do this with db calls?

Thanks

dzimney
 
jordanlev replied on at Permalink Best Answer Reply
jordanlev
You're close, but you have the arguments for the addBlock method backwards. Should be:
$page = Page::getByID($pid);
$block = BlockType::getByHandle('some_block');
//set block data (differs for each block type... following is an example for the 'content' type)
$data = array(
    'content' => '<p>test</p>',
);
$page->addBlock($block, 'Area Name', $data);
dzimney replied on at Permalink Reply
dzimney
HA! I can't believe I missed that in the class documentation. Thanks! That was exactly what I was looking for.
goldhat replied on at Permalink Reply
Is there a way to do the opposite of this, to remove a block from a given Area of a Page? The collection model has addBlock() so I was hoping to find removeBlock, but I don't see it. For my purpose even better would be a "clearArea" function like $page->clearArea(Area) where it deletes all blocks from that Area.
goldhat replied on at Permalink Reply
Found a solution, deleteBlock using something like this:
$blocks = $page->getBlocks();
foreach($blocks as $b) {
  $b->deleteBlock();
}


Thanks all the same.
zoinks replied on at Permalink Reply
That's pretty impressive. I just deleted every single block on a page by accident and it even overrides versioning history so now I have to add the blocks back I wanted to keep.
jordanlev replied on at Permalink Reply
jordanlev
I know this stuff is not intuitive, so I don't mean to "blame the victim" here, but if you're unfamiliar with how code works or what it does, you should definitely be doing this on a development site or a copy that you don't care about messing up. Or at least back up the database before running your experiments.
And definitely don't put any code in site_post.php unless you very intentionally want it to run on every single page load :)
zoinks replied on at Permalink Reply
Oh, it is a development site, it's not a big deal. I am working locally with a copy of our real site.
zoinks replied on at Permalink Reply
^ So, following this, I added this to config/site_post.php. And what happened is every single time I refreshed the page, it added a new instance of the block. What has changed?

I ended up having to delete the block entirely in addition to deleting confing/site_post.php. Deleting config/site_post.php wasn't enough (should have been, right?) and clearing all the caches in the world wasn't enough. Deleting old versions of pages and clearing cache and turning off block cache numerous times was not enough. I actually had to delete the block. However, the block didn't cause a problem until I added the above code into config/site_post.php. So, why should I have had to delete the block?
jordanlev replied on at Permalink Reply
jordanlev
The site_post.php file is loaded by Concrete5 on every page load, so any code in that file will be run every time the page is loaded.

What exactly are you trying to achieve with this code? Under what circumstances do you want a new block installed and then added to a page? (Generally the only place I've ever done this is in a package controller's "install" method, which only gets run when the package is installed via the dashboard).
zoinks replied on at Permalink Reply
Ah, well that explains it. Thank you. Is there a better place to add blocks programmatically where it will only happen once? (I will save the phrase "package installer" for later Googling).

I am just trying to create my first blocks to get an idea about what is possible and how they work. I've learned a lot about C5 in the process. Much less confusing.

I eventually want to do a portfolio gallery plugin as my first project, but I am learning everything I can about block creation at the moment and just trying to gather all the concepts together. When I saw this technique, I just wanted to explore it because I've bought different add-ons that do things like automatically stick blocks on pages, so I figured it would be important to comprehend how it works in case I want to make some user-friendly dashboard-based add-on rather than making people add blocks to pages individually all the time.
jordanlev replied on at Permalink Reply 1 Attachment
jordanlev
Hey Zoinks,
I think it's great that you're trying to learn how to build blocks! It's definitely not easy (took me a while to get the hang of, even having had lots of programming experience in the past).

Here's the big picture as I see it:
If you're creating custom blocktypes, there are 2 places you can do it: either in a package, or at the top-level of your site (in the /blocks/ directory). The primary purpose of packages is to make it easy to share things amongst different sites, whereas the top-level /blocks/ directory is for one-off custom blocks (or custom templates that override other blocks) that are specific to one site. Any block you've ever gotten from the C5 marketplace will always be in the /packages/ directory, because the marketplace is for distributing things that go on lots of different sites. Packages also have 2 side benefits: they allow you keep things bundled together in the package folder, so they're not spread out across the site (this doesn't apply as much to blocks, because blocks are bundled together in their own folder as well... but when you get to more complicated things like dashboard pages, js and css files, libraries, models, etc, then it really helps keep things much cleaner by putting them all together into a package). The other side benefit of packages is that they have an "install" method that gets called by Concrete5 whenever it's installed. Blocks on their own don't have this (you need to manually install them via the dashboard).

So I think it would be best for you to build these in a package. There's a small amount of overhead involved, but the benefits far outweigh the drawbacks. (And if you're wanting to programmatically add blocks to pages, this is the *only* way you can achieve this).

I'm attaching a bare-bones skeleton package for you that contains one blocktype, and in the package controller (/packages/zoinks/controller.php) it installs the blocktype and then adds it to a page. The tricky part is how do you know what page you want to add it to? I can't answer that question for you, it depends on your project and your purposes for the block.

Hopefully this gets you off in the right direction. There are a million different ways you could go from here, but hopefully this shows you the bare minimum and then when you look at other block code in the marketplace it will make sense what's going on a little more (maybe... some of them are messy and disorganized to say the least, even some of my own if they are from a long time ago).

Good luck!

-Jordan
zoinks replied on at Permalink Reply
Wow, thank you so much! I'm going to have to dedicate my first add-on to you somehow whenever I finally figure it out. Maybe I'll call it "Gallery Gears" or something as a reference to your avatar. It also kinda makes sense as a name, so yeah, that's what I'm going to do.
enlil replied on at Permalink Reply
enlil
By the sounds of it, you're staring at code like i was 3 years ago. To me, I've climbed a mountain. In reality, I'm still but an amateur. Understanding the code and how it really works will come with time. From my experiences, I suggest you take a deep look at some of those add-ons that install blocks or pages etc and figure out how things work. Grab a free simple block from the marketplace and compare code with the package jordanlev gave to you, or take a free package and play with modifying it until your comfortable with things. And be open minded about how the same thing can be accomplished in many different ways. Find the "groove" you're comfortable with and go. You'll be throwing together packages before you know it!
balavec replied on at Permalink Reply
And how to add an HTML Composer block?
I use Concrete5.7.2
goldhat replied on at Permalink Reply
In the code shared above there is a use of the function BlockType::getByHandle(). Find out what handle (identifier) the HTML block has and then use it in the line below. It might be "html", I can't recall offhand.

$block = BlockType::getByHandle('html');


Update: ended up exploring this further and writing a tutorial about adding the PageList block programmatically to singlepages in a package. Can be adapted to adding any blocktypes, the process is the same with different data options.
http://concrete5.ca/blog/concrete57-add-pagelist-block-programmatic...
shahroq replied on at Permalink Reply
shahroq
Hi,
What about adding a block to a stack? What should it be instead of Page Area?

Edited:
I figure it out:
$stack = Stack::getByID(309);
$block = BlockType::getByHandle('content');
$data = array(
    'content' => '<p>test13</p>',
);
$stack->addBlock($block, 'Main', $data);