Related
I followed this tutorial for adding social media cards to my site: https://www.gatsbyjs.com/tutorial/seo-and-social-sharing-cards-tutorial/
However, my url https://www.peregrinastro.com/articles/jupiter-saturn-conjunction-in-aquarius-part-1-fresh-air still returns this in twitter card validator:
INFO: Page fetched successfully
INFO: 5 metatags were found
ERROR: No card found (Card error)
I can see that I have all the metatags, so what can be the issue?
SEO component :
import React from "react"
import PropTypes from "prop-types"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"
function SEO({ description, lang, meta, image: metaImage, title }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
keywords
author
url
twitter
facebook
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
const image =
metaImage && metaImage.src
? `${site.siteMetadata.url}${metaImage.src}`
: null
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={`%s | ${site.siteMetadata.title}`}
meta={[
{
name: `description`,
content: metaDescription,
},
{
name: "keywords",
content: site.siteMetadata.keywords.join(","),
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
property: `og:site_name`,
content: title,
},
{
property: `og:url`,
content: site.siteMetadata.url,
},
]
.concat(
metaImage
? [
{
property: "og:image",
content: image,
},
{
property: "og:image:width",
content: metaImage.width,
},
{
property: "og:image:height",
content: metaImage.height,
},
{
name: "twitter:card",
content: "summary_large_image",
},
{
name: "twitter:image:src",
content: image,
},
]
: [
{
name: "twitter:card",
content: "summary",
},
]
)
.concat([
{
name: `twitter:creator`,
content: site.siteMetadata.twitter,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
{
name: `twitter:site`,
content: site.siteMetadata.twitter,
},
])
.concat(meta)}
/>
)
}
SEO.defaultProps = {
lang: `en`,
meta: [],
description: ``,
}
SEO.propTypes = {
description: PropTypes.string,
lang: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
image: PropTypes.shape({
src: PropTypes.string.isRequired,
height: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
}),
}
export default SEO
gatsby-config.js
const { isNil } = require("lodash")
const mapPagesUrls = {
index: "/",
}
module.exports = {
siteMetadata: {
title: `Peregrin Astrology`,
description: `astrology blog, horoscopes, mundane, historical astrology, birth chart consultations.`,
keywords: [
"astrology",
"astrologer",
"zodiac",
"signs",
"aries",
"taurus",
"gemini",
"cancer",
"leo",
"virgo",
"libra",
"scorpio",
"sagittarius",
"capricorn",
"aquarius",
"pisces",
"horoscope",
"forecast",
"mundane",
"birth chart",
],
author: `Pedro Coelho`,
url: "https://www.peregrinastro.com",
siteLanguage: "english",
twitter: "#peregrinastro",
facebook: "peregrinastro",
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/favicon.png`, // This path is relative to the root of the site.
},
},
{
resolve: `gatsby-source-strapi`,
options: {
apiURL: `https://astrobeats-cms.herokuapp.com`,
queryLimit: 10000, // Default to 100
contentTypes: [`article`, `category`, `author`],
//If using single types place them in this array.
},
},
{
resolve: "gatsby-source-filesystem",
options: {
name: "fonts",
path: `${__dirname}/src/fonts/`,
},
},
{
resolve: "gatsby-plugin-web-font-loader",
options: {
google: {
families: ["Merriweather", "Montserrat", "Lato:100,300,400,700,900"],
},
},
},
{
resolve: "gatsby-plugin-react-svg",
options: {
rule: {
include: /assets/,
},
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images/`,
},
},
],
}
After 5-6 hours of searching for the solution, I start to give up. I have a project with docker, node & nuxt.I would like to share meta tags on FB and for this, I need SSR && vue-meta and for vue-meta I need asyncData.
it works with different api!
async asyncData({ params, $axios, error }) {
const product = await $axios.$get(`https://api.nuxtjs.dev/posts/1`);
return { product };
},
It is working when i navigate to here with nuxt routing, but if i reload the page (just here) then i get a RuntimeError from the nuxt ssr.
SO THE REAL PROBLEM IS I GET A RuntimeError ON PAGE RELOAD ON LOCALHOST
async asyncData({ params, $axios, error }) {
//axios knows the api
//http://localhost:8080/
const product = await $axios.$get(`products/${params.id}`);
return { product };
},
If I try this with Axios then I get this error:
Cannot read property 'data' of undefined
If I try this with #nuxt/http then I get this error
request to http://localhost:8080/products/some-id failed, reason: connect ECONNREFUSED 127.0.0.1:8080
I think the problem is when I push hard reload on this page, then I cannot make requests on localhost but I don't know why and how to solve it.
my nuxt-config.js
export default {
// Disable server-side rendering (https://go.nuxtjs.dev/ssr-mode)
// ssr: false,
// Global page headers (https://go.nuxtjs.dev/config-head)
head: {
title: '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Josefin+Sans:wght#300;400;600&display=swap' },
]
},
// Global CSS (https://go.nuxtjs.dev/config-css)
css: [
'#/assets/scss/styles.scss',
// '~node_modules/bootstrap/dist/css/bootstrap.css',
// '~node_modules/bootstrap-vue/dist/bootstrap-vue.css',
],
// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
plugins: [
'~/plugins/notifier',
'~/plugins/axios',
'~/plugins/dateFilter',
'~/plugins/loading',
],
// Auto import components (https://go.nuxtjs.dev/config-components)
components: true,
// Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
buildModules: [
'nuxt-lazysizes', //https://github.com/ivodolenc/nuxt-lazysizes
'#aceforth/nuxt-optimized-images', //https://github.com/juliomrqz/nuxt-optimized-images //only build
],
// Modules (https://go.nuxtjs.dev/config-modules)
modules: [
'#nuxtjs/axios',
'#nuxtjs/auth',
'#nuxtjs/style-resources',
'nuxt-i18n',
'bootstrap-vue/nuxt',
'#nuxt/http',
],
styleResources: {
scss: [
// './assets/scss/*.scss',
'#/assets/scss/_variables.scss',
'#/node_modules/bootstrap/scss/_functions.scss',
'#/node_modules/bootstrap/scss/_variables.scss',
'#/node_modules/bootstrap/scss/mixins/_breakpoints.scss',
]
},
bootstrapVue: {
bootstrapCSS: false,
bootstrapVueCSS: false,
icons: false,
},
axios: {
// baseURL: ``, //built by docker compose from API_PORT && API_HOST variables
},
auth: {
strategies: {
local: {
endpoints: {
login: { url: '/auth/login', method: 'post', propertyName: 'token' },
logout: false,
user: { url: '/auth/user', method: 'get', propertyName: 'user' },
},
}
},
redirect: {
login: '/login',
logout: '/',
callback: '/login',
home: '/admin/products',
},
},
// Build Configuration (https://go.nuxtjs.dev/config-build)
build: {
// babel: {
// compact: true,
// },
},
router: {
extendRoutes(routes, resolve) {
routes.push(
{
name: 'product-edit',
path: '/admin/products/edit/:id',
component: 'pages/admin/products/add.vue',
},
{
name: 'product-image-upload',
path: '/admin/products/product-image-upload/:id',
component: 'pages/admin/products/product-image-upload.vue',
},
{
name: 'gallery-image-upload',
path: '/admin/gallery-image-upload',
component: 'pages/admin/gallery-image-upload.vue',
},
);
}
},
env: {
baseUrl: `${process.env.BASE_URL}`,
imagePath: `${process.env.BASE_URL}:${process.env.API_PORT}/uploads`,
},
publicRuntimeConfig: {
baseUrl: `${process.env.BASE_URL}`,
imagePath: `${process.env.BASE_URL}:${process.env.API_PORT}/uploads`,
},
loading: '~/components/LoadingBar.vue',
i18n: {
locales: [
{ code: 'en', iso: 'en-US', file: 'en.js' },
{ code: 'hu', iso: 'hu-HU', file: 'hu.js' },
{ code: 'de', iso: 'de-DE', file: 'de.js' },
],
defaultLocale: 'en',
lazy: true,
langDir: '/i18n/',
parsePages: false,
vueI18n: {
fallbackLocale: 'en',
},
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
},
seo: false,
vueI18nLoader: true,
strategy: 'no_prefix',
},
lazySizes: {
extendAssetUrls: {
img: 'data-src',
source: 'data-srcset',
// Component with custom props
AppImage: ['source-md-url', 'image-url'],
},
},
optimizedImages: {
inlineImageLimit: 1000,
handleImages: ['jpeg', 'png', 'svg', 'webp', 'gif'],
optimizeImages: false,
optimizeImagesInDev: false,
defaultImageLoader: 'img-loader',
mozjpeg: {
quality: 80,
},
optipng: {
optimizationLevel: 3,
},
pngquant: false,
gifsicle: {
interlaced: true,
optimizationLevel: 3,
},
svgo: {
// enable/disable svgo plugins here
},
webp: {
preset: 'default',
quality: 75,
},
},
};
my docker-compose.yml
version: '3'
services:
server:
build:
context: ./server
env_file: .env
expose:
- $SERVER_PORT
ports:
- $SERVER_PORT:$SERVER_PORT
volumes:
- ./server:/usr/app
- /usr/app/node_modules
client:
build:
context: ./client
env_file: .env
environment:
NUXT_HOST: 0.0.0.0
NUXT_PORT: $CLIENT_PORT
API_HOST: 0.0.0.0
API_PORT: $SERVER_PORT
BASE_URL: $BASE_URL
volumes:
- ./client:/usr/app
- /usr/app/node_modules
expose:
- $CLIENT_PORT
ports:
- $CLIENT_PORT:$CLIENT_PORT
Update: if I start my nuxt project without Docker then everything works fine but this is not a solution for me :D
I have solved my question. I had to use nginx proxy as a container and some nuxt config.
// https://axios.nuxtjs.org/options/
privateRuntimeConfig: {
axios: {
baseURL: 'http://nginx/api' // name of the docker proxy
}
},
this is my configuration in apostrophe-assets. did i miss something?
// This configures the apostrophe-assets module to push a 'site.less'
// stylesheet by default, and to use jQuery 3.x
module.exports = {
jQuery: 3,
stylesheets: [
{
name: 'bootstrap.min',
minify: true
},
{
name:'font-awesome.min',
path: 'fonts/css',
minify:true
},
{
name: 'style',
minify: false
},
{
name: 'site'
}
],
scripts: [
{
name: 'jquery-3.2.1.min',
minify:true
},{
name: 'popper'
},{
name: 'bootstrap.min'
},
{
name: 'custom'
},
{
name: 'site'
}
]
};
i have referred https://apostrophecms.org/docs/tutorials/getting-started/pushing-assets.html. also i have overwrite the existing module in apostrophe.
It would be interesting to know if its necessary to add jQuery: 3
look at my code:
lib/modules/apostrophe-assets/index.js
module.exports = {
stylesheets: [
{
name: 'site'
}
],
scripts: [
{
name: 'site'
},
{
name: 'lethargy.min'
},
{
name: 'smartscroll.min'
}
]
};
my js files are located in the default path like that:
lib/modules/apostrophe-assets/public/js/lethargy.min.js
You can push assets as well from every widget here for example in index js of :
lib/modules/example-widget/index.js
//Create functions for pushing assets to browser
afterConstruct: function(self) {
self.pushAssets();
},
//load third party styles and scripts
//init has all settings for fullpage
construct: function(self, options) {
self.pushAssets = function() {
self.pushAsset('stylesheet', 'vendor/materialize.min', { when: 'always' });
self.pushAsset('stylesheet', 'overrides', { when: 'always' });
self.pushAsset('script', 'vendor/materialize', { when: 'always' });
self.pushAsset('script', 'init', { when: 'always' });
};
}
I am trying unsuccessfully to insert embed code into my 4.7.1 ckeditor. I click on SOURCE...paste the embed code...click source again...the video shows and I can even play the video. When I go to save the "post" with text and video the only thing that remains is the text. The iframe is replaced with <p> </p>. Here is my config.js file:
CKEDITOR.editorConfig = function( config ) {
// Define changes to default configuration here.
// For complete reference see:
// http://docs.ckeditor.com/#!/api/CKEDITOR.config
// The toolbar groups arrangement, optimized for two toolbar rows.
config.toolbarGroups = [
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'links' },
{ name: 'insert' },
{ name: 'forms' },
{ name: 'tools' },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'others' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'styles' },
{ name: 'colors' },
{ name: 'about' }
];
// Remove some buttons provided by the standard plugins, which are
// not needed in the Standard(s) toolbar.
config.removeButtons = 'Underline,Subscript,Superscript';
// Set the most common block elements.
config.format_tags = 'p;h1;h2;h3;pre';
// Simplify the dialog windows.
config.removeDialogTabs = 'image:advanced;link:advanced';
config.extraAllowedContent = 'p(*)[*]{*};div(*)[*]{*};li(*)[*]{*};ul(*)[*]{*};iframe(*)[*]{*}';
config.allowedContent = true;
};
I have integrated ckeditor into a MVC asp.net project. My problem is that the input is encoded back to the controller and then when redisplayed in a view the contents contain the encoded characters & html tags.
How do I show the inner html and still have the text encoded.
Any suggestions would be appreciated.
What are you using to render the textarea? If you are using an Html helper (like Html.Textarea for instance), the encoding is done automatically.
Therefore, if you are using a RTE like CKEditor or TinyMCE, you probably don't want that. So, just write out a textarea by hand in the view, or better yet write your own Textarea extension method to limit/eliminate the encoding.
any reason why you can't just use the <%=%> instead of the <%:%> tags for your RTE output?
I have integrated with CKeditor
<script type="text/javascript">
$(document).ready(function () {
CKEDITOR.replaceByClassEnabled = true;
$('textarea.editor-basic, textarea.editor-standard, textarea.editor-richtext, textarea.editor-full').each(function (i, textarea) {
var config = {};
if ($(textarea).hasClass('editor-basic')) {
config = {
language: 'en',
toolbar:
[
{ name: 'basicstyles', items: ['Source', 'RemoveFormat'] }
]
};
}
else if ($(textarea).hasClass('editor-standard')) {
config = {
language: 'en',
toolbar:
[
{ name: 'basicstyles', items: ['Source', 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat'] }
]
};
}
else if ($(textarea).hasClass('editor-richtext')) {
config = {
language: 'en',
toolbar:
[
{ name: 'basicstyles', items: ['Source', 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat'] },
'/',
{ name: 'colors', items: ['TextColor', 'BGColor', 'Maximize', 'ShowBlocks'] },
'/',
{ name: 'fonts', items: ['Link', 'Styles', 'Format', 'Font', 'FontSize'] }
]
};
}
else if ($(textarea).hasClass('editor-full')) {
config = {
language: 'en',
height: '500px',
toolbar:
[
{ name: 'document', items: ['Source', '-', 'Save', 'NewPage', 'DocProps', 'Preview', 'Print', '-', 'Templates'] },
{ name: 'clipboard', items: ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo'] },
{ name: 'editing', items: ['Find', 'Replace', '-', 'SelectAll', '-', 'SpellChecker', 'Scayt'] },
'/',
{ name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat'] },
{
name: 'paragraph', items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv',
'-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl']
},
{ name: 'links', items: ['Link', 'Unlink', 'Anchor'] },
{ name: 'insert', items: ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar'] },
{ name: 'styles', items: ['Styles', 'Format', 'Font', 'FontSize'] },
{ name: 'colors', items: ['TextColor', 'BGColor', 'Maximize', 'ShowBlocks'] }
]
};
}
else {
return;
}
CKEDITOR.replace(textarea.id, config);
});
$('textarea.editor-basic, textarea.editor-standard, textarea.editor-richtext, textarea.editor-full').each(function (i, textarea) {
if (!$(textarea).hasClass('langdefault')) {
$('#cke_' + textarea.id).hide();
}
});
$('.sort_up, .sort_down').click(function () {
var thisrow = $(this).parent().parent().parent();
if ($(this).hasClass('sort_down')) {
if (thisrow.next().find('.sort_up').length > 0) {
thisrow.next().after(thisrow);
}
}
else {
if (thisrow.prev().find('.sort_up').length > 0) {
thisrow.prev().before(thisrow);
}
}
thisrow.parent().find('tr').removeClass('alternate-row');
thisrow.parent().find('tr:odd').addClass('alternate-row');
updateOrders();
return false;
});
$('.sortable').tableDnD({
onDrop: function (table, row) {
$(table).find('tr').removeClass('alternate-row');
$(table).find('tr:odd').addClass('alternate-row');
updateOrders();
}
});
$(".form-reset").bind("click", function () {
$("input[type='text'], textarea").val("");
for (var i in CKEDITOR.instances) {
CKEDITOR.instances[i].setData("");
}
});
});
</script>
<!-- in view page -->
<textarea name="desc" id="desc" class="form-textarea2 editor-basic"><%=Html.Encode(ViewBage.desc) %></textarea>