I am trying to render a view for seo tags in umbraco cms. However I am not sure how it can be done. Is there some source I can look up to?
Tags for SEO and social media could be combined, as they share some of the same information.
On my umbraco installation I have added the following properties to website root node, page nodes and member nodes:
On top node:
siteName - textbox
siteDescription - textarea
siteLocale - textbox (ie. nb_NO)
facebookPageUrl- textbox
facebookAppId - textbox
twitterUserName - textbox
siteLogo - media picker
On pages
pageTitle - textbox
pageSnippet - textbox with 160 chars about the page content
author - member picker
On members
facebookProfilePage - textbox
twitterUserName - textbox
memberProfileUrl - textbox
Then i use the following code to render head meta tags on all pages:
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#{
// SITE INFORMATION
string site_locale = "en_US";
if (Model.Content.AncestorOrSelf(1).HasProperty("siteLocale") && (Model.Content.GetPropertyValue<string>("siteLocale") != ""))
{ site_locale = Model.Content.GetPropertyValue<string>("siteLocale"); };
// Check if root node has defined site name, otherwise use domain name.
string domain = System.Web.HttpContext.Current.Request.Url.Scheme + "://" + System.Web.HttpContext.Current.Request.Url.Authority;
string site_name = Model.Content.AncestorOrSelf(1).HasProperty("siteName") ? Model.Content.AncestorOrSelf(1).GetPropertyValue("siteName").ToString() : HttpContext.Current.Request.Url.Host.ToString();
// Check if site description exist, and default text if not.
string site_description = Model.Content.AncestorOrSelf(1).HasProperty("siteDescription") ? Model.Content.AncestorOrSelf(1).GetPropertyValue("siteDescription").ToString() : "The website " + HttpContext.Current.Request.Url.Host.ToString();
string site_logo_url = "";
string site_logo_height = "";
string site_logo_width = "";
if (Model.Content.AncestorOrSelf(1).HasProperty("siteLogo") && (Model.Content.AncestorOrSelf(1).GetPropertyValue<int>("siteLogo") != 0))
{
var logo = Umbraco.TypedMedia(Model.Content.AncestorOrSelf(1).GetPropertyValue("siteLogo").ToString());
site_logo_url = domain + logo.Url;
site_logo_height = logo.GetPropertyValue<string>("umbracoHeight");
site_logo_width = logo.GetPropertyValue<string>("umbracoWidth");
}
string site_fb_app_id = Model.Content.AncestorOrSelf(1).GetPropertyValue("facebookAppId").ToString();
string site_fb_page_url = Model.Content.AncestorOrSelf(1).GetPropertyValue("facebookPageUrl").ToString();
string site_twitter_username = Model.Content.AncestorOrSelf(1).GetPropertyValue("twitterUserName").ToString();
// PAGE INFORMATION
// Use page title if defined, otherwise Model.Content.Name
string page_url = Model.Content.Url;
string page_title = Model.Content.HasProperty("pageTitle") ? Model.Content.GetPropertyValue("pageTitle").ToString() : Model.Content.Name.ToString();
DateTime page_created_date = Model.Content.CreateDate;
DateTime page_updated_date = Model.Content.UpdateDate;
string page_description = Model.Content.HasProperty("pageSnippet") ? Model.Content.GetPropertyValue("pageSnippet").ToString() : "";
// AUTHOR INFORMATION
// Check for information about the author of this page
bool hasAuthorInfo = false;
if (Model.Content.HasProperty("author") && (Model.Content.GetPropertyValue("author").ToString() != ""))
{
hasAuthorInfo = true;
}
string author_name = "";
string author_facebook_page = "";
string author_twitter_username = "";
string author_member_profile_url = "";
if (hasAuthorInfo)
{
var author = Members.GetById((int)Model.Content.GetPropertyValue("author"));
author_name = author.Name;
author_facebook_page = author.GetPropertyValue("facebookProfilePage").ToString();
author_twitter_username = author.GetPropertyValue("twitterUserName").ToString();
author_member_profile_url = author.GetPropertyValue("memberProfileUrl").ToString();
}
// FEATURED IMAGE
// Check if there is a featured image for this page
bool hasFeaturedImage = false;
string page_featuredimage_url = "";
if (Model.Content.HasProperty("featuredImage") && (Model.Content.GetPropertyValue<int>("featuredImage") != 0))
{
hasFeaturedImage = true;
}
if (hasFeaturedImage)
{
var image = Umbraco.TypedMedia(Model.Content.GetPropertyValue("featuredImage").ToString());
page_featuredimage_url = domain + image.GetCropUrl("1200x630"); // Preferred size by Facebook
}
}
<meta name="description" content="#page_description" />
<meta property="og:title" content="#page_title" />
<meta property="og:site_name" content="#site_name" />
<meta property="og:url" content="#page_url" />
<meta property="og:description" content="#page_description" />
<meta property="og:image" content="#page_featuredimage_url" />
<meta property="fb:app_id" content="#site_fb_app_id" />
<meta property="og:type" content="article" />
<meta property="og:locale" content="nb_NO" />
<meta property="article:author" content="#author_facebook_page" />
<meta property="article:publisher" content="#site_fb_page_url" />
<meta name="twitter:title" content="#page_title" />
<meta name="twitter:description" content="#page_description" />
<meta name="twitter:image:src" content="#page_featuredimage_url" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="#site_twitter_username" />
<meta name="twitter:creator" content="#author_twitter_username" />
<script type="application/ld+json">
{
"##context": "http://schema.org",
"##type": "NewsArticle",
"mainEntityOfPage":{
"##type":"WebPage",
"##id":"#page_url"
},
"headline": "#page_title",
"image": {
"##type": "ImageObject",
"url": "#page_featuredimage_url",
"height": 630,
"width": 1200
},
"datePublished": "#page_created_date.ToString("o")",
"dateModified": "#page_updated_date.ToString("o")",
"author": {
"##type": "Person",
"name": "#author_name"
},
"publisher": {
"##type": "Organization",
"name": "#site_name",
"logo": {
"##type": "ImageObject",
"url": "#site_logo_url",
"width": "#site_logo_width",
"height": "#site_logo_height"
}
},
"description": "#page_description"
}
</script>
Related
Good morning everyone. I tried creating a site that could get information from another page and feed the response into a div tag, but it didnt work. I checked with a very similar one i learnt from. Here is the HTML code.
<html>
<head>
<script>
function checkit(){
var samxml; var username;
if (window.XMLHttpRequest){
samxml = new XMLHttpRequest();}
else {
samxml = new ActiveXObject("Microsoft.XMLHTTP");
}
samxml.onreadystatechange = function() {
if (samxml.readyState == 4 && samxml.status == 200){
document.getElementById("check").innerHTML = samxml.responseText;}
}
username = document.getElementById("username").value;
samxml.open("POST", "check.php",true);
samxml.send( "username" );
}
}
</script>
</head>
<body>
<form>
<label for ="username">User ID:</label>
<input type = "text" name = "username" id = "username"/>
<div id = "check"></div>
<button type = "button" onclick = "checkit()">Check</button>
</form>
</body>
</html>
Here is the PHP page:
//php file
<?php
$user = $_POST["username"];
if ($user == "samuel") {
echo "Hmm. Chosen! Choose another one";}
else {
echo "Nice one";}
?>
Thanks so much.
Could you please give me an example how to query the information?
We have the example to query defect in the way as below,
var queryConf = { type: 'defect',
key : 'defects',
fetch: true
};
Per Web Services API documentation Artifact object has Changesets collection on it. Defects inherit from Artifacts. Here is an example that builds a table of defects by priority with associated Changesets data:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- Copyright (c) 2010 Rally Software Development Corp. All rights reserved -->
<html>
<head>
<title>Defects By Priority with associated Changesets Example</title>
<meta name="Name" content="App Example: Defects by Priority and associated Changesets" />
<meta name="Version" content="2010.4" />
<meta name="Vendor" content="Nick M Rally lab" />
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.33/sdk.js?apiVersion=1.43"></script>
<script type="text/javascript">
var table;
var rallyDataSource = null;
function showTable(results) {
if(table) {
table.destroy();
}
for (var i=0; i < results.defects.length; i++) {
if(results.defects[i].Changesets.length > 0){
results.defects[i].ChangesetsMessages = "";
console.log(results.defects[i].Changesets.length);
for (var j=0; j < results.defects[i].Changesets.length; j++) {
results.defects[i].ChangesetsMessages += results.defects[i].Changesets[j].Revision;
results.defects[i].ChangesetsMessages += ' ';
results.defects[i].ChangesetsMessages += results.defects[i].Changesets[j].Message;
results.defects[i].ChangesetsMessages += '<br />';
}
}
}
var config = {
columnKeys : ['FormattedID', 'Name', 'Priority','ChangesetsMessages'],
columnHeaders : ['Formatted ID', 'Name', 'Priority','Changesets - Revision, Message'],
columnWidths : ['150px','150px', '150px', '300px'],
};
table = new rally.sdk.ui.Table(config);
table.addRows(results.defects);
table.display("defects");
}
function onSelectionChanged(sender, eventArgs) {
var queryObject = {
key : 'defects',
type : 'defect',
query: '(Priority = "' + eventArgs.value + '")',
fetch: 'Name,FormattedID,Priority,Changesets,Changeset,ObjectID,Message,Revision'
};
rallyDataSource.findAll(queryObject, showTable);
}
function onLoad() {
rallyDataSource = new rally.sdk.data.RallyDataSource('1111','2222','false','false');
var dpConfig = {
type : "defect",
attribute: "priority",
defaultDisplayedValue: "Low",
label: "Defect Priority:",
showLabel: true
};
var dpDropdown = new rally.sdk.ui.AttributeDropdown(dpConfig, rallyDataSource);
dpDropdown.display("priorityDiv", onSelectionChanged);
}
rally.addOnLoad(onLoad);
</script>
</head>
<body>
<div id="priorityDiv"></div><div id="defects"></div>
</body>
</html>
My default action code:
public ViewResult Act(int? id)
{
if (id == null)
ViewData["p"] = GetDefaultView();
else
ViewData["p"] = GetEditView((int)id);
return View("Index");
}
My Index view code:
<!DOCTYPE html><html><head></head><body>
<div id="content">#Html.Raw(ViewData["p"])</div></body></html>
How it is possible to use instead of ViewData a string ? How I can update #content only by means of $.ajax?
Before being able to use the $.ajax function you will first need to render a view which includes the jquery.js script:
<!DOCTYPE html>
#{ Layout = null; }
<html>
<head>
</head>
<body>
<div id="content"></div>
<!-- TODO: Adjust your proper jquery version here: -->
<script type="text/javascript" src="~/scripts/jquery.js"></script>
<script type="text/javascript">
$.ajax({
url: '#Url.Action("act")',
data: { id: 123 },
success: function(result) {
$('#content').html(result);
}
});
</script>
</body>
</html>
then you should adapt your Act controller action so that it returns some partial view or a Content result:
public ActionResult Act(int? id)
{
if (id == null)
{
return Content("<div>id was null</div>");
}
return Content("<div>id value is " + id.Value.ToString() + "</div>");
}
If you want to return a string, you could change your controller to return a ContentResult.
public ContentResult Act(int? id)
{
string html = "";
if (id == null)
html = GetDefaultView();
else
html = GetEditView((int)id);
var content = new ContentResult();
content.Content = html;
return content;
}
I'm displaying a Bing Map (v7) in my Webmatrix2 website with a series of pushpins & infoboxes drawn from a SQL Express database using a JSON enquiry.
While the maps appears in all 3 browsers I'm testing (IE, FF & Chrome) the pushpins are sometimes not showing in FF & Chrome, particularly if I refresh with Cntrl+F5
This is my first JSON and Bing Maps app so expect there's a few mistakes.
Any suggestions on how to improve the code and get display consistency?
#{
Layout = "~/_MapLayout.cshtml";
}
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<link rel="StyleSheet" href="infoboxStyles.css" type="text/css">
<script type="text/javascript">
var map = null;
var pinLayer, pinInfobox;
var mouseover;
var pushpinFrameHTML = '<div class="infobox"><a class="infobox_close" href="javascript:closeInfobox()"><img src="/Images/close2.jpg" /></a><div class="infobox_content">{content}</div></div><div class="infobox_pointer"><img src="images/pointer_shadow.png"></div>';
var pinLayer = new Microsoft.Maps.EntityCollection();
var infoboxLayer = new Microsoft.Maps.EntityCollection();
function getMap() {
map = new Microsoft.Maps.Map(document.getElementById('map'), {
credentials: "my-key",
zoom: 4,
center: new Microsoft.Maps.Location(-25, 135),
mapTypeId: Microsoft.Maps.MapTypeId.road
});
pinInfobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
AddData();
}
$(function AddData() {
$.getJSON('/ListSchools', function (data) {
var schools = data;
$.each(schools, function (index, school) {
for (var i = 0; i < schools.length; i++) {
var pinLocation = new Microsoft.Maps.Location(school.SchoolLat, school.SchoolLon);
var NewPin = new Microsoft.Maps.Pushpin(pinLocation);
NewPin.title = school.SchoolName;
NewPin.description = "-- Learn More --";
pinLayer.push(NewPin); //add pushpin to pinLayer
Microsoft.Maps.Events.addHandler(NewPin, 'mouseover', displayInfobox);
}
});
infoboxLayer.push(pinInfobox);
map.entities.push(pinLayer);
map.entities.push(infoboxLayer);
});
})
function displayInfobox(e) {
if (e.targetType == "pushpin") {
var pin = e.target;
var html = "<span class='infobox_title'>" + pin.title + "</span><br/>" + pin.description;
pinInfobox.setOptions({
visible: true,
offset: new Microsoft.Maps.Point(-33, 20),
htmlContent: pushpinFrameHTML.replace('{content}', html)
});
//set location of infobox
pinInfobox.setLocation(pin.getLocation());
}
}
function closeInfobox() {
pinInfobox.setOptions({ visible: false });
}
function getCurrentLocation() {
var geoLocationProvider = new Microsoft.Maps.GeoLocationProvider(map);
geoLocationProvider.getCurrentPosition();
}
</script>
<body onload="getMap();">
<div id="map" style="position:relative; width:800px; height:600px;"></div>
<div>
<input type="button" value="Find Nearest Schools" onclick="getCurrentLocation();" />
</div>
</body>
The JSON file is simply
#{
var db = Database.Open("StarterSite");
var sql = #"SELECT * FROM Schools WHERE SchoolLon != ' ' AND SchoolLon != 'null' ";
var data = db.Query(sql);
Json.Write(data, Response.Output);
}
Add your pinLayer, infobox, and infoboxLayer before calling the AddData function and see if that makes a difference. Also verify that school.SchoolLat and school.SchoolLon are numbers and not a string version of a number. If they are a string, then use parseFloat to turn them into a number. Other than that everything looks fine.
I used the jQuery autocompletion for my Struts2 application.
Pratically, my action made a list of strings that jQuery use. This is the script:
$().ready(function() {
$("#tag").autocomplete("/myAction/Action", {
multiple : true,
autoFill : true,
minChars:1
});
});
During typing appear the box with the suggestions. The problem is that the box render another value,
exactly render the code of my JSP ( links to CSS for the autocomplete plug-in).
How can I solve this?
This is my JSP:
<html>
<head>
<script src="<%=request.getContextPath()%>/scripts/jquery-latest.js"></script>
<link rel="stylesheet" href="<%=request.getContextPath()%>/scripts/main.css" type="text/css" />
<link rel="stylesheet" href="<%=request.getContextPath()%>/scripts/jquery.autocomplete.css" type="text/css" />
<script type="text/javascript" src="<%=request.getContextPath()%>scripts/jquery.bgiframe.min.js"></script>
<script type="text/javascript" src="/<%=request.getContextPath()%>/query.dimensions.js"></script>
<script type="text/javascript" src="<%=request.getContextPath()%>/scripts/jquery.autocomplete.js"></script>
<script type="text/javascript">
$().ready(function() {
$("#tag").autocomplete("/myAction/Action", {
multiple : true,
autoFill : true,
minChars:1
});
});
</script>
</head>
<body>
<s:form action="Action" theme="simple">
<s:iterator value="elencoMateriali" var="asd">
<s:property value="#asd" escape="false"/>
</s:iterator>
<s:textfield id="tag" name="tagField" label="tag" />
</s:form>
</body>
I think it's too late for an answer, but the probles is still remaining in Struts2. I have made some modifications to solve such problem:
Copy the jquery.struts2.js file into you js path.
Edit the jquery.struts2.js fil and look for 'success: function(data)' in the handle of the Autocompleter Widget, and replace the function for the next one:
success: function(data) {
var x = 0;
if (data[o.list] !== null) {
var isMap = false;
if (!$.isArray(data[o.list])) {
isMap = true;
}
var result = [];
$.each(data[o.list], function(j, val) {
if (isMap) {
result.push({
label: val.replace(
new RegExp(
"(?![^&;]+;)(?!<[^<>]*)(" +
$.ui.autocomplete.escapeRegex(request.term) +
")(?![^<>]*>)(?![^&;]+;)", "gi"
), "<strong>$1</strong>" ),
value: val,
id: j
});
}
else {
if (o.listkey !== undefined && o.listvalue !== undefined) {
result.push({
label: val[o.listvalue].replace(
new RegExp(
"(?![^&;]+;)(?!<[^<>]*)(" +
$.ui.autocomplete.escapeRegex(request.term) +
")(?![^<>]*>)(?![^&;]+;)", "gi"
), "<strong>$1</strong>" ),
value: val[o.listvalue],
id: val[o.listkey]
});
}
else {
result.push({
label: data[o.list][x].replace(
new RegExp(
"(?![^&;]+;)(?!<[^<>]*)(" +
$.ui.autocomplete.escapeRegex(request.term) +
")(?![^<>]*>)(?![^&;]+;)", "gi"
), "<strong>$1</strong>" ),
value: data[o.list][x],
id: data[o.list][x]
});
}
}
x++;
});
response(result);
}
}
Now, if you subscribe a onSelectTopics method on your jsp code, you will have a new item.id element available, so you can set the id value into a hidden o whatever you want.
Now, your autocompleter show a list with the strong word, fills the input with the selection, and mantains the id in a variable you can catch.
Remember to add the modified js in the include header section.
<%# taglib prefix="s" uri="/struts-tags" %>
<%# taglib prefix="sx" uri="/struts-dojo-tags" %>
<s:form action="ActionJson" theme="simple">
<s:url id="elencoFuffa" action="ActionJSON"/>
<sx:autocompleter id="autocompleter" name="materiale" loadOnTextChange="true" preload="false" href="%{elencoFuffa}" size="24" loadMinimumCount="1" showDownArrow="false" cssClass="dropDown" onchange="submit();"/>
<s:submit value="Prosegui"/>
<s:property value="luoghiSmaltimento"/>
</s:form>
Now, the Action:
public class Action extends ActionSupport {
private String materiale;
private String luoghi;
private List<String> elencoMateriali;
private Map<String, String> json;
public String execute() throws Exception {
System.out.println("------------------" + materiale);
return SUCCESS;
}
public String getMateriali() throws Exception {
MaterialiDAO dao = new MaterialiDAO();
List<Materiali> toResult = new ArrayList<Materiali>();
toResult = dao.findAll();
elencoMateriali = new ArrayList<String>();
Iterator i = toResult.iterator();
while (i.hasNext()) {
Materiali m = (Materiali) i.next();
elencoMateriali.add(m.getValueNomemateriale());
}
return SUCCESS;
}
public String getJson() throws Exception {
json = new HashMap<String, String>();
if (materiale != null && materiale.length() > 0) {
MaterialiDAO dao = new MaterialiDAO();
List<Materiali> materiali = dao.findByLikeValue(materiale);
for (Materiali m : materiali) {
json.put(m.getValueNomemateriale(), "" + m.getIdMateriali());
}
}
return SUCCESS;
}
public String trovaLuogo() throws Exception {
LuoghismalDAO daoL = new LuoghismalDAO();
MaterialiDAO daoM = new MaterialiDAO();
Materiali m = daoM.findByMaterialiName(materiale);
if (m != null) {
luoghi = m.getLuoghismal().getValueDescrluogo();
return SUCCESS;
} else {
luoghi = "-- Scegliere un materiale --";
return SUCCESS;
}
}
/* Getters and setters */
At the end the struts.xml
<action name="ActionJSON" class="it.action.Action"
method="getJson">
<result type="json">
<param name="root">json</param>
</result>
</action>