I am slowly learning D8 while implementing my website, and decided to follow https://www.webwash.net/how-to-create-powerful-container-paragraphs-in-drupal-8/ to start my landing page.
Starting the hook_preprocess section, I assumed this would go in:
THEMES/MYBOOTSTRAPSUBTHEME/MYTHEMENAME.theme
<?php
/**
* #file
* Bootstrap sub-theme.
*
* Place your custom PHP code in this file.
*/
function MYSUBTHEMENAME_preprocess_paragraph__banner(&$variables) {
$paragraph = $variables['paragraph'];
if (!$paragraph->field_image->isEmpty()) {
$image = $paragraph->field_image->entity->url();
$variables['attributes']['style'][] = 'background-image: url("' . $image . '");';
$variables['attributes']['style'][] = 'background-size: cover;';
$variables['attributes']['style'][] = 'background-position: center center;';
}
}
I have cleared cache from the Configuration page with no luck. This is built localhost using MAMP (PHP 7.1.6) - if of any use.
I have double checked all the configurations that the tutorial shows and all the names are correct (banner, field_image). I just can't seem to find the issue!
Any suggestions?
If it is not a typo your themename is not MYBOOTSTRAPSUBTHEME, it is MYTHEMENAME as you said:
THEMES/MYBOOTSTRAPSUBTHEME/MYTHEMENAME.theme
Therefore the function should be called:
function MYTHEMENAME_preprocess_paragraph__banner(&$variables) {
// If devel module is enabled you may check if it is working
// by adding some debug output:
// dpm('debug');
}
Make sure to use lowercase letters for directory- file and function name. After implementing the function do not forget to rebuild cache. It's not necesary to have a twig template file paragraphs-banner.twig, it should work without that too.
Related
I updated a website to Drupal 8.9.6 version. I saw that the global variable $pager_total_items was used, but is deprecated since D8.8.0.
So, I'm looking for an alternative to retrieve the total items of the pager.
This was used on a Search API page.
The old code looks like this :
$variables['count_results'] = empty($GLOBALS['pager_total_items']) ? 0 : $GLOBALS['pager_total_items'][0];
And now, looking this change record : https://www.drupal.org/node/2779457 I try to replace this like this :
/** #var \Drupal\Core\Pager\PagerManager $pagerManager */
$pagerManager = \Drupal::service('pager.manager');
dpm($pagerManager->getPager());
This renders nothing in the dpm(), so no Pager was found. It appears that Search API doesn't use a Pager...
This works for me:
$pager = \Drupal::service('pager.manager')->getPager();
$count_results = $pager->getTotalItems();
I am very much new to drupal 8, I am trying to alter a form under custom content type "Question". The form has an id "node-question-form".
I have setup a module and trying to add hook_FORM_ID_alter() but its never getting called. Even the simplest hook is not working. eg:
function constellator_form_alter(&$form, &$form_state, $form_id){
echo "alter the form"; exit;
}
where 'constellator' is the module name.
I have been stuck with since morning and nothing is working for me, Any help will be greatly appriciated.
Cheers
hook_form_alter() and hook_FORM_ID_alter() are called while a form is being created and before displaying it on the screen.
These functions are written in the .module file.
Always clear the cache after writing any hook function. This makes Drupal understand that such a function has been declared.
Use drush cr if using drush version 8 else click on Manage->Drupal 8 logo->Flush all Caches to clear the caches.
Now you can check if the function is being called or not.
The best way to check that is to install the Devel module, enable it. Along with Devel, Kint is installed. Enable Kint too from the Admin UI.
After doing that,you can check whether the hook is being called or not in the following way:
function constellator_form_alter(&$form, &$form_state, $form_id){
kint($form);
}
This will print all the form variables for all forms in the page.
If you want to target a particular form in the page, for eg. you form, node-question-form, type:
function node_question_form_form_alter(&$form, &$form_state, $form_id){
kint($form);
}
Using echo, the way you did, you can confirm whether the function is being called or not, without any hassle, by viewing the Source Code for the page and then searching for the text that you have echoed, using some search option of browser, like, Ctrl+f in case of Google Chrome.
If you want to change sorting options and/or direction (ASC / DESC), you can use this example (tested with Drupal 9).
Here I force the sorting direction according to the "sort by option" set by the user in an exposed filter. (if the user want to sort by relevance, we set the order to ASC, if the user want to sort by date, we set the order to DESC to have the latest content first).
/**
* Force sorting direction for search by date
*
*/
function MYTHEME_form_alter(&$form, &$form_state, $form_id)
{
if (!$form_id == 'views_exposed_form"' || !$form['#id'] == 'views-exposed-form-search-custom-page-1') {
return;
}
$user_input = $form_state->getUserInput();
if (empty($user_input['sort_by'])) {
return;
}
if ($user_input['sort_by'] == 'relevance') {
$user_input['sort_order'] = 'ASC';
} elseif ($user_input['sort_by'] == 'created') {
$user_input['sort_order'] = 'DESC';
}
$form_state->setUserInput($user_input);
}
Note that "views-exposed-form-search-custom-page-1" is the id of my form,
"relevance" and "created" are the sort field identifier set in drupal admin.
function hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface &$form_state, $form_id) {
echo 'inside form alter';
}
Let me start by saying I have absolutely no idea what I should be doing because the documentation and available information on Assetic is either limited or Symfony oriented.
Here is my folder structure.
Assetic
+ assets
+ css
+ example.css
+ docs
+ src
+ tests
+ vendor
+ index.php
+ styles.php
Now, I have the following test code. Basically I cloned a clean copy of Assetic and ran composer install. Then I create an index.php file which simply links to my styles.php file with HTMLs <link> tag.
Here is my styles.php
<?php
require 'vendor/autoload.php';
$assetPath = __DIR__.'/assets/css/example.css';
$assetBasePath = __DIR__.'/assets/css';
$asset = new Assetic\Asset\FileAsset($assetPath, array(), $assetBasePath, 'example.css');
header('Content-Type: text/css');
$asset->setTargetPath(__DIR__);
echo $asset->dump(new Assetic\Filter\CssRewriteFilter);
Here is my example.css stylesheet.
body {
background-image: url('../img/background.png');
}
When I load up the styles.php in my browser I get the following output.
url('../img/background.png');
That's the same as the actual CSS. If I use the CSS URI Rewriter from Mr. Clay I get the expected output.
url('/Assetic/assets/img/background.png');
So what am I doing wrong with Assetic? I have no idea what paths I should be passing in and to where.
Thanks.
Just a pretty hard time with it, but finally (after reading the doc. of webassets, python library on which assetic is based) I won over the lack of documentation.
Here you go
<?php
require 'vendor/autoload.php';
$assetPath = __DIR__.'/assets/css/example.css';
$asset = new Assetic\Asset\FileAsset($assetPath, array(new Assetic\Filter\CssRewriteFilter), dirname($assetPath), '/assets/css');
// I assume the 'assets' directory is at the root of your website
header('Content-Type: text/css');
$asset->setTargetPath('/path/to/dumped/asset');
// As above, it's the path to the generated asset from your http root
echo $asset->dump();
I'm not sure to be very clear, so ask if you didn't understand something.
From another forum I found the following example:
"I was looking for a way to pull node data via ajax and came up with the following solution for Drupal 6. After implementing the changes below, if you add ajax=1 in the URL (e.g. mysite.com/node/1?ajax=1), you'll get just the content and no page layout.
in the template.php file for your theme:
function phptemplate_preprocess_page(&$vars) {
if ( isset($_GET['ajax']) && $_GET['ajax'] == 1 ) {
$vars['template_file'] = 'page-ajax';
}
}
then create page-ajax.tpl.php in your theme directory with this content:
<?php print $content; ?>
"
This seems like the logical way to do it and I did this, but the phptemplate_preprocess_page function is never called ... any suggestions?
I figured it out for myself from a Drupal Support Theme Development page:
"Maybe this helps
leahcim.2707 - May 29, 2008 - 05:40
I was trying to get the same thing done and for me this works, but I'm not sure if it is the correct way as I'm still new to Drupal:
in "template.php" I added the following function:
function phptemplate_preprocess_page(&$vars)
{
$css = $vars['css'];
unset($css['all']['module']['modules/system/system.css']);
unset($css['all']['module']['modules/system/defaults.css']);
$vars['styles'] = drupal_get_css($css);
}
I think after adding the function you need to go to /admin/build/themes so that Drupal recognises the function."
The part in bold is what did the trick ... you have to re-save the configuration so it recognizes that you've added a new function to the template.
I am using both Zend framework and Django, and they both have they strengths and weakness, but they are both good framworks in their own way.
I do want to create a highly modular web application, like this example:
modules:
Admin
cms
articles
sections
...
...
...
I also want all modules to be self contained with all confid and template files.
I have been looking into a way to solve this is zend the last days, but adding one omer level to the module setup doesn't feel right. I am sure this could be done, but should I? I have also included Doctrine to my zend application that could give me even more problems in my module setup!
When we are talking about Django this is easy to implement (Easy as in concept, not in implementation time or whatever) and a great way to create web apps. But one of the downsides of Django is the web hosing part. There are some web hosts offering Django support, but not that many..
So then I guess the question is what have the most value; rapid modular development versus hosting options!
Well, comments are welcome!
Thanks
You can implement sub-modules with relatively little effort in ZF. Let's say you have directory structure such as:
application/
modules/
admin/
cms/
controllers/
views/
controllers/
views/
You'd register the modules like this in your bootstrap (sub-modules use _ to separate the sub-module from the main module):
$frontController->setControllerDirectory(array(
'default' => APPLICATION_PATH . '/modules/default/controllers',
'admin' => APPLICATION_PATH . '/modules/admin/controllers',
'admin_cms' => APPLICATION_PATH . '/modules/admin/cms/controllers'
));
The issue with this is that it would actually use an underline in the URL instead of a slash, so eg: "admin_cms/conteroller/action" instead of "admin/cms/controller/action". While this "works", it's not pretty. One way to solve the issue is to provide your own route for the default route. Since the default Zend_Controller_Router_Route_Module does it almost right, you can simply extend from it and add the wanted behavior:
<?php
class App_Router_Route_Module extends Zend_Controller_Router_Route_Module
{
public function __construct()
{
$frontController = Zend_Controller_Front::getInstance();
$dispatcher = $frontController->getDispatcher();
$request = $frontController->getRequest();
parent::__construct(array(), $dispatcher, $request);
}
public function match($path)
{
// Get front controller instance
$frontController = Zend_Controller_Front::getInstance();
// Parse path parts
$parts = explode('/', $path);
// Get all registered modules
$modules = $frontController->getControllerDirectory();
// Check if we're in default module
if (count($parts) == 0 || !isset($modules[$parts[0]]))
array_unshift($parts, $frontController->getDefaultModule());
// Module name
$module = $parts[0];
// While there are more parts to parse
while (isset($parts[1])) {
// Construct new module name
$module .= '_' . $parts[1];
// If module doesn't exist, stop processing
if (!isset($modules[$module]))
break;
// Replace the parts with the new module name
array_splice($parts, 0, 2, $module);
}
// Put path back together
$path = implode('/', $parts);
// Let Zend's module router deal with the rest
return parent::match($path);
}
}
And in your bootstrap:
$router = Zend_Controller_Front::getInstance()->getRouter();
$router->addRoute('default', new App_Router_Route_Module);
What this does is traverse the path as long as it finds a module, and transparently rewrites the path so that the default Zend_Controller_Router_Route_Module can do the real work. For example the following path: "/admin/cms/article/edit" will be transformed into "/admin_cms/article/edit", which allows the standard convention of the ZF's ":module/:controller/:action" do the magic.
This allows you to have nice modular structure with self-contained modules, while still use pretty, logical URLs. One thing you want to make note of is that if you use Zend_Navigation and specify the navigation items using module/controller/action parameters, you need to tell ZF how to correctly build the URL using "/" instead of "_" in module names (by default ZF uses the :module/:controller/:action spec when it builds the URLs). You can do this by implementing your own Zend_Controller_Action_Helper_Url, like this:
<?php
class App_Router_Helper_Url extends Zend_Controller_Action_Helper_Url
{
public function url($urlOptions = array(), $name = null, $reset = false, $encode = false)
{
// Replace the _ with / in the module name
$urlOptions['module'] = str_replace('_', '/', $urlOptions['module']);
// Let the router do rest of the work
return $this->getFrontController()->getRouter()->assemble($urlOptions, $name, $reset, $encode);
}
}
And in your bootstrap:
Zend_Controller_Action_HelperBroker::addHelper(new App_Router_Helper_Url);
Now Zend_Navigation works nicely with your sub-module support as well.
I (despite of being happy ZF user) would go for Django. In ZF the "fully-modular" application is kind of holly grail. It's nearly impossible (or at least without extreme effort) to create selfcontained modules, instalable like "copy this folder into your modules directory" :) Not sure about Django, but from what I head it's simplier there...