Reputation: 312
[Update I added more details after @S.Walsh answered because I am still stuck on how to make an include_once render in the content area.]
My custom plugin includes a Gutenberg dynamic block that uses a PHP function as its 'render_callback'. I would like this render function to do something similar to the PHP include_once() to include a template part.
I can use get_template_part, but how do I tell Wordpress to only do that once despite how many times the block is used (similar to the PHP include_once)?
My block.php looks like this:
register_block_type( __DIR__ . '/build/chart', [
'render_callback' => 'chart_render',
'attributes' => [
'theFile' => [
'type' => 'string',
'default' => ''
],
'theVars' => [
'type' => 'string',
'default' => ''
]
]
] );
The output part of render function looks like this:
function chart_render($attr, $content) {
ob_start();
get_template_part($path_to_template_part, null);
$ret = ob_get_contents();
ob_end_clean();
return $ret;
}
I want to include another separate PHP file that powers the chart, but I only want to include it once, regardless of how many times my block is used in a page/post. This is where I get stuck.
I can simply add include_once() to the render function, but the contents of the file render before the post content loads. In other words, the file I try to include gets output above the frontend HTML tag. I would like it to render with the post content where the block lives.
I tried using the has_block() function as described here by Rich Tabor and I tried the init hook. This approach works for enqueuing scripts, but I get the same problem when trying to use PHP include_once(): The content renders above the tag. I tried this:
function my_dependencies () {
if(has_blocks('chart')) {
include_once ('my_path/myfile.php' );
}
}
add_action( 'init', 'my_dependencies' );
If I put that function in block.php, it will always return false. I suspect that the content blocks do not exist at the time the blocks are registered.
If I put that function in my template part that the render function calls, then it will render the content before the tag.
Not relevant, but you might be asking why I am doing this nonsense? I have a specialized theme that allows my content editors to select certain charts to load in the post, along with an array of parameters the user supplies. Those charts are dependent on a separate PHP file that only needs to appear on the post one time (not one time per block).
_________________________
The Solution based on @S.Walsh's answer @S.Walsh pointed out that it is ok to add include_once() inside of the Output Buffer. That seems so obvious now. Here is what works for me:
function chart_render($attr, $content) {
ob_start();
include_once(my_path/myfile.php) // only gets loaded regardless of how many blocks on are the post.
get_template_part($path_to_template_part, null); // gets loaded for each block on the post.
$ret = ob_get_contents();
ob_end_clean();
return $ret;
}
Upvotes: 1
Views: 598
Reputation: 3699
Output buffering can be used include your other PHP template file inside the render_callback
of your dynamic block.
Updated example based on updated question
Your dynamic block with two attributes, "theFile" and "theVars" have a safe default of ''
which is good practise. The PHP template contains a function that returns the chart content based on the saved blocks attributes. When called in the render_callback
, with output buffering the contents of the include_once()
file is not printed before the block:
template.php
<?php
function render_chart($file, $vars)
{
// return chart content or other dynamic content
return "<p>File: ".$file."Vars: ".$vars."</p>";
}
plugin.php
<?php
function chart_render($attrs, $content)
{
include_once 'src/template.php';
// Start the output buffer
ob_start();
// Print the block wrapper attributes (classnames etc)
echo "<div " . get_block_wrapper_attributes() . ">";
// Include once the "template.php" file when the block rendered with
// $block_attributes passed to render_chart() function of the template
echo render_chart($attrs['theFile'], $attrs['theVars']);
// Print closing block tag
echo "</div>";
// Get the output buffer content to return
$content = ob_get_clean();
// End the output buffer
ob_flush();
// Returns the content ready to render
return $content;
}
NB. Keep in mind the differences between require versus include in PHP. Using require()
will throw a fatal error and stop the script if there is an issue where include()
will only produce a warning - important to note when testing your dynamic code/block.
Upvotes: 1