In my Next.js app I'm trying to insert og meta tags with dynamic content on a product page. So the content of the meta tags will change based on the product data fetched from server.
I am fetching product data using getServerSideProps and passing product data to page component as props.
export const getServerSideProps = wrapper.getServerSideProps(
store => async (context) => {
const response = await fetch(url, {
method: 'GET',
});
const data = await response.json();
return {
props: {
host: context.req.headers.host,
product: data.product
}
}
}
)
First Approach
I tried to insert meta tags directly on my product page component within <Head> component. Here meta tags even with static conetnt are not showing in page source.
const Product = ({product}) => {
return (
product ?
<>
<Head>
<title>{product.title}</title>
<meta name="description"
content={product.description}/>
<meta property="og:title" content={product.title}/>
<meta property="og:type" content="video.movie"/>
<meta property="og:url" content={`${props.host}/products/${product.slug}`}/>
<meta property="og:description" content={product.description}/>
<meta property="og:image" content={product.thumbnail}/>
</Head>
<Course/>
</> : null
);
};
Second Approach
return (
<Html lang="en">
<Head>
{/*<meta property="og:image" content="https://static.onlinevideobooks.com/abed1e5658b3ad23c38c22646968e4f2/files/media/images/2022/04/5b0645b9-ab03-4233-b5f3-86b092d4062b/conversions/cad47d2beb9143eab3d65ea4a75b0b0e-1280x720.webp" />*/}
{/*<title>your keyword rich title of the website and/or webpage</title>*/}
<meta name="description"
content="description of your website/webpage, make sure you use keywords!"/>
<meta property="og:title" content="short title of your website/webpage"/>
<meta property="og:type" content="video.movie"/>
<meta property="og:url" content="https://example.com/"/>
<meta property="og:description" content="description of your website/webpage"/>
<meta property="og:image"
content="https://example.com/image"/>
</Head>
</Html>
);
I tried inserting meta tags within <Head> in _document.js file. Here I am passing only static conetnt as I don't have dynamic data in _document.js. This time meta tags are showing up in page source and I can also preview them on facebook.
Third Approach
Then I try to insert those tag in _app.js file as I receive pageProps in this component.
Unfortunately when I pass dynamic content in meta tags like first approach, they do not show up in page source but they do when I pass static conetnt similar to second approach.
full _app.js code gist
UPDATE
As regard to my third approach, I checked once again and surprisingly I can see all meta tags in page source when inserted either with static or dynamic content in _app.js. I can preview the url when content is static but when content is dynamic I can not preview the url using either Facebook debug or Open graph
My Next.js version is 12.2.0
It's possible that the code you have in your _app.js is blocking the meta tags from being rendered. The "View page source" in browsers will not wait for client code to finish rendering. You can verify this and click "View page source" from your browser. Do you see any of the HTML you are expecting, for example do you see your meta tags and product html?
I expect that you probably don't see anything except some static HTML tags. One thing you could try is moving your use of hooks and rendering logic down into its own MainLayout component.
You can then try your first approach where you do something like this:
const Product = ({product}) => {
return (
product ?
<>
<Head>
<title>{product.title}</title>
<meta name="description"
content={product.description}/>
<meta property="og:title" content={product.title}/>
<meta property="og:type" content="video.movie"/>
<meta property="og:url" content={`${props.host}/products/${product.slug}`}/>
<meta property="og:description" content={product.description}/>
<meta property="og:image" content={product.thumbnail}/>
</Head>
<MainLayout>
<Course/>
<MainLayout>
</> : null
);
};
Where MainLayout contains all the logic you have in your _app.js. This should keep your actual _app.js free of any client side code that is blocking the meta tags from rendering.
Basically we want to utitlize Next.js static optimization and have it pre-render the meta tags for your page so that the browser and web crawlers get the data without having to wait for any client side rendering.
Hopefully this helps someone, but my issue was the placement of the <Head> tags within _app.js. For some reason, when it was nested under <Auth0ProviderWithHistory> the meta tags would not render, moving it outside of this gave me victory.
Broken
<Auth0ProviderWithHistory>
<Head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{openGraphData.map((og) => (
<meta {...og} />
))}
<title>{pageProps.title}</title>
</Head>
<CssBaseline>
<div className="page-layout">
<NavBar />
<Component {...pageProps} />
<Footer />
</div>
</CssBaseline>
</Auth0ProviderWithHistory>
Fixed
<span>
<Head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{openGraphData.map((og) => (
<meta {...og} />
))}
<title>{pageProps.title}</title>
</Head>
<Auth0ProviderWithHistory>
<CssBaseline>
<div className="page-layout">
<NavBar />
<Component {...pageProps} />
<Footer />
</div>
</CssBaseline>
</Auth0ProviderWithHistory>
</span>
Not sure what's going under the hood, but removing the Head tag resolves this for me.
I just put my meta tags without nesting them inside Head, and it worked.
I have seen posts such as
Cypress - run test in iframe for how to handle iframes in Cypress. But I am using the old and outdated frames, which is what a legacy system (that I have to test) uses.
I have checked Github -Cypress iframes which is recommended by Cypress, but haven't found an answer for plain old frames. Using the solution for iframe, hasn't worked.
The problem is the same as with an iframe where, when trying to select an element using
cy.get('input').type('test');
you receive an AssertionError stating:
Timed out retrying after 4000ms: Expected to find element: input, but never found it.
Any advice is appreciated.
I don't have any experience with <frame>, but testing on this source
index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">
<html>
<head>
<meta name="robots" content="noindex">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Example page</title>
</head>
<frameset cols="150,*">
<frame src="example_a.html">
<frame src="example_b.html">
<noframes>
<body>
<p>Alternate content</p>
</body>
</noframes>
</frameset>
</html>
example_b.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="robots" content="noindex">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Example page</title>
</head>
<body>
<input />
</body>
</html>
this test works
cy.visit('http://127.0.0.1:5500/index.html') // served from vscode
cy.get('frame')
.eq(1) // 2nd frame
.then($frame => $frame[0].contentWindow) // it's window
.its('document.body')
.within(() => { // sets cy.root() to 2nd frame body
cy.get('input')
.type('something')
.invoke('val')
.should('eq', 'something')
})
If you've got more complicated stuff to do, you can try visiting the frame's source, for example this makes the frame content the top window
cy.visit('http://127.0.0.1:5500/example_b.html')
cy.get('input')
.type('something')
.invoke('val')
.should('eq', 'something')
You can try something like this:
cy.get('#iframeSelector')
.then(($iframe) => {
const $body = $iframe.contents().find('body')
cy.wrap($body)
.find('input')
.type('test')
});
How to add title and favicon in meteor 1.3, using iron router and blaze ?
In js you can set the page title anytime with:
document.title = "Foo";
This is much more flexible than including a static title in the <head> section as you generally want the title to change on a route-by-route basis.
In i-r you can do this in an onAfterAction hook ex:
onAfterAction() {
document.title = 'mySiteName:' + Router.current().route.getName();
}
The icon can also be set dynamically, see this question
In the default layout template of iron router add the following lines in the starting of the html file.
<head>
<link rel='icon' sizes="16x16 32x32" href='/favicon.ico' >
</head>
Save the /favicon.ico in public directory in the meteor root app. Don't forget the / in /favicon.ico
For favicon, add the following code in your main.html page in the head tag
<link rel='shortcut icon' type='image/x-icon' href='favicon.ico' />
For title per page, you can add in each html template the following code
{{documentTitle 'Document Title'}}
And add the following code in a js file
//global template helper
Template.registerHelper('documentTitle', function(title){
document.title = title;
});
You can use head tag inside the client/main.html file.
This will allow you to add title and favicon icon.
<head>
<meta charset="utf-8" />
<title>MY Title</title>
<link rel='shortcut icon' href='favicon.ico' type='image/x-icon'/ >
</head>
I am trying to embed an R htmlwidget into an existing webpage -- a webpage that already has bootstrap and styling applied. For example, consider the following webpage (note where the widget should be placed):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>This is a test.</p>
<!-- htmlwidget should go here. -->
<p>A closing paragraph.</p>
</body>
</html>
I can create and save a datatable widget like so:
library(htmlwidgets)
library(datatable)
d1 <- datatable(mtcars, filter = "top")
saveWidget(d1, file = "widget_file.html")
The generated widget_file.html (even for this modest widget) contains a lot of code. Is there an easy way to embed this into an existing webpage/template?
I have been successful using <iframe src="widget_file.html"> but I'm wondering if there is a better way? Moreover, is there a way to separate pieces/dependencies (e.g. json data) from the widget_file.html so they can be placed in other folders?
Note: I created the htmlwidget tag, but I believe there should be a synonymous htmlwidgets tag.
The htmlwidget-Package offers a way to save the pieces for the widget separately as follows:
library(dygraphs)
d1 <- dygraph(nhtemp, main = "New Haven Temperatures") %>%
dyRangeSelector(dateWindow = c("1920-01-01", "1960-01-01"))
saveWidget(d1, file = "widget_file.html", selfcontained = FALSE)
Which results in the following files/dirs:
widget_file.html
widget_file_files
/dygraphs-1.1.1
..
/dygraphs-binding-0.6
..
/htmlwidgets-0.5
..
/jquery-1.11.1
..
/moment-2.8.4
..
/moment-timezone-0.2.5
..
And widget_file.html reads as follows:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="widget_file_files/htmlwidgets-0.5/htmlwidgets.js"></script>
...
<script src="widget_file_files/dygraphs-binding-0.6/dygraphs.js"></script>
</head>
<body style="background-color:white;">
<div id="htmlwidget_container">
<div id="htmlwidget-2956" style="width:960px;height:500px;" class="dygraphs"></div>
</div>
<!-- THE JSON DATA -->
<script type="application/json" data-for="htmlwidget-2956">
{THE JSON DATA YOU WERE LOOKING FOR}
</script>
<!-- THE JSON DATA -->
<script type="application/htmlwidget-sizing" data-for="htmlwidget-2956">{Widget-Styling-Json}
</script>
</body>
</html>
So you can edit your html as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- Begin of scripts to run the widget -->
<script src="widget_file_files/htmlwidgets-0.5/htmlwidgets.js"></script>
<script src="widget_file_files/jquery-1.11.1/jquery.min.js"></script>
<link href="widget_file_files/dygraphs-1.1.1/dygraph.css" rel="stylesheet" />
<script src="widget_file_files/dygraphs-1.1.1/dygraph-combined.js"></script>
<script src="widget_file_files/moment-2.8.4/moment.js"></script>
<script src="widget_file_files/moment-timezone-0.2.5/moment-timezone-with-data.js"></script>
<script src="widget_file_files/dygraphs-binding-0.6/dygraphs.js"></script>
<!-- End of scripts to run the widget -->
<!-- Begin Widget styling -->
<script type="application/htmlwidget-sizing" data-for="htmlwidget-2956">{"viewer":{"width":450,"height":350,"padding":10,"fill":true},"browser":{"width":960,"height":500,"padding":40,"fill":true}}</script>
<!-- End widget Styling -->
<!-- Begin Data for the widget-->
<script type="application/json" data-for="htmlwidget-2956">{"x":{"attrs":{"title":"New Haven Temperatures","labels":["year","V1"],"legend":"auto","retainDateWindow":false,"axes":{"x":{"pixelsPerLabel":60}},"showRangeSelector":true,"dateWindow":["1920-01-01T00:00:00Z","1960-01-01T00:00:00Z"],"rangeSelectorHeight":40,"rangeSelectorPlotFillColor":" #A7B1C4","rangeSelectorPlotStrokeColor":"#808FAB","interactionModel":"Dygraph.Interaction.defaultModel"},"scale":"yearly","annotations":[],"shadings":[],"events":[],"format":"date","data":[["1912-01-01T00:00:00Z","1913-01-01T00:00:00Z","1914-01-01T00:00:00Z","1915-01-01T00:00:00Z","1916-01-01T00:00:00Z","1917-01-01T00:00:00Z","1918-01-01T00:00:00Z","1919-01-01T00:00:00Z","1920-01-01T00:00:00Z","1921-01-01T00:00:00Z","1922-01-01T00:00:00Z","1923-01-01T00:00:00Z","1924-01-01T00:00:00Z","1925-01-01T00:00:00Z","1926-01-01T00:00:00Z","1927-01-01T00:00:00Z","1928-01-01T00:00:00Z","1929-01-01T00:00:00Z","1930-01-01T00:00:00Z","1931-01-01T00:00:00Z","1932-01-01T00:00:00Z","1933-01-01T00:00:00Z","1934-01-01T00:00:00Z","1935-01-01T00:00:00Z","1936-01-01T00:00:00Z","1937-01-01T00:00:00Z","1938-01-01T00:00:00Z","1939-01-01T00:00:00Z","1940-01-01T00:00:00Z","1941-01-01T00:00:00Z","1942-01-01T00:00:00Z","1943-01-01T00:00:00Z","1944-01-01T00:00:00Z","1945-01-01T00:00:00Z","1946-01-01T00:00:00Z","1947-01-01T00:00:00Z","1948-01-01T00:00:00Z","1949-01-01T00:00:00Z","1950-01-01T00:00:00Z","1951-01-01T00:00:00Z","1952-01-01T00:00:00Z","1953-01-01T00:00:00Z","1954-01-01T00:00:00Z","1955-01-01T00:00:00Z","1956-01-01T00:00:00Z","1957-01-01T00:00:00Z","1958-01-01T00:00:00Z","1959-01-01T00:00:00Z","1960-01-01T00:00:00Z","1961-01-01T00:00:00Z","1962-01-01T00:00:00Z","1963-01-01T00:00:00Z","1964-01-01T00:00:00Z","1965-01-01T00:00:00Z","1966-01-01T00:00:00Z","1967-01-01T00:00:00Z","1968-01-01T00:00:00Z","1969-01-01T00:00:00Z","1970-01-01T00:00:00Z","1971-01-01T00:00:00Z"],[49.9,52.3,49.4,51.1,49.4,47.9,49.8,50.9,49.3,51.9,50.8,49.6,49.3,50.6,48.4,50.7,50.9,50.6,51.5,52.8,51.8,51.1,49.8,50.2,50.4,51.6,51.8,50.9,48.8,51.7,51,50.6,51.7,51.5,52.1,51.3,51,54,51.4,52.7,53.1,54.6,52,52,50.9,52.6,50.2,52.6,51.6,51.9,50.5,50.9,51.7,51.4,51.7,50.8,51.9,51.8,51.9,53]]},"evals":["attrs.interactionModel"]}</script>
<!-- End Data for the widget-->
</head>
<body>
<p>This is a test.</p>
<div id="htmlwidget_container">
<div id="htmlwidget-2956" style="width:960px;height:500px;" class="dygraphs"></div>
</div>
<p>A closing paragraph.</p>
</body>
</html>
This will leave you with the json-data hardcoded within the html-document (see my ).
If you want to load the data dynamically you can use e.g.
json_dat <- readLines("widget_file.html")[18]
cat(sub("</script>","",sub('<script type=\"application/json\" data-for=.*\">', "", json_dat)), file = "./widget_file_files/my_data.json")
To save the json-data as ./widget_file_files/my_data.json and then load it within the html. If you are using PHP you can do:
<script type="application/json" data-for="htmlwidget-2956">
<?php include('widget_file_files/my_data.json'); ?>
</script>
If you want to use a pure JS solution maybe have a look at http://api.jquery.com/jquery.getjson/ and the widget_file_files/htmlwidgets-0.5/htmlwidgets.js-File how the json-data is bound at the moment...
P.S.:
As this question got a lot of attention already you could also contact the package developer and ask him to further "un-selfcontain" the "selfcontained" option in htmlwidgets:::saveWidget: Meaning to save the json-data separately and include it e.g. via jquery.getjson
I'm building a website using Flex, Codeigniter, and I use swfobject to embed the swf.
This will not work if I access the website using Codeigniter's index.php file.
This is the ouput source:
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<base href="http://localhost/Pixelatte-debug/"/>
<link rel="stylesheet" type="text/css" href="history/history.css" />
<title>${title}</title>
<script src="AC_OETags.js" language="javascript"></script>
<script src="history/history.js" language="javascript"></script>
<style>
body { margin: 0px; overflow:hidden; background:url('swirlsbg.png') }
</style>
</head>
<body scroll="no">
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
var flashVars = {};
var params = { play: "true",
loop: "false",
quality: "high",
wmode: "transparent",
allowscriptaccess: "sameDomain" };
var attributes = { id: "${application}" };
swfobject.embedSWF( "${swf}.swf",
"divContent",
"100%", "100%",
"9.0.0",
"expressInstall.swf",
flashVars,
params,
attributes );
</script>
<div id="divContent">
<h1>Alternative content</h1>
<p><a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
</a></p>
</div>
</body>
</html>
My guess is that swfobject.js is not detected by codeigniter..
What is the result? (The replacement text, or a broken object tag...?)
Is swfobject.js loaded properly?
Is your SWF file's path correct?
What is your final HTML output?
Maybe one of the details will solve your problem.
CodeIgniter won't be your issue here. You should use a tool like Firebug (a firefox plugin) to confirm your assets are actually being found.
Codeignitor won't know about your JS, your browser will. If the JS isn't running there is either a fault in the JS code, or it isn't found by your browser.