I have a working WordPress Gutenberg Block project which uses nested blocks. I'm trying to rewrite the javascript save function in PHP to create a dynamic block.
I've modified the PHP file to include the following:
function render_html($attributes) {
var_dump($attributes);
ob_start(); ?>
<h1>Attributes</h1>
<h3>The number of columns is <?php echo esc_html($attributes['myColumns']) ?>!</h3>
<?php return ob_get_clean();
}
function cards_init() {
register_block_type_from_metadata( __DIR__, array(
'render_callback' => 'render_html'
) );
}
add_action( 'init', 'cards_init' );
This displays the top level attributes correctly (just one value):
C:\Users\Steve\Local Sites\netmonics6\app\public\wp-content\plugins\cards\cards.php:32:
array (size=1)
'myColumns' => int 3
Attributes
The number of columns is 3!
I'm just wondering how I access the attributes for the nested blocks?
I've used Innerblocks in the main edit.js as follows to enable a nested block:
<InnerBlocks
allowedBlocks={['some-name/card']}
orientation="horizontal"
template={[
['some-name/card'],
['some-name/card'],
['some-name/card'],
]}
/>
Does anyone please have any ideas?
Steve
InnerBlocks can be accessed via $block in the render_callback function. The syntax for the render callback is function($attributes, $content, $block) although commonly, only $attributes is used - unless you want to access something <InnerBlocks>, eg:
PHP
/*
* Render callback function
* #return string HTML markup
*/
function render_html($attributes, $content, $block)
{
$output = '';
// Loop through each inner block
foreach ($block->inner_blocks as $inner_block) {
// Eg. If your ['some-name/card'] block had an attribute
// called `someAttribute` (boolean), it could be accessed via:
if ($inner_block->someAttribute == true) {
// Do something different with this block
$output .= sprintf('<div class="is-some-attribute">%s</div>', $inner_block->render());
} else {
// Otherwise, render block as usual..
$output .= $inner_block->render();
}
}
/*
* Tip: Always return the content to render
* echo() should not be used in render_callback() and ob_start/ob_get_clean not needed.
* Returning valid content avoids dreaded "Invalid JSON" error in Editor.
*/
return $output;
}
When using InnerBlocks, the save() function in JavaScript is required so that the block editor saves the InnerBlock content (even if you are using a PHP render_callback), eg:
save.js
export default function save() {
const blockProps = useBlockProps.save();
return (
<div {...blockProps}>
<InnerBlocks.Content />
</div>
)
}
Depending on what you need from the InnerBlocks, block context might also be useful too..
Related
I'm new to cakephp2 and I need some help here.
The problem is that I have a view that displays a list of items from the database and there is a pagination button below. Instead of moving to the 2nd page by using the pagination, I want to have a single button that will allow you to display(append)10 more data list. But I'm not sure how it is called and how to implement it. Sorry for my bad explanation.
I think, you can play with limit parameter.
Somethink like this:
// in controller
<?php
function items() {
$limit = array_key_exists('n', $this->request->query) ? (int) $this->request->query['n'] : 10;
// some security check you need to add
$this->paginate = array(
'limit' => $limit
);
$items = $this->paginate($this->YourModel);
// some other code
$this->set(array(
'items' => $items,
'next_limit' => $limit + 10
));
}
?>
<?php
// in view file
// items output
foreach($items as $item) ...
// more button
echo "<a href='".$this->here."?n=".$next_limit."'>More</a>";
?>
How does $_GET Variable works with Concrete5? Can I use that on regular page?
I know I can do this with single page via url segment, I'm just wondering if it is possible with regular page.
Example is :http://www.domain_name.com/about-us/?name=test...
Get-parameters are available via the controllers. In the view of a page or block use:
$this->controller->get("parameterName");
A cleaner way for custom parameters would be to define them in the function view() of the page controller. If at http://www.domain_name.com/about-us is your page and you define the view function of it's pagetype controller like this:
function view($name) {
$this->set("name", $name);
}
... and call the URL http://www.domain_name.com/about-us/test – then "test" will be passed under $name to your page view.
Note that controllers for page types must be in controllers/page_types/ and called BlablaPageTypeController ... with "PageType" literally being in there.
You can use it in a template. For instance, you can grab a variable...
$sort_by = $_GET['sort'];
And then use that variable in a PageList lookup, similar to:
$pl = new PageList();
$ctHandle = "teaching";
// Available Filters
$pl->filterByCollectionTypeHandle($ctHandle); //Filters by page type handles.
// Sorting Options
if ($sort_by == "name") {
$pl->sortByName();
} else {
$pl->sortBy('teaching_date', 'desc'); // Order by a page attribute
}
// Get the page List Results
$pages = $pl->getPage(); //Get all pages that match filter/sort criteria.
$pages = $pl->get($itemsToGet = 100, $offset = 0);
Then you can iterate over that array to print stuff out...eg
if ($pages) {
foreach ($pages as $page){
echo ''.$page->getCollectionName() . '<br />';
}
}
Props to the C5 Cheatsheet for the PageList code.
I have a twig variable html. To show it in a twig template I do {{html}}.
That variable looks like:
<div>{{region_top}}</div><div>{{region_center}}</div>
region_* is a variable too. When Twig parses my html variable, it doesn't parse the inner variables (regions).
What I should do?
I have twig variable html. To show it in twig template I do {{html}}. That variable look like {{region_top}}{{region_center}}. region_* is variables too. When twig parse my html variable he didn't parse inner variables (regions). What can I should do?
Twig takes your strings as a literal string, meaning you'll see the content of the variable, escaped. If you want it to be able to display {{region_top}} as well, I'd recommend something like this:
{{html|replace({'{{region_top}}': region_top, '{{region_center}}': region_center})}}
If the content of your html variable is also dynamic (meaning it can contain more than just those two variables), I'd write a twig plugin which can do what you want. Writing plugins is pretty easy to do.
EDIT: Here's the extension I just finished writing.
EDIT 2: The extension now uses the environment to render the string, so it evaluates the string, instead of just replacing variables. This means your variable can contain anything a template can, and it will be render and escaped by Twig itself. I'm awesome.
<?php
/**
* A twig extension that will add an "evaluate" filter, for dynamic evaluation.
*/
class EvaluateExtension extends \Twig_Extension {
/**
* Attaches the innervars filter to the Twig Environment.
*
* #return array
*/
public function getFilters( ) {
return array(
'evaluate' => new \Twig_Filter_Method( $this, 'evaluate', array(
'needs_environment' => true,
'needs_context' => true,
'is_safe' => array(
'evaluate' => true
)
))
);
}
/**
* This function will evaluate $string through the $environment, and return its results.
*
* #param array $context
* #param string $string
*/
public function evaluate( \Twig_Environment $environment, $context, $string ) {
$loader = $environment->getLoader( );
$parsed = $this->parseString( $environment, $context, $string );
$environment->setLoader( $loader );
return $parsed;
}
/**
* Sets the parser for the environment to Twig_Loader_String, and parsed the string $string.
*
* #param \Twig_Environment $environment
* #param array $context
* #param string $string
* #return string
*/
protected function parseString( \Twig_Environment $environment, $context, $string ) {
$environment->setLoader( new \Twig_Loader_String( ) );
return $environment->render( $string, $context );
}
/**
* Returns the name of this extension.
*
* #return string
*/
public function getName( ) {
return 'evaluate';
}
}
Example usage:
$twig_environment->addExtension( new EvaluateExtension( ) );
In the template:
{% set var = 'inner variable' %}
{{'this is a string with an {{var}}'|evaluate}}
See http://twig.sensiolabs.org/doc/functions/template_from_string.html
It seems that this is frequently missed as most folks think (and search for) "eval" when expecting a filter/function to evaluate in the current language they're drafting in. Template from string isn't the first search query that comes to mind.
One option is to render your templates as strings. You can do that like this:
$env = new \Twig_Environment(new \Twig_Loader_String());
echo $env->render(
"Hello {{ name }}",
array("name" => "World")
);
I'll leave it to you to decide how exactly to structure your code to make this work, but it might go something like this:
1) Fetch the inner template text that contains the variables that aren't being replaced.
2) Render that inner template text into an $html variable. Be sure to pass in any vars you need.
3) Render your original template that contains {{html}}. Be sure to pass in 'html' => $html in the vars array
You can also pass an array or an object to the view, and then use the twig attribute() method: http://twig.sensiolabs.org/doc/functions/attribute.html
{% if attribute(array, key) is defined %}
{{ attribute(array, key) }}
{% endif %}
I know how to get block data by module_invoke(),
but how to use standard block theme for rendering it.
I tried to use theme() function but with no success.
Could somebody give me advice?
Regards
Taken from the API comments for theme_block
// setup vars
$module = 'system';
$delta = 0; // could also be a string
// renders the "Powered by Drupal" block
// #see hook_block()
// #see module_invoke()
$block = module_invoke($module, 'block', 'view', $delta);
// must be converted to an object
$block = !empty($block) ? (object)$block : new stdclass;
$block->module = $module;
$block->delta = $delta;
$block->region = 'whateverYouWant';
echo theme('block',$block);
Haven't tested it but it seems to be doing what you want. This uses the regular theme function to theme the block you are retrieving
I've created a cck filed of type textarea with name filed_desc, how do i get this field to index in solr.
i found this article http://acquia.com/blog/understanding-apachesolr-cck-api, i have tried this but it is not indexing the filed, can somebody help.
<?php
// $Id$
/**
* Implementation of hook_apachesolr_cck_fields_alter
*/
function example_apachesolr_cck_fields_alter(&$mappings) {
// either for all CCK of a given field_type and widget option
// 'filefield' is here the CCK field_type. Correlates to $field['field_type']
$mappings['text'] = array(
'text_textarea' => array('callback' => 'example_callback', 'index_type' => 'string'),
);
}
/**
* A function that gets called during indexing.
* #node The current node being indexed
* #fieldname The current field being indexed
*
* #return an array of arrays. Each inner array is a value, and must be
* keyed 'value' => $value
*/
function example_callback($node, $fieldname) {
$fields = array();
foreach ($node->$fieldname as $field) {
// In this case we are indexing the filemime type. While this technically
// makes it possible that we could search for nodes based on the mime type
// of their file fields, the real purpose is to have facet blocks during
// searching.
$fields[] = array('value' => $field['field_desc']);
}
return $fields;
}
?>
I am currently working on adding this in a nice, pretty, generic way. If you really need this working now, take a look at this issue on Drupal.org. My code is currently living at GitHub, though hopefully I can get this included upstream and make a release of it.
Hope that helps!
Per field mapping is easier to control.
alter function:
$mappings['per-field']['field_specialities'] = array(
'index_type' => 'string',
'callback' => 'ge_search_apachesolr_field_specialities_callback'
);
callback:
function ge_search_apachesolr_field_specialities_callback($node, $fieldname)
{
$fields = array();
foreach($node->$fieldname as $field) {
$fields[] = array('value' => $field['value']);
}
return $fields;
}