Global $pager_total_items replacment - drupal-8

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();

Related

MYTHEME_preprocess_paragraph__PARAGRAPHTYPE not loading

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.

Zend Regex Routes in Application.ini not recognized

I've been struggling with this problem the last 2 hours. I'm trying to add a regex-route to my Zend Framework (V1) application. My other routes are static and stored in my application.ini file and that is where i want to put some new regex-routes.
Before i continue to work on more complex regex routes i started to translate the following (working) route to a regex route:
resources.router.routes.shift-display.route = /shift/display/:id
resources.router.routes.shift-display.defaults.module = shift
resources.router.routes.shift-display.defaults.controller = index
resources.router.routes.shift-display.defaults.action = display
Here is what i came up with:
resources.router.routes.shift-display.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.shift-display.regex = "shift/display/(\d+)"
resources.router.routes.shift-display.defaults.module = shift
resources.router.routes.shift-display.defaults.controller = index
resources.router.routes.shift-display.defaults.action = display
resources.router.routes.shift-display.map.1 = id
resources.router.routes.shift-display.reverse = "shift/display/%d"
But it's not working. It seems the route isn't recognized by the router. When trying to open e.g. vh.localhost/shift/display/7 i get "Invalid controller specified (display)" so the router uses the default route. I also tried to prepend the regex-route with a slash. I tried to use the url-helper to generate links (with passed ID param) using the new regex-route and it works.
Anyone has a clue?
Sometimes is it just that simple. When definining the route, the mistake was made in that line:
resources.router.routes.shift-display.regex = "shift/display/(\d+)"
It has to be
resources.router.routes.shift-display.route = "shift/display/(\d+)"
4 hours for nothing. But at least I finally found it ;-)

Sitecore Multisite Manager and 'source' field in template builder

Is there any way to parametise the Datasource for the 'source' field in the Template Builder?
We have a multisite setup. As part of this it would save a lot of time and irritation if we could point our Droptrees and Treelists point at the appropriate locations rather than common parents.
For instance:
Content
--Site1
--Data
--Site2
--Data
Instead of having to point our site at the root Content folder I want to point it at the individual data folders, so I want to do something like:
DataSource=/sitecore/content/$sitename/Data
I can't find any articles on this. Is it something that's possible?
Not by default, but you can use this technique to code your datasources:
http://newguid.net/sitecore/2013/coded-field-datasources-in-sitecore/
You could possibly use relative paths if it fits with the rest of your site structure. It could be as simple as:
./Data
But if the fields are on random items all over the tree, that might not be helpul.
Otherwise try looking at:
How to use sitecore query in datasource location? (dynamic datasouce)
You might want to look at using a Querable Datasource Location and plugging into the getRenderingDatasource pipeline.
It's really going to depend on your use cases. The thing I like about this solution is there is no need to create a whole bunch of controls which effectively do he same thing as the default Sitecore ones, and you don't have to individually code up each datasource you require - just set the query you need to get the data. You can also just set the datasource query in the __standard values for the templates.
This is very similar to Holger's suggestion, I just think this code is neater :)
Since Sitecore 7 requires VS 2012 and our company isn't going to upgrade any time soon I was forced to find a Sitecore 6 solution to this.
Drawing on this article and this one I came up with this solution.
public class SCWTreeList : TreeList
{
protected override void OnLoad(EventArgs e)
{
if (!String.IsNullOrEmpty(Source))
this.Source = SourceQuery.Resolve(SContext.ContentDatabase.Items[ItemID], Source);
base.OnLoad(e);
}
}
This creates a custom TreeList control and passes it's Source field through to a class to handle it. All that class needs to do is resolve anything you have in the Source field into a sitecore query path which can then be reassigned to the source field. This will then go on to be handled by Sitecore's own query engine.
So for our multi-site solution it enabled paths such as this:
{A588F1CE-3BB7-46FA-AFF1-3918E8925E09}/$sitename
To resolve to paths such as this:
/sitecore/medialibrary/Product Images/Site2
Our controls will then only show items for the correct site.
This is the method that handles resolving the GUIDs and tokens:
public static string Resolve(Item item, string query)
{
// Resolve tokens
if (query.Contains("$"))
{
MatchCollection matches = Regex.Matches(query, "\\$[a-z]+");
foreach (Match match in matches)
query = query.Replace(match.Value, ResolveToken(item, match.Value));
}
// Resolve GUIDs.
MatchCollection guidMatches = Regex.Matches(query, "^{[a-zA-Z0-9-]+}");
foreach (Match match in guidMatches)
{
Guid guid = Guid.Parse(match.Value);
Item queryItem = SContext.ContentDatabase.GetItem(new ID(guid));
if (item != null)
query = query.Replace(match.Value, queryItem.Paths.FullPath);
}
return query;
}
Token handling below, as you can see it requires that any item using the $siteref token is inside an Site Folder item that we created. That allows us to use a field which contains the name that all of our multi-site content folders must follow - Site Reference. As long at that naming convention is obeyed it allows us to reference folders within the media library or any other shared content within Sitecore.
static string ResolveToken(Item root, string token)
{
switch (token)
{
case "$siteref":
string sRef = string.Empty;
Item siteFolder = root.Axes.GetAncestors().First(x => x.TemplateID.Guid == TemplateKeys.CMS.SiteFolder);
if (siteFolder != null)
sRef = siteFolder.Fields["Site Reference"].Value;
return sRef;
}
throw new Exception("Token '" + token + "' is not recognised. Please disable wishful thinking and try again.");
}
So far this works for TreeLists, DropTrees and DropLists. It would be nice to get it working with DropLinks but this method does not seem to work.
This feels like scratching the surface, I'm sure there's a lot more you could do with this approach.

