Help me figure out why isn't my form getting styled a la sites/all/modules/pecapture/themes/pecapture-displayform.tpl.php
Here's my code:
/**
* Implementation of hook_theme()
*/
function pecapture_theme() {
$path = drupal_get_path('module', 'pecapture') . '/theme';
return array(
'pecapture_displayform' => array(
'arguments' => array('form' => NULL),
'template' => 'pecapture-displayform',
'path' => $path,
),
);
}
Basically this says that theme files are in the module/theme folder ($path)
There is a theme function pecapture_displayform($form = NULL), called using theme('pecapture_displayform', $form) where $form is a Drupal form array
There is a template file pecapture_displayform.tpl.php at $path
function pecapture_block($op = 'list', $delta = 0, $edit = array()) {
$block = array();
if ($op == "list") { // Generate listing of blocks from this module, for the admin/block page
$block[0]["info"] = t('Persistent E-mail Capture Form Block');
}
else /* if ($op == 'view') */ { // Generate our block content
$block['subject'] = ''; //'Persistent E-mail Capture Form';
$block['content'] = pecapture_displayForm();
}
return $block;
} // function pecapture_block
This says that when you are viewing the block, use the function pecapture_displayForm() to generate the contents. $block gets php print()ed
/**
* Callback for pecapture_theme
*/
function pecapture_displayform() {
return drupal_get_form('pecapture_blockform');
}
This says return the html formatted drupal form array (for output)
function pecapture_blockform(&$form_state) {
/* the form, standard ... */
This is the form contents, it's typical.
I've tried calling the theme function explicitly in pecapture_displayform:
return theme('pecapture_displayform', $form);
and
return theme('pecapture_displayform', drupal_get_form($form));
So why is the form not going through pecapture-displayform.tpl.php ?
There's two basic ways of creating themes from a module - using a theme function, or using a template. In both cases, you need to register the themes in the hook_theme function for your module (pecapture_theme). That part of your example looks right.
If you register a theme function, you then create the theme function, and call it theme_themename. If you register a template (like you did) you use an optional template_preprocess function and a template. Template_preprocess functions are called template_preprocess_themename and are passed, by reference, an array of variables to be then passed to the template. Also, you should never directly call a theme function. Always uses theme('themename', $args) to access a theme so that drupal can handle it correctly (allows overriding, and correct variable preprocessing).
So, first of all, it looks like you're trying to directly call a theming function that drupal doesn't recognize as theme function. Second, you're using a template, so you need a function called template_preprocess_pecapture_displayform(&$vars) if you want to process the form before sending it to the template. Also make sure your template is called pecapture-display.tpl.php so it matches exactly the name you supplied in hook_theme except for the extension.
Also, it looks like you're trying to theme a form. So, you'll need to tell drupal_get_form to use your theme by including $form['#theme'] = 'pecapture_displayform' in your form function. You can output individual form elements in your theme by calling drupal_render($form['element']), calling drupal_render($form) will render any remaining un-rendered elements (drupal keeps track so they won't be rendered twice).
See http://api.drupal.org/api/drupal/developer--topics--forms_api.html/6 for more information on theming forms.
As long as you've specified the theme in your form function you won't need to call it explicitly, so you should be able to do
$block['content'] = drupal_get_form('pecapture_blockform');
in your block hook.
Related
I want to create a CakePHP Widget in order to create a custom form control. The end goal is to make it a plugin, but for now I am trying to determine the general structure of a Widget. I have created a file in src/View/Widget/DateTimeWidget.php containing
<?php
namespace App\View\Widget;
use Cake\View\Form\ContextInterface;
use Cake\View\Widget\WidgetInterface;
class DateTimeWidget implements WidgetInterface
{
protected $_templates;
public function __construct($templates)
{
$this->_templates = $templates;
}
public function render(array $data, ContextInterface $context)
{
$data += [
'name' => '',
];
return $this->_templates->format('DateTime', [
'name' => $data['name'],
'attrs' => $this->_templates->formatAttributes($data, ['name'])
]);
}
public function secureFields(array $data)
{
return [$data['name']];
}
}
?>
I load the Widget in a View with the code
$this->Form->addWidget(
'datetime',
['DateTime']
);
and then create a form control with it using
echo $this->Form->control('end_time', ['type' => 'datetime']);
However, I get the error Cannot find template named 'DateTime'.
I have created the basic template code
<?php
$this->Form->setTemplates([
'DateTime' => '<p {{attrs}}>Test template</p>'
]);
But I have no idea where in the folder structure to put it? In most plugins I have looked at it is in a helper file, but I wonder if this is the default way to do it? What are my options? And how do i tell CakePHP to load it? What is the preferred way of doing this?
Thank you!
If you want your widget to come with default string templates, then you could for example define them in the widget itself, by adding it to the string template instance that is being passed to the widget's constructor. You'd do it in the widget's render() method though, it wouldn't work properly in the constructor, as widget instances are being reused, ie they are only being constructed once, for example:
public function render(array $data, ContextInterface $context)
{
if (!array_key_exists('customDateTime', $this->_templates->getConfig())) {
$this->_templates->add([
'customDateTime' => '<p {{attrs}}>Test template</p>',
// ...
]);
}
// ...
}
Another option is to put the string templates in a config file:
// in path_to_your_plugin/config/form_helper_templates.php
<?php
return [
'customDateTime' => '<p {{attrs}}>Test template</p>',
// ...
];
and ask the users to load the form helper string templates in their view templates when they want to use your widgets:
$this->Form->templater()->load('YourPluginName.form_helper_templates');
Both options will integrate properly with the form helper, so that users can still override the templates by setting custom templates either via FormHelper::setTemplates(), StringTemplate::load()/add(), or the templates option for FormHelper::control().
I think you should use Cells for it.
Take a look at: https://book.cakephp.org/3/en/views/cells.html
I created my prestashop module, with a hook to display my specific search form.
public function hookDisplayTopColumn($params)
{
$this->context->controller->addCSS($this->_path.'css/modelfilter.css', 'all');
$this->context->controller->addJS($this->_path.'js/modelfilter.js');
$marque = $this->getSubCategories($this->marquesCategory);
$this->context->smarty->assign(array(
'marques' => $marque,
));
return $this->display(__FILE__, 'form_model.tpl');
}
JS and CSS files are not included. To find why, I added a parse line in classes/controller/FrontController.php :
public function addMedia($media_uri, $css_media_type = null, $offset = null, $remove = false, $check_path = true)
{
echo 'addMedia '.$media_uri."<br/>\n";
And the result is : all css/js files appears before the beginning of the page (just after <body>), but my files comes just before displaying form_model.tpl
Please, how to make my files to be called in the good time ?
You shall not use $this->context->controller->addCSS and addJS outside of hookDisplayHeader().
When the header of your page is built hookDisplayHeader() is called to add headers elements. Once this hook is done, the header is built and can't be changed.
So when the hook hookDisplayTopColumn() is called, the header is already built.
To add your files you have to implement the hookDisplayHeader() in your module:
public function hookDisplayHeader($params)
{
$this->context->controller->addCSS($this->_path.'css/modelfilter.css', 'all');
$this->context->controller->addJS($this->_path.'js/modelfilter.js');
}
And remove those lines from hookDisplayTopColumn().
I can't seem to change the templates that the results function uses. I've taken the results function and modified the template but it's rendering with Page.ss instead of MyCustomResultTemplate.ss
public function results($data, $form, $request)
{
// [...]
$templates = array(
'MyCustomResultTemplate',
'Page'
);
return $this->owner->customise($data)->renderWith($templates);
}
MyCustomResultTemplate.ss exists in the correct templates folder and looks identical the the default Page_results.ss file yet still no luck.
Am I missing some route setting or something here?
We have built out our own version of the tinyMCE editor in SilverStripe. The only issue is that you need to hit refresh for our custom configuration to be loaded. Once it has been refreshed once, it sticks for the rest of the session.
Our set up is as follows:
BolierplateWYSIWYG.php
class BolierplateWYSIWYG extends Extension {
protected function defaults() {
$defaultEditorConfig = HtmlEditorConfig::get('cms');
$defaultEditorConfig->setOptions(
array(
'theme' => 'advanced',
'priority' => 1,
// More config options
)
);
return HtmlEditorConfig::get('cms');
}
public function getConfig() {
return $this->defaults();
}
}
Then, inside of Page.php we have the following:
... page functions ...
public function getCMSFields() {
$fields = parent::getCMSFields();
// Update WYSIWYG
$digital360Wysiwyg = new Digital360WYSIWYG;
$digital360Wysiwyg->getConfig();
... Page CMS configuration ...
Inside of our boilplate.yml we have:
HtmlEditorField:
extensions:
- BolierplateWYSIWYG
How do I get this new configuration to load without requiring a page refresh?
Like #assertchris mention, my PR https://github.com/silverstripe/silverstripe-framework/pull/4259/files has now been merge so you can easily have multiple TinyMCE configs which should help you with you extension.
Setup your HTMLEditorConfig in _config.php like
HtmlEditorConfig::get('default')->setOptions....
HtmlEditorConfig::get('fancy')->setOptions....
Since you have to have an extension, you could have something like:
class BolierplateWYSIWYG extends Extension {
public function setEditorConfig($name = 'default')
{
HtmlEditorConfig::set_active($name);
}
}
The you can use it like this when setting up your CMS fields
$digital360Wysiwyg = new Digital360WYSIWYG;
$digital360Wysiwyg->setEditorConfig();
or
$digital360Wysiwyg = new Digital360WYSIWYG;
$digital360Wysiwyg->setEditorConfig('fancy');
This should work fine. Although be careful when changing some of the editor options like mode, as this can cause your refresh issue. an you shouldn't have to change theme or priority?
Might want to check this pull request: https://github.com/silverstripe/silverstripe-framework/pull/4259
You can customise your HtmlEditorField by calling setOptions in your _mysite/config.php:
HtmlEditorConfig::get('cms')->setOptions(
array(
'theme' => 'advanced',
'priority' => 1,
// More config options
)
);
This will work without the need to refresh a CMS page.
I'm building a way to extend a WordPress plugin I'm developing using the following filter for grabbing the html content from a different plugin:
$content = apply_filters('satl_render_view', array($view, $slides));
With just one plugin this works perfectly, but once I activate a second plugin utilizing this same filter it stops working, $content is null for either plugin:
I'm adding the filters on the plugins in the __construct() method:
add_filter('satl_render_view', array('SatellitePortraitPlugin','addRender'));
and
add_filter('satl_render_view', array('SatelliteAwesomePlugin', 'addRender'));
Anyone run into this before?
In case it helps, this is the addRender method as it currently stands:
public static function addRender($params)
{
list($view, $slides) = $params;
$plugin = new SatelliteAwesomePlugin();
return $plugin->render($view, array('slides' => $slides, 'frompost' => 'false'), false);
}
For the record, I've tried remove_filter() if there is no content to return, but that didn't solve the problem.
Params get passed to callback function, in this case addRender() and contain all the HTML of what is wanted to display to the second plugin using that same filter. To utilize this bit of information one must change the method:
public static function addRender($params)
{
if (is_array($params)) {
list($view, $slides) = $params;
$plugin = new SatelliteAwesomePlugin();
return $plugin->render($view, array('slides' => $slides, 'frompost' => 'false'), false);
} else {
return $params;
}
}
You also need to make sure to update how the render() method passed the proper information back to the apply_filters method so the next plugin would have the proper array to run the addRender()
} else {
return array($file,$params['slides']);
}
Main Learning: WordPress apply_filters is much dumber than you'd think. You can't assume it merges everything for you, it just passes the information along and your code needs to make sense of it.