Add Composer Control Output Block Pragrammatically - concrete5

I'm creating pages programmatically and inserting content to a Content Block but after it has been created, I can't edit it via composer (because it's not a core_page_type_composer_control_output, it's a regular content block). Is there a way to add a block to a page programmatically and have it play nice in Composer?
Relevant code I'm using:
$page = Page::getByPath('/articles/xxx');
$block = BlockType::getByHandle('content');
$data = array(
'content' => 'the content',
);
$page->addBlock($block, 'Main', $data);

To achieve this, I would setup the pagetype as you would create the page with composer.
(add the content block to composer and the standard output of the pagetype)
After creating the page, you will notice the composer-linked content block is present on the page but completely empty. Then I would update the block instead of trying to create a new block in the 'Main' area.
Code example (not tested):
$page = Page::getByPath('/articles/xxx');
$blocks = $page->getBlocks('Main');
if(!empty($blocks)){
foreach($blocks as $block){
//check if the blocktype is content
if($block->getBlockTypeHandle() == 'content'){
//we are pretty sure this is the content block in the main area
//because it's the only content block present... updating the block content
$data = array(
'content' => 'the content',
);
$block->update($data)
}
}
}

Related

Drupal 8 Delete layout prefix

I have a page, created via page manager with the layout type - "One Column". I placed blocks on the page and when I open this page, I see my blocks wrapped by a
<div class="block-region-content">
When I print content variable in twig template, I can see that this div is the value of #prefix property
content array(12)
'content' => array(4)
'#prefix' => string(34) "<div class="block-region-content">"
'#suffix' => string(6) "</div>"
How can I delete this properties?
You can implement hook_preprocess_HOOK to achieve this. For example, you should probably preprocess blocks within your theme (same can be done from a module though) :
function THEME_preprocess_block(&$vars) {
// Act on a specific block, eg. here the page title block
if ($vars['plugin_id'] === 'page_title_block') {
unset ($vars['content']['#prefix'], $vars['content']['#suffix']);
}
}

Drupal 8 passing current nid to block template