How to generate media item link with id instead of path in Sitecore

Anyone knows how to generate links in sitecore with ID instead of item path?
If you use GetMediaUrl method from the API, I can get this URL:
/~/media/Images/Archive/content/News and Events/News_and_Events_Level2/20070419162739/iwhiz3.jpg
The problem with this approach is that if someone changes the media item name, removes it somewhere or deletes it, the above link will break.
I notice if I insert a media link from rich text editor, I get the link as below:
/~/media/14BDED00E4D64DFD8F74019AED4D74EB.ashx
The second link is better because it's using the item id, so if the actual media item is renamed, removed, or deleted, all related links will be updated too. On top of that, when Sitecore renders the page, it will actually convert the above link and display the item path so it's readable.
I'm using Sitecore 6.5 and currently doing content migration so I need to make sure all internal links are updated properly.
May I know if there is a method to generate the second link by using sitecore API?
Thanks!
The GetMediaItemUrl extension method seems to give you what you want.
public static class ItemExtensions
{
public static string GetMediaItemUrl(this Item item)
{
var mediaUrlOptions = new MediaUrlOptions() { UseItemPath = false, AbsolutePath = true };
return Sitecore.Resources.Media.MediaManager.GetMediaUrl(item, mediaUrlOptions);
}
}
[TestFixture]
public class when_using_items_extensions
{
[Test]
public void a_url_based_on_media_item_id_can_be_generated()
{
// Arrange
Database db = global::Sitecore.Configuration.Factory.GetDatabase("master");
Item item = db.GetItem("/sitecore/media library/Images/MyImage");
// Act
var mediaUrl = item.GetMediaItemUrl();
// Assert
Assert.That(mediaUrl, Is.EqualTo("/~/media/17A1341ABEEC46788F2159843DCEAB03.ashx"));
}
}
These are called dynamic links and you can normally generate them using the LinkManager e.g:
Sitecore.Links.LinkManager.GetDynamicUrl(item)
.. but I'm not sure of the method to do this with Media links (there probably is one but I cant seem to find it and its not on MediaManager) but the basic syntax is:
"/~/media/" + item.ID.ToShortID() + ".ashx"
If you always want to use ID's instead of paths, you can change this setting in webconfig to false (like this):
<setting name="Media.UseItemPaths" value="false"/>`
Here is what the webconfig describes about it:
MEDIA - USE ITEM PATHS FOR URLS
This setting controls if item paths are used for constructing media URLs.
If false, short ids will be used.
Default value: true
Then you can use the default implementation (without additional parameters):
Sitecore.Resources.Media.MediaManager.GetMediaUrl(item);
This is what I use:
var imgField = ((Sitecore.Data.Fields.ImageField)currentItem.Fields["Icon"]);
MediaUrlOptions opt = new MediaUrlOptions();
opt.AlwaysIncludeServerUrl = true;
// Absolute Path works as well. So either use AbsolutePath or AlwaysIncludeServerUrl
opt.AbsolutePath = true;
string mediaUrl = MediaManager.GetMediaUrl(imgField.MediaItem, opt);

Why is php_template_preprocess_page function not called in Drupal 6x?

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.