TYPO3 - Overriding & adding meta tags (from tx_metaseo) on detail view of custom extension - seo

I have a custom extension and on the detail page of the records I want to seo pimp the profile sites. I'm also using tx_metaseo.
I'm already changing the 'title' tag via the show action like this:
/**
* action show
*
* #param Application $record
* #return void
*/
public function showAction(Application $record=null) {
// For the search
$GLOBALS['TSFE']->indexedDocTitle = $record->getName();
}
}
But since I have tx_metaseo installed ... I'm also getting the generall meta tags. So on the detail page of my extension I would like to override them:
<meta name="DCTERMS.title" content="">
<meta name="description" content="">
<meta name="DCTERMS.description" content="">
<meta name="keywords" content="">
<meta name="DCTERMS.subject" content="">
<meta property="og:title" content="">
<meta property="og:type" content="">
<meta property="og:email" content="">
... in addtion I want to add/set:
<meta property="og:description" content="">
... and I want to have a lange consideration (Default/German/English) ... so I would like to add (for German):
<meta http-equiv="Content-Language" content="de" />
<meta name="Language" CONTENT="Deutsch"/>
How can I do this?
I assume I need to work with Hooks/Signals? https://docs.typo3.org/typo3cms/extensions/metaseo/DeveloperManual/Index.html#signals But how?
Here is a similar discussion: https://github.com/webdevops/TYPO3-metaseo/issues/477
Edit: I tried this to prevent the meta tags created by tx_metaseo
#[globalVar = TSFE:id = 71, GP:tx_metaseo|var = 0]
[globalVar = TSFE:id = 71, GP:tx_metaseo]
#page.metaseo.meta.og:title >
#page.metaseo.meta.og:description >
page.meta.og:title =
page.meta.og:description =
[global]
... or:
[globalVar = TSFE:id = 71]
plugins.tx_metaseo >
[global]

as you can not override an existing meta value you need to prevent creating of the default meta tags.
One usual way would be a typoscript condition.
You can identify the pages where you show the detail view of your records usually by a URL parameter which gets the uid of the record to be shown.
Regarding news records you could do it like this in a site extension template:
[globalVar = GP:tx_news_pi1|news > 0]
// set news-specific meta tags
[else]
// set default meta tags (based just on the pages record)
[global]
or another way:
// somewhere (site_extension or other specific template):
// set default meta tags (based just on the pages record)
// in the static template of your extension:
[globalVar = GP:tx_news_pi1|news > 0]
// clear default meta tags (if that is possible)
page.meta.og:title >
page.meta.og:site_name >
page.meta.og:description >
page.meta.og:image >
// or deactivate the extension for generating the default meta tags
// maybe something like
plugins.tx_metatagsgenarator >
// finaly: set news-specific meta tags
:
[global]
The first example can be enhanced for multiple records just by adding more conditions (assuming the detail views of these records are on differnt pages):
[globalVar = GP:tx_news_pi1|news > 0]
// set news-specific meta tags
[globalVar = GP:tx_myext|myrec_uid > 0]
// set myext-specific meta tags
[else]
// set default meta tags (based just on the pages record)
[global]
Using extensions which generate the meta tags whithout option to control it by typoscript would make the whole process very complicated.
Outlook: Handling meta tags will be easier with TYPO3 9.
The easiest manipulation for ext:metaseo looks like the stdWraps mentioned in the manual.
Or use the hooks to manipulate the whole array of all the values the extension is generating.
in the extension manual there are no real hints how to enhance the features of the extension for additional records. as you need to do more than just ethe meta-tags for the detail views: you need to enhace the generated sitemap. Maybe the extension author(s) need some impulse to enhance the manual with the informations how to add meta information for own records.

Related

Context Dictionary isn't being passed with render in view

