We have our site running on Drupal. Now I have 2 landingpages: pages without menu's and a bit different in layout as the others. I want to edit the complete HTML of the pages in the Drupal-interface, so marketeers can easily add HTML-snippets (for testing etc), without using a developer.
How could I create an empty header and footer, and let the complete HTML be the content?
You could create a specific node type, and then use this function in your template.php :
<?php
function theme_preprocess_page(&$variables)
{
if (isset($variables['node']->type))
{
$nodetype = $variables['node']->type;
$variables['theme_hook_suggestions'][] = 'page__' . $nodetype;
}
}
It will allows you to create templates for pages (Drupal is only offering this possibility for the page content) based on node types using page--node-type.tpl.php, so that you'll be able to customize the entire page html instead of just the content.
Related
I have created several sections with plain HTML and CSS that I would like to use as "wrapper" sections for my clients to be able to populate using Elementor drag and drop interface. I have tried to do this creating a custom Elementor widget, but there is no "Controls_Manager::NAME_OF_CONTROL" that I could find that would correspond to an Elementor section or inner section. (Controls_Manager::WYSIWYG is actually just a text editor).
I've also tried creating an elementor section template that has two HTML blocks: one above and one below an empty elementor section. Like this:
---------- begin HTML (Elementor or Wordpress type) block ----------
<div class="myOpeningSectionDiv"> <!-- no, it's not just a single div, I'm using opening div as an example here for brevity -->
---------- end first HTML block ----------
---------- standard empty Elementor block with the little + button goes here ----------
---------- begin second HTML (Elementor or Wordpress type) block ----------
</div>
---------- end second HTML block ----------
This does not work, because Elementor wraps those custom HTML blocks in its own html tags which breaks things.
The closest I solution I could find is creating two templates. One template is the contents simple Elementor drag and drop contents that the client can edit. The second contains just one custom HTML block with a short-code pointing towards the first template. The client would then insert that into their page. This is not ideal because 1) When you preview the page, the contents of the shortcoded section do not show up, and 2) they have to edit that section separately from the rest of the page in the templates area and can't create other sections like it without messing with HTML directly or getting me involved.
I've been searching the internet for two days for a solution and came up short. Is this possible to do?
And no, I don't think I can use a theme page template, because I need them to be able to drag and drop other sections with elementor above and below this section.
To summorize I'm trying to do this:
[Some elemnentor drag and drop content]
<someCustomReusableHtmlIWroteHere>
[Section where you can drag and drop buttons, text, form, etc using Elementor]
</someCustomReusableHtmlIWroteHere>
[Some more elemnentor drag and drop content]
I hope I'm explaining this correctly. As far as software used: latest Wordpress and Elementor Pro.
Use Elementor PHP Hooks for this:
For example:
add_action( 'elementor/frontend/section/before_render', function ( \Elementor\Element_Base $element ) {
if('section' === $element->get_name()){
// your code here
}
} );
add_action( 'elementor/frontend/section/after_render', function ( \Elementor\Element_Base $element ) {
if('section' === $element->get_name()){
// your code here
}
} );
The only issue is that while this works on the actual rendered page,it doesn't show the extra HTML in the preview in Elementor. This seems to be an issue with the before_render and after_render hooks.
you can use Unlimited Elements for Elementor,
this plugin has functionality to create own widget with html, css and JS.
then you can re-use that widget anywhere on website.
https://wordpress.org/plugins/unlimited-elements-for-elementor/
I am using Drupal with the Commerce Module to build a webshop. I am using the Commerce Cart Block to display a cart icon with the amount of items in the cart, in the navigation bar.
Now I would also like to display the Cart Block on the Cart page, but with a different template than being used in the navigation bar.
I am using the debug mode, which let me see what I could call the file names to use them like I would like to. But above both Cart Blocks it says the same file name, so I can't output two different templates. I tried putting primary_menu-- before the navigation cart block and content-- (the region the cart block is going to be in), but they don't work.
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'commerce_cart_block' -->
<!-- BEGIN OUTPUT from 'themes/custom/verdamigo/templates/commerce-cart-block.html.twig' -->
This is shown above both cart blocks (which are on the same page). So how can I use two different templates for both blocks.
primary_menu--commerce-cart-block.html.twig
is not working.
I would like to be able to edit both the block in the primary_menu and the block in the content-region. But both carts get output with the same template.
In an effort to decouple Blocks from Displays, Drupal 8 renders a block independently of which display it's in and what region/weight it has in that display (see Twig Template naming conventions) :
Region-specific block templates are not available in Drupal 8.
This removes the ability to override block.tpl.php by region, and for hook_preprocess_block() to adjust variables based on it. Instead, core developers recommend to manage block template overrides with CSS or using additional blocks.
But you can still work around this by implementing hook_theme_suggestions_HOOK_alter() :
function SOME_theme_suggestions_block_alter(array &$suggestions, array $variables) {
if (!empty($variables['elements']['#id'])) {
$block_id = $variables['elements']['#id'];
$block = Drupal\block\Entity\Block::load(block_id);
$region = $block->getRegion();
// Allow per-region block templating.
$suggestions[] = 'block__' . $region . '__' . $block_id;
}
return $suggestions;
}
Note : the template name should begin with "block" since you override a block template, so in your case the override file should be named block--primary_menu--commerce-cart-block.html.twig.
Setup
I want to transfer data from my project to a TYPO3 instance. Assume I have an HTML export that generates about 20 different HTML files inside my TYPO3 directory. These files contain data from a different system and the data updates quite frequently, so I am overwriting them regularly with the newest information.
Problem
I would like to tell TYPO3 to load the HTML contents of each file as its own page. Please note: the pages are not complete html documents (no <html> or <body> tags). Instead, I want whatever code is in those files to be displayed inside the context of a TYPO3 page. Kind of like a TYPO3 HTML PageContent, but I want the source for the HTML to be from a file.
I don't care if I have to manually set up each page, but I haven't found any way to let a TYPO3 Page or PageContent get its data from a file. Do you know of any way this would be possible?
Note: iframe isn't a solution in my case. I am using TYPO3 7.6.23
My answer is based on the following assumptions:
You have you have a "frontend provider extension" EXT:yourext; if not you can change every path like EXT:yourext/Resources/Private/Etcetera with the proper ´fileadmin/etcetera/Resources/Private/Etcetera´
You use backend_layout on database to store the backend layout and use that field to control the frontend template. I don't remember if in version 7 you can also use the filesystem using key.data=pagelayout
of course you have to adjust the IDs of the backend_layout items
the files to include will be partials, stored in the folder EXT:yorext/Resources/Private/Partials/ and will be named
MyFileToIncludeOne.html
MyFileToIncludeTwo.html
et cetera
The basic TypoScript will be something like:
page.10 = FLUIDTEMPLATE
page.10{
templateName= TEXT
templateName.stdWrap {
cObject = CASE
cObject {
key.data = levelfield:-2,backend_layout_next_level,slide
key.override.field = backend_layout
//I assume you already have some templates
1 = TEXT
1.value = Default
2 = TEXT
2.value = Home
//The layouts for the "pages with html files" begin here
10 = TEXT
10.value = MyFileOne
11 =TEXT
11.value = MyFileTwo
}
}
layoutRootPaths {
0 = EXT:yourext/Resouces/Private/Layouts/Page/
}
partialRootPaths {
0 = EXT:yourext/Resouces/Private/Partials/Page/
}
templateRootPaths {
0 = EXT:yourext/Resouces/Private/Template/Page/
}
}
So, in the previous lines,
the template MyFileOne.html will include the partial MyFileToIncludeOne.html, with just writing in it:
<f:render partial="MyFileToIncludeOne"/>
You could also use distinct paths if you want to keep the files separated:
partialRootPaths {
0 = EXT:yourext/Resouces/Private/Partials/Page/
1 = fileadmin/some/other/path/
}
I hope I have not forgotten important passages. Feel free to ask for clarifications
We have a component that contains a background image. Our front-end guy needs it to be loaded through CSS (i.e. background: url(/*path here*/)...). The following is a possible solution we came up with:
#string src = // Get image path from Sitecore().Field("Picture");
<div style="background: url(#src) left top no-repeat;"> ... </div>
However, there are two problems with this approach:
It makes it very difficult for the content editor to swap out the image. They will have to manually change it through edit item.
It feels like a hack/workaround.
So the question is as follows: Is there a way to edit the CSS of an element through Razor/Sitecore? Specifically, the background: field.
I had a similar case and I used :
<footer class="layout_footer" style="background-color: #Model.BackgroundColor">
on view rendering (cshtml file)
And on the model we have :
public string BackgroundColor
{
get
{
Sitecore.Data.Fields.ImageField imgField =((Sitecore.Data.Fields.ImageField)item.Fields["BackgroundImage"]);
return Sitecore.Resources.Media.MediaManager.GetMediaUrl(imgField.MediaItem);
}
}
For editing this field in page editor you can use Sitecore Field Editor from a command : http://blog.istern.dk/2012/05/21/running-sitecore-field-editor-from-a-command/
Check for edit mode, and display in edit mode a editable field. Also create a Custom Experience Button from the Field Editor Button Type. You can also display. See User friendly developing with the Sitecore Experience Editor
#string src = // Get image path from Sitecore().Field("Picture");
<div style="background: url(#src) left top no-repeat;">
#if (IsInEditingMode)
{
<h3>Backgroiund Picture: #Editable(m => m.Picture)</h3>
}
</div>
There is no Sitecore extension method which will do this out of the box (i.e. #Html.Sitecore().Field("fieldName") will not work here as it would render the entire image tag (also a load of other non-image markup in page editor mode) as you probably know.
The method that #sitecore climber mentions is useful for controller renderings (or view renderings with a custom RenderingModel). If you want to stick with simple view renderings (i.e. not create a RenderingModel) then you could create a Html extension method which can be re-used on any view rendering. This could be something like the following:
public string ImageFieldSrc(this SitecoreHelper sitecoreHelper, string fieldName, Item item = null)
{
if (item == null) {
item = sitecoreHelper.CurrentItem;
}
var imageField = new ImageField(item.Fields[fieldName]);
var mediaItem = imageField.MediaItem;
var mediaUrl = MediaManager.GetMediaUrl(mediaItem);
mediaUrl = HashingUtils.ProtectAssetUrl(mediaUrl); //if you want to use media request protection (adding the hash onto the end of the URL, use this line
return mediaUrl;
}
It's worth noting that if you are using Sitecore 7.5 or above there is a feature to protect media URLs with a hash to prevent malicious DoS type attacks described in this blog post by Adam Najmanowicz.
In summary; if you are using Sitecore 7.5+ and you use media hashing then you will need to call HashingUtils.ProtectAssetUrl on the media URL if it is to respect size parameters.
Introduce the Problem
I would like to profoundly modify the layout of the Orchard CMS Tags list.
Here is an example page with Shape Tracing enabled.
The only alternate that it suggests for the List shape is ~/Themes/TheThemeMachine/Views/List.cshtml, because the page is rendering the default List shape. I would like to have other alternates that are specific to the page.
After reading Orchard list customization, I have been able to implement the default List.cshtml in razor. What I would like to do, though, is to add another alternate, such as ~/Themes/TheThemeMachine/Views/Parts.Tags.List.cshtml instead of implementing the default List.cshtml template.
The problem seems to be that the page is rendering the generic List shape.
In contrast, the blog post list page is rendering a Parts_Blogs_BlogPost_List shape, which means that a ~/Themes/TheThemeMachine/Views/Parts.Blogs.BlogPost.List.cshtml is available.
Search and Research
All quotes below are from the Orchard list customization blog post, which explains how to add a list item alternate (whereas I would like to add a list alternate).
What we really want is an alternate template... aptly called Shape
Alternates... [so] enable Shape Tracing... and select a post in the list...
[you will see that] we already have some possible alternates.
My example page also has some possible alternates for the List Content. Cool.
we need to somehow get into list rendering... [t]he default is defined
in code... [which] can be override by a new [cshtml] template in our
theme.
Okay. That makes sense. We can override the list rendering.
As Shape Tracing can show, we can override the list rendering for a
blog by creating a Parts.Blog.BlogPost.List.cshtml template.
This works for alog but not for the blog Tag page (example page). You see, the blog displays a **Parts_Blogs_BlogPost_List shape and suggests an appropriate alternate but the blog tags page displays the default List shape with no alternates other than List.cshtml.
Blog Page with alternates galore
Blog Tags Page with one alternate List.cshtml
So, I created a List.cshtml not a Parts.Blog.BlogPost.List.cshtml template, and save it in my theme's Views directory. (One problem here is that, once we get it working, we will b overriding the default List rendering.)
Then I add the Razor code (copy and pasted from Bertrand's post) to override the default rendering for Lists. When I refresh the site, the browser renders a blank page. It isn't working. Here's the code:
This Does NOT Work in List.cshtml
#using Orchard.DisplayManagement.Shapes;
#{
var list = Model.ContentItems;
var items = list.Items;
var count = items.Count;
var listTag = Tag(list, "ul");
listTag.AddCssClass("content-items");
listTag.AddCssClass("blog-posts");
var index = 0;
}
#listTag.StartElement
#foreach (var item in items) {
var itemTag = Tag(item, "li");
if (index == 0) {
itemTag.AddCssClass("first");
}
else if (index == count - 1) {
itemTag.AddCssClass("last");
}
#itemTag.StartElement
#Display(item)
#itemTag.EndElement
++index;
}
#listTag.EndElement
As a trouble shooting step, I replace the List.cshtml with <p>Hello world.</p>. Orchard renders the markup as expected. So, something is incompatible between the Razor code from Bertrand's blog and the Tags List.
To find out what exactly is incompatible, I try Betrand's code one line at time to see where it breaks (yup, VS would be better than WM here). At each change, I restart WebMatrix and view the results. This is the minimal code that breaks it.
The Culprit
#using Orchard.DisplayManagement.Shapes;
#{
var list = Model.ContentItems;
var items = list.Items;
}
list.Items isn't appropriate here. So I comment it out again and run the <p>Hello World</p> version again. Also, Shape Tracing reveals that on my Tags/tagname page, the Content Zone is now rendering the List twice. Is that normal?
As another step, I replace Model.ContentItems just with Model. It works. It seems that, to override the List.cshtml template, we cannot use the ContentItems property of Model. Here is the new, working code:
This Does Work in List.cshtml
#using Orchard.DisplayManagement.Shapes;
#{
//var list = Model.ContentItems;
//var items = list.Items;
var items = Model.Items;
var count = items.Count;
//var listTag = Tag(list, "ul");
var listTag = Tag(Model, "ul");
listTag.AddCssClass("content-items");
listTag.AddCssClass("blog-posts");
var index = 0;
}
#listTag.StartElement
#foreach (var item in items) {
var itemTag = Tag(item, "li");
if (index == 0) {
itemTag.AddCssClass("first");
}
else if (index == count - 1) {
itemTag.AddCssClass("last");
}
#itemTag.StartElement
#Display(item)
#itemTag.EndElement
++index;
}
#listTag.EndElement
Onward through the article.
So far so good, we have effectively taken over the rendering of the
list, but the actual HTML [will] be... identical to what we had before
[except for] the implementation.
Okay. I'm following. We want to modify the rendering not just re-implement it.
Alternates are a collection of strings that describe additional shape
names for the current shape... in the Metadata.Alternates property of any shape.
Gotcha. Now, why doesn't the Tags/tagname page show an alternate other than just List.cshtml for the rendering of the List shape?
All we need to do is add to this list [of alternates]... [and make sure] to respect the lifecycle...
Great. Maybe we can we add another alternate for the List shape on the Tags/tagname page. But, doing that is different from what Betrand is explaining. While Betrand's blog post is excellent, it is explaining how to add an alternate for an item, whereas I would like to add an alternate for the list.
The List.cshtml template is where I would add an alternate for a List Item as follows:
ShapeMetadata metadata = item.Metadata;
string alternate = metadata.Type + "_" +
metadata.DisplayType + "__" +
item.ContentItem.ContentType +
"_First";
metadata.OnDisplaying(ctx => {
metadata.Alternates.Add(alternate);
});
So that...
[t]he list of alternates from Shape Tracing now contains a new item.
Where and how, though, would I add an alternate for the List shape? Bertrand has recommended to check out the Shape Table Providers blog post for this. The quotes below are from that post.
But what if you want to change another shape template for specific
pages, for example the main Content shape on the home page?
This looks like a fit, because my example is the main List shape on the tags page. To do this we...
... handle an event that is triggered every time a shape named "Content"
[in our case "List"] is about to be displayed. [It] is implemented in a shape table provider which is where you do all shape related site-wide operations.
Great! Here is my implementation for adding another template for the main List shape.
TheThemeMachine > ListShapeProvider.cs
namespace Themes.TheThemeMachine
{
using Orchard.DisplayManagement.Descriptors;
public class ListShapeProvider : IShapeTableProvider
{
public void Discover(ShapeTableBuilder builder)
{
System.Diagnostics.Debugger.Break(); // break not hit
builder.Describe("List").OnDisplaying(displaying => {
// do stuff to the shape
displaying.ShapeMetadata.Alternates.Add("Tags__List");
});
}
}
}
The above builds and runs but does not hit the breakpoint nor add an alternate for the List shape on the /tags page. So I looked into the Orchard.Azure.MediaServices module and its CloudVideoPlayerShape which implements IShapeTableProvider. Its breakpoint does get hit. How is my code for ListShapeProvider fundamentally different than the code for the CloudVideoPlayerShape?
Also, I installed the Orchard.Themes.CustomLayoutMachine.1.0.nupkg as suggested in Bertrand's blog post. It unfortunately no longer contains an implementation of IShapeTableProvider.
I have also looked at this szmyd post, which does not explain where to put the IShapeTableProvider code.
Further, I installed the Contoso theme from the Orchard Gallery. It works and builds after adding a reference to Microsoft.CSharp. It also includes an implementation of the IShapeTableProvider. Hooray! Comparing its ContentShapeProvider with my ListShapeProvider reveals a subtle but important difference:
Contoso.csproj
<ItemGroup>
<Compile Include="Code\ContentShapeProvider.cs" />
</ItemGroup>
My implementation didn't include the .cs file in the compilation, because my theme has neither a .csproj nor a App_Code folder. So, I recreated my theme with the following code generation:
orchard.exe
feature enable Orchard.CodeGeneration
codegen theme My.FirstTheme /CreateProject:true
theme enable My.FirstTheme
feature enable Orchard.DesignerTools
When adding the ListShapeProvider.cs file, Visual Studio automatically added a ItemGroup/Compile entry for the file, which included the code in compilation. Hooray!
These two posts will help.
Shape Shifting
List Customization
Here are steps of my own minimum solution.
Download and unzip Orchard.Source.1.8.zip.
Open "\Downloads\Orchard.Source.1.8\src\Orchard.sln" in Visual Studio.
Build the solution to create orchard.exe.
Generate a new theme with orchard.exe. Use CreateProject:true because you will need a csproj to include your .cs file.
orchard.exe
setup /SiteName:SITE /AdminUsername:ME /AdminPassword:PWD /DatabaseProvider:SqlCe
feature enable Orchard.CodeGeneration
codegen theme My.FirstTheme /CreateProject:true
theme enable My.FirstTheme
In VS, add a ListShapeProvier.cs file to the root (or any folder) in your theme.
Add the following code to ListShapeProvider.cs.
namespace My.FirstTheme
{
using Orchard.DisplayManagement.Descriptors;
public class ListShapeProvider : IShapeTableProvider
{
public void Discover(ShapeTableBuilder builder)
{
System.Diagnostics.Debugger.Break();
// implementation here
}
}
}
Build the solution.
Run Orchard.Web.
Visual Studio will break at System.Diagnostics.Debugger.Break(). If it doesn't, go to the Orchard Dashboard and make My.FirstTheme the Current Theme.
Now read Shape Shifting to implement public void Discover(ShapeTableBuilder builder).
This post should give you a full response: http://weblogs.asp.net/bleroy/archive/2011/05/23/orchard-list-customization-first-item-template.aspx