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.
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 am migrating and troubleshooting a wordpress theme. I have a gutenberg block and an alert module set up to use the Timber composer package that allows the use of the twig templating engine.
I have it configured in a class
ProcessorTable.php
<?php
namespace CRG\Blocks;
class ProcessorTable
{
public function __construct()
{
$this->createProcessorTable();
}
public function createProcessorTable()
{
if (function_exists('acf_register_block')) {
// register a custom vue gravity forms block
acf_register_block(array(
'name' => 'processor-table-block',
'title' => __('Processor Table Block'),
'description' => __('A Block for displaying a contracted database processors table'),
'category' => 'crg-custom-blocks',
'icon' => 'welcome-write-blog',
'render_callback' => array($this, 'render_processor_table'),
'keywords' => array( 'table' ),
));
}
}
public function render_processor_table($block, $content = '', $is_preview = false)
{
$context = \Timber\Timber::context();
// Store block values.
$context['block'] = $block
// Store field values.
$context['fields'] = get_fields();
// Store $is_preview value.
$context['is_preview'] = $is_preview;
$twigPath = TEMPLATEPATH . "/src/views/blocks/block-processor-table.html.twig";
\Timber\Timber::render($twigPath, $context, 600);
}
}
AlertNotification.php
<?php
namespace CRG\Controllers\SiteWide;
class AlertNotification {
public function AlertModal(){
$context = \Timber\Timber::context();
$context['alert_header_text'] = get_field('alert_header_text', 'options');
$context['alert_text'] = get_field('alert_text', 'options');
$context['alert_icon'] = get_field('alert_icon', 'options');
$context['alert_color'] = get_field('alert_color', 'options');
$context['alert_toggle'] = get_field('alert_toggle', 'options');
\Timber\Timber::render( TEMPLATEPATH . "/src/views/sitewide/alert-modal.html.twig", $context );
}
}
this code worked on a cpanel server and on nexcess managed wordpress hosting, but when I migrated it to kinsta the code stopped rendering. It looks like the Timber::context() works, and the method can find the html.twig files, but it can't render the twig template, and produces no errors
I have tried troubleshooting this by checking the composer package versions, reinstalling the timber composer package, testing the code outside of the class directly into the functions.php file, and verifying the code can reach and output the file contents as a string. I checked the error log files and was unable to find a solution, or a cause of the error.
Hosting configuration:
Kinsta Caching: disabled
Wordpress debugging is enabled
Running on PHP 7.4
Using MySQL
I added this to my functions.php file
\Timber\Timber::$locations = TEMPLATEPATH . "/src/views";
so everything in the functions.php file for timber to work would look like this
require_once(__DIR__ . '/vendor/autoload.php');
$timber = new Timber\Timber();
\Timber\Timber::$locations = TEMPLATEPATH . "/src/views";
then in my ProcessorTable.php file I can call the Twig file path like this
$twigPath = "/blocks/block-processor-table.html.twig";
return \Timber\Timber::render( $twigPath, $context);
My guess about what went wrong is that the timber package was looking in the wrong director when rendering, based on incorrect locations information the Timber:locations method allows you to set up a custom location to store the templates: https://timber.github.io/docs/guides/template-locations/
Not sure why this would have worked on other systems, but not Kinsta. However, this appears to be a good practice going forward by explicitly setting the views.
Is it possible? If I set $config['url_suffix'] = '/en'; in the file config.php itself everything is ok.
However if I want to set it like so: $ci->config->set_item('url_suffix', '/en'); in my hook class:
class Language_loader {
public function __construct()
{
}
public function initialize()
{
$ci =& get_instance();
$ci->db = $ci->load->database('english', TRUE);
$ci->config->set_item('url_suffix', '/en');
}
}
then it doesn't work! I get 404 Page Not Found. Oh, and hook is set up properly I tested with the above change of database.
Hook config in hooks.php:
$hook['post_controller_constructor'] = array(
'class' => 'Language_loader',
'function' => 'initialize',
'filename' => 'Language_loader.php',
'filepath' => 'hooks'
);
EDIT: Some more info I noticed, application redirects links properly with /en suffix its just when I get there instead of the site I get 404. So I guess it works but only half of it.
EDIT2: I can't set $this->config->set_item('url_suffix', '/en'); anywhere for that matter I tried various location throughout the script. I can set other variables in config file but not this url_suffix one. If I only knew when in the excecution codeigniter reads that value I could change it.
is there any posibillity to access a controller function from a php file that is based in resource/public/php/file.php
What I want is this php file is special file I use it for this:
<img src="file.php"></img>
I will disable readable paths. So this php file does some encryption and need a connection to a normal controller function.
thanks
is there any posibillity to access a controller function from a php file that is based in resource/public/php/file.php
Yes, it is possible but therefor you need to bootstrap the TYPO3 core as well. Or if it is a static and public method than you can call it directly.
But this seems not the right way to do it in your case.
Assuming you're working on some kind of captcha thing you should consider your own page type for rendering the dynamic images. Here's a working example:
TypoScript Setup
In TypoScript we're registering our own page typ and pointing it out to our extension, controller and action:
DynamicCaptchaImage = PAGE
DynamicCaptchaImage {
typeNum = 1234
10 = USER_INT
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
pluginName = Pi1
extensionName = MyExtName
vendorName = MyCompanyName
controller = MyExtbaseController
action = renderCaptchaImage
# view =< plugin.tx_myextname.view // you provide the view yourself
# persistence =< plugin.tx_myextname.persistence // in case you need a repository you should uncomment it
settings =< plugin.tx_myextname.settings
}
config {
disableAllHeaderCode = 1
additionalHeaders = Content-Type: image/png
xhtml_cleaning = 0
admPanel = 0
debug = 0
}
}
See also: Registering a custom typeNum-based Controller access
Controller
Here's an example how your controller and action should look like:
<?php
namespace MyCompanyName\MyExtName\Controller;
/**
* MyExtbaseController
*/
class MyExtbaseController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* Render Captcha Image Action
*
* #return void
*/
public function renderCaptchaImageAction() {
// Send some headers
header('Content-Type: image/png');
// < do your magic stuff here >
// Breaks the script because we've sent already some headers and want
// to prevent that TYPO3 is adding another stuff (eg. for debugging purposes)
// that can break the image from loading.
// return FALSE; does not stop doing that!
exit;
}
}
See also: Extbase wiki
Accessing the controller
Now we've configured the custom page type we're allowed to access the controller by calling the page type given in the TypoScript setup.
Eg. http://www.example.com?type=1234 points out to the renderCaptchaImageAction() in the MyExtbaseController.
Fluid
In Fluid you can link to the page type you've configured by:
<img src="{f:link.page(pageType: 1234)}" />
See also: Fluid wiki
Realurl
If you're using the extension realurl you can change ?type=1234 to captcha.png by:
// [...]
'fileName' => array(
'index' => array(
'captcha.png' => array(
'keyValues' => array(
'type' => 1234,
),
),
),
),
// [...]
See also: Realurl wiki
Bit of a long shot but can anyone shed any light on this?
I have recently installed the subsites module to run multiple sites from a single installation and am now getting the error: "I can't handle sub-URLs of a Form object." when I try to add descriptions/titles to image gallery objects. I have removed the subsites to verify that it is this which is causing the issue. I am using 2.4
I can upload images fine, however it is when trying to save a description from the popup that the issue arises.
I have tried with the default fields too and this still gives the same error.
My code:
<?php
class Gallery extends Page {
public static $db = array(
'SummaryText'=>'Text',
'GalleryText'=>'Text'
);
static $has_many = array(
'Photos' => 'GalleryPhoto'
);
function getCMSFields() {
$fields = parent::getCMSFields();
$manager = new ImageDataObjectManager(
$this, // Controller
'Photos', // Source name
'GalleryPhoto', // Source class
'Image' // File name on DataObject
);
$manager->uploadFolder = $this->URLSegment;
$fields->addFieldToTab('Root.Content.Main', new TextField('SummaryText', 'Summary Text (Appears in the section preview)'), 'Content');
$fields->addFieldToTab('Root.Content.Main', new TextField('GalleryText', 'Gallery Text (entering anything in here will overwrite any image Titles and Descriptions)'), 'Content');
$fields->addFieldsToTab("Root.Content.Gallery", array($manager));
$fields->removeFieldFromTab('Root.Content', 'StyledText');
$fields->removeFieldFromTab('Root.Content', 'Column2');
$fields->removeFieldFromTab('Root.Content', 'Content');
return $fields;
}
}
..
<?php
class GalleryPhoto extends Photo {
public static $db = array(
'HTMLDescription'=>'HTMLText'
);
static $has_one = array(
'Gallery' => 'Gallery'
);
public function getCMSFields(){
$fields = parent::getCMSFields();
$fields->removebyname('Description');
$fields->removebyname('Title');
$fields->replaceField('HTMLDescription', new SimpleTinyMCEField('HTMLDescription'));
return $fields;
}
}
Unfortunately "I can't handle sub-URLs of a Form object." is a pretty generic error message and from my experience rather tricky to debug.
To be honest, the Subsites module isn't that great in my opinion, it works, but its not that nice and not really compatible with other modules I guess.
I could imagine that the reason for your error is because silverstripe forgets the SubsiteID inside the popup and because of that SilverStripe can no longer find the current Page you are editing (because it adds a filter WHERE SubsiteID = x to every query of Pages you make)
one place to start debuging would be hooking into Subsite::currentSubsiteID() and see if it remembers the SubsiteID when you are in the popup
also, what is the exact url that gets called when you get the error message?
I just had the same error, searched for hours. It was a problem with /framework/control/Session.php