I have created a custom module that uses a custom block to display a list of nodes (I can't use D8 views in this particular case).
Inside the block twig template I need to filter this list on the current nid (node id of the current page) and I'm passing the value to twig in this way:
$node = \Drupal::routeMatch()->getParameter('node');
$nid = $node->nid->value;
return array(
'currentnid' => $nid,
);
Everything is working fine, but changing page the nid passed to the block template is still the same. I think this is related to template caching: by clearing the cache and reloading the page I get the correct value for the current page, but moving to another page I'm still getting the same nid!
Is there something I can do to prevent nid value to be cached?
I think that the best solution would be to get the current nid value directly inside the template, but I'm inside the custom block and I don't know how to get it. Any idea? I have already checked the kint() output and the current page nid is not present at the block template level.
<?php
namespace Drupal;
$node_v1 = \Drupal::request()->attributes->get('node');
$node_v2 = \Drupal::routeMatch()->getParameter('node')
?>
in your build array try using cache tags with your current nid
return array(
'currentnid' => $nid,
'#cache' => [
'tags' => ['node:'.$nid],
],
);

Drupal add blank page without styles and js

I have the site based on drupal 7.
I need to create widget for iframe. I created new content type and removed all sidebars, headers, footers from there. I left only content. It works good.
But this page loads all my scripts and css (less) from mytheme.info. And I want just to use scripts and css from my custom module. Is it possible to do?
You can make use of template_process_html to do so.
Add the following code to your theme's template.php file.
function [YOUR_THEME]_process_html(&$vars) {
// first check for the path of the page you need to unset the js & css for.
// assuming the path is 'node/12'
if(arg(0) === 'node' && arg(1) === '12') {
$vars['scripts'] = array();
$vars['styles'] = array();
}
}
To check if current page is a specific content type; You can use $vars['classes'] or $vars['classes_array'], which holds the css classes to add to <body> tag. In case of a node page, it adds a class name node-type-NODE_TYPE_MACHINE_NAME to the classes string.
if(strpos($vars['classes'], 'node-type-[YOUR_TYPE]') === TRUE) {
OR
if(in_array('node-type-[YOUR_TYPE]', $vars['classes_array']) === TRUE) {
Update
You can add any js / css files to the array
$vars['scripts'] = array(
'path/to/js/file1.js',
'path/to/js/file2.js'
);
$vars['styles'] = array(
'path/to/css/file1.css',
'path/to/css/file2.css'
);

Silverstripe date and image error

This is the .ss template file:
<ul>
<% control Menu(1) %>
<li>$MenuTitle</li>
<% end_control %>
</ul>
<div>
<h1>$Title</h1>
<div>Date : $Date.nice</div>
$layout
$Content
</div>
This is the php file:
class ArticlePage extends Page {
static $db = array(
'Date' => 'Date',
);
private static $has_one = array(
'SingleImage' => 'Image'
);
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Content.Main', new DateField('Date'), 'Content');
$fields->addFieldToTab(
'Root.Upload',
$uploadField = new UploadField(
$name = 'SingleImage',
$title = 'Upload a single image', "Content"));
return $fields;
}
}
The date and image are not showing up on the page.
This could be any number of things.
It could be that you have not set the page type properly in the CMS.
It could be that you have not flushed your template cache.
To do this append ?flush=all to the end of your URL.
It could be that you have not done either of the above and have not completed a database build yet either.
To do this visit yoursite/dev/build.
It could be that you have not named the template correctly. It must mirror the php Class name (ArticlePage.ss)
It could be that you have not put this in the correct place. It must be in a templates folder in either the selected theme or your project folder. A flush is required after relocating the file (see above).
If you are using a theme it could be that you do not have the correct theme selected. See the documentation on this.
It could be because you're not being diligent with your code. The dot method for formatting a date nicely is .Nice, not .nice. $Date.asdf would also cause nothing to show up - as you are describing. Template variables fail silently if there is no sensible value to output.
Similar to the above - the layout variable is $Layout, not $layout (although this is irrelevant to this particular problem). $Layout also only works in 'main' templates (in the base 'templates' folder, not in the 'Layout' subfolder).
If all of the above checks out, then it could be simply that you have not put any information in through the CMS yet. You must of course complete this step before anything will show up.

Wordpress page slug conflicts with media library item

I created a new page which is assigned a custom template. When I visit that page's url I see what appears to be the default page layout (not my template) and the admin toolbar shows options pertaining to media (ex: Edit media).
After some head scratching, I deduced that somehow that url must point to a media item. I edited the page slug and "bingo" the actual page appears just as expected. When I visit the original url (from the first slug) I see the same media item.
Bottom line: It appears that coincidentally the page and the media item share the same name, and this was somehow causing WP's wires to get crossed.
My question: Can someone help me understand how/why this happens? Does wordpress create magic permalinks to everything in the media library (other than their location in wp-content/uploads/...)?
Note: The media item was uploaded normally into the media library (not FTP into the root directory, etc)
Yes, in WordPress you cannot have duplicate slugs/categories/taxonomies/tags. So if your theme allows for media files and permalinks to have their own page and the slug is the same as another one, it will usually append a number to it because the database does not like it.
media slug "example"
page slug "example" will not work since that slug exists already , if done in the admin it will automatically change the slug to "example-1".
I just had this problem and fixed it like this:
$post_s=get_posts('posts_per_page=-1');
foreach($post_s as $p){
$atts = get_posts('post_type=attachment&name='.$p->post_name.'&posts_per_page=-1&post_status=inherit');
foreach($atts as $att){
echo 'found!! '.$p->post_name;
// Update post 37
$my_post = array(
'ID' => $atts->ID,
'post_name' => $att->post_name.'-image'
);
// Update the post into the database
wp_update_post( $my_post );
}
}
This is a late answer, but I wanted to give a cleaner version of the answer that alesub gave.
function wp21418_append_to_post_name() {
// Checks to see if the option images_updated has been set or has a value of true.
if ( get_option( 'images_updated' ) === 'true' ) :
return;
endif;
// get all attachment posts.
$attachments = get_posts([
'post_type' => 'attachment',
'post_status' => 'inherit',
'name' => $p->slug,
'posts_per_page' => -1,
]);
// For each attachment, loop and update the post_name
foreach($attachments as $p){
$attachment = array(
'ID' => $p->ID,
'post_name' => $p->post_name.'-image'
);
// Update the post into the database
wp_update_post( $attachment );
}
// Once everything is looped, add the option to the database.
add_option( 'images_updated', 'true' );
}
add_action( 'after_setup_theme', 'wp21418_append_to_post_name' );
This function runs on an action hook right after the theme has setup. The first line checks to see if there is an option in the database images_updated. If that option exists, we bail on the function and it doesn't do any processing. Otherwise, if the option does not exist, it runs the function and sets the option at the very end.
This makes it so it will only run once. You don't have to remove the function after refresh. If you want to run it again, you can simply remove the if statement at the top. As a caveat: doing this will add another -image at the end of post_names even if they have -image already (e.g. -image-image)
There could be more file name checking for that situation. Will update the answer with that if someone really needs it.
I tried one of the suggested solutions, and ended up having attachment pages like /bob-image-image-image-image/.
I'd suggest that instead of using alesub or disinfor's code blindly, use a better option in the form of "Disable Media Pages" plugin.
https://github.com/joppuyo/disable-media-pages
It automatically sets all attachment slugs to an unique id, and there is the option to mangle any existing attachment slugs so they won't cause any issues in the future.

Resources