Alright, I've been poking around the internet for a solution to that there's something obvious that I'm missing but so far no good.
I'm currently having trouble with passing a context dictionary to a template in Django via my view. So far everything else seems to return, except for the dictionary that I'm passing to the template.
def search_subjects(request):
"""
This is our search view, at present it collects queries relating to:
- Subject ID
- Study Name
- Date Range Start
- Date Range Start
Then validates these entries, after which it redirects to the search
results view.
:param request:
:return: Redirect to search results if search button is pressed and form fields
are valid or renders this view again if this request is not POST
"""
if request.method == 'POST':
form = SearchForm(request.POST)
if form.is_valid():
search_dict = {}
search = form.save(commit=False)
search.subject_search = request.POST['subject_search']
search.study_search = request.POST['subject_search']
if request.POST['date_range_alpha'] and \
dateparse.parse_datetime(request.POST['date_range_alpha']):
search.date_range_alpha = request.POST['date_ranch_alpha']
else:
search.date_range_alpha = EPOCH_TIME
if request.POST['date_range_omega'] and \
dateparse.parse_datetime(request.POST['date_range_omega']):
with_tz = dateparse.parse_datetime(request.POST['date_range_omega'])
search.date_range_omega = with_tz
else:
search.date_range_omega = timezone.now()
search.save()
for k, v in form.data.items():
search_dict[k] = v
print(search_dict)
return render(request, 'dicoms/search_results.html', search_dict)
else:
form = SearchForm()
return render(request, 'dicoms/search.html', {'form': form})
And my template here:
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Search Results</title>
</head>
<body>
Here's what you searched for:
<div>{{ search_dict }}</div>
</body>
</html>
The page that I'm getting back:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Search Results</title>
</head>
<body>
Here's what you searched for:
<div></div>
</body>
</html>
What on earth am I missing here?
Ok, so I walked away from this for a bit and managed to solve it. I wasn't passing a context dictionary correctly. Fix can be seen below.:
search.save()
context = {'search': search}
return render(request, 'dicoms/search_results.html', context)
Adjusting the template accordingly:
Here's what you searched for:
<div>{{ search.subject_search }}</div>
<div>{{ search.study_search }}</div>
<div>{{ search.date_range_alpha }}</div>
<div>{{ search.date_range_omega }}</div>
Results in:
Here's what you searched for:
<div>herp </div>
<div>herp </div>
<div>Jan. 1, 1970, midnight</div>
<div>Feb. 26, 2019, 11:05 p.m.</div>
Had I trusted in django and simply passed the whole search object in the beginning I wouldn't have ended up here. But you live and learn.

Orchard: Displaying only a single content item

I want to be able to display a content item of a certain type and only that content item i.e. no shapes that are not part of said item.
I have tried creating a controller method with a {Themed(false)] attribute, or returning a partial view. Both of these do almost exactly what I want, except that these don't include any scripts or styles associated with the View I'm trying to display.
My current attempt look like this:
Controller method:
[Themed(false)]
public ActionResult DisplayBare(int id) {
var contentItem = _contentManager.Get(id, VersionOptions.Published);
dynamic model = _contentManager.BuildDisplay(contentItem);
return View( (object)model);
}
The DisplayBare view:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
#Display(Model)
</body>
</html>
The problem is that when the display View of an item includes Script.Require, Script.Include and Script.Foot directives, the scripts do not show up in the Html.
How would I achieve this?
Found a solution by snooping around Orchard sources:
Using this view to display my content item gives me exactly what i want:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
#{
Style.Include("Site.css");
var content = Display(Model);
}
#Display.Metas()
#Display.HeadScripts()
#Display.HeadLinks()
#Display.StyleSheetLinks()
</head>
<body>
#content
#Display.FootScripts()
</body>
</html>

How to add id using dojo.query to search element

I'm trying to add id to a element using dojo.query. I'm not sure if it's possible though. I trying to use the code below to add the id but it's not working.
dojo.query('div[style=""]').attr("id","main-body");
<div style="">
content
</div>
If this is not possible, is there another way to do it? Using javascript or jquery? Thanks.
Your way of adding an id to an element is correct.
The code runs fine for me in Firefox 17 and Chrome 23 but I have an issue in IE9. I suspect you may have the same issue.
In IE9 the query div[style=""] returns no results. The funny thing is,it works fine in compatibility mode!
t seems that in IE9 in normal mode if an HTML element has an inline empty style attribute, that attribute is not being preserved when the element is added to the DOM.
So a solution would be to use a different query to find the divs you want.
You could try to find the divs with an empty style attributes OR with no style attribute at all.
A query like this should work:
div[style=""], div:not([style])
Take a look at the following example:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test Page</title>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.8.2/dojo/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojo.NodeList-manipulate");//just for the innerHTML() function
dojo.addOnLoad(function () {
var nodeListByAttr = dojo.query('div[style=""], div:not([style])');
alert('Search by attribute nodeList length:' + nodeListByAttr.length);
nodeListByAttr.attr("id", "main-body");
var nodeListByID = dojo.query('#main-body');
alert('Search by id nodeList length:' + nodeListByID.length);
nodeListByID.innerHTML('Content set after finding the element by ID');
});
</script>
</head>
<body>
<div style="">
</div>
</body>
</html>
Hope this helps
#Nikanos' answer covers the query issue, I would like to add, that any query returns an array of elements, in case of Dojo it is dojo/NodeList.
The problem is you are about to assign the same id to multiple DOM nodes, especially with query containing div:not([style]). I recommend to use more specific query like first div child of body:
var nodes = dojo.query('body > div:first-child');
nodes.attr("id", "main-body");
To make it more robust, do not manipulate all the nodes, just the first node (even through there should be just one):
dojo.query('body > div:first-child')[0].id = "main-body";
This work also in IE9, see it in action: http://jsfiddle.net/phusick/JN4cz/
The same example written in Modern Dojo: http://jsfiddle.net/phusick/BReda/

How to do standard layouts with StringTemplate?

With StringTemplate, what is the proper way to have a standard layout template such as:
<head>
..
</head>
<html>
$body()$
</html>
Where I can set the body template from my application, so that every template I use uses this fundamental layout?
Thanks.
I found it hiding in the documentation:
http://www.antlr.org/wiki/display/ST/StringTemplate+2.2+Documentation
"Include template whose name is
computed via expr. The argument-list
is a list of attribute assignments
where each assignment is of the form
attribute=expr. Example
$(whichFormat)()$ looks up
whichFormat's value and uses that as
template name. Can also apply an
indirect template to an attribute."
So my main layout template now looks like this:
<head>
<title>Sportello</title>
</head>
<html lang="en-US">
<body>
$partials/header()$
<section>$(body_template)()$</section>
$partials/footer()$
</body>
</html>
...to which I pass the subtemplate's name as an attribute.

Is this proper in .NET?

I am beginner in .NET. One of my firsts task is to change the meta tags dynamically for dynamically generated pages.
So, I came up with this, but am not too sure on what is considered the "proper" way to do it in .NET.
<head>
<title><%= title %></title>
<meta name="description" content="<%= MetaDescription %>" />
...
</head>
This function lives in my masterpage codebehind and I set a default title, etc on page init (not shown below)
Protected Title As String = ""
Public Sub ChangeTitle(ByVal title As String)
Title = title
End Sub
I also called this function in any product detail pages to set the appropriate dynamic title.
Is that considered ok in NET? Is this not good or hackish or would you say "if it works, works?
I tried adding runat="server" to the head tag, to use Page.title but then once that got added in, this line <meta name="description" content="<%= MetaDescription %>" /> gets decoded to
<meta name="description" content="<%= MetaDescription %>" />
and my code above then doesn't work to change the meta description.
If the header is marked Runat="Server" then the Page.Title property of the page will do the change in title automatically for you.
The second one for the meta tag I do the same thing, because it works.
There is already a property for this: Page.Title
After adding runat="server" to the head tag so that you can use the Title property, you can use something like this to add meta tags to the head:
public static void AddMeta(string name, string content) {
Page page = (Page)HttpContext.Current.Handler;
HtmlMeta meta = new HtmlMeta();
meta.Name = name;
meta.Content = content;
page.Header.Controls.Add(meta);
}
you can use this example:
page.title = "your title here"
page.metadescription = "your description here"