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/`,
},
},
],
}
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 having a Rails application with CKEditor integration.
I was no able to integrate the Wiris plugin into it
My config.js looks like this:
CKEDITOR.editorConfig = function( config ) {
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' }
];
config.removeButtons = 'Underline,Subscript,Superscript';
config.format_tags = 'p;h1;h2;h3;pre';
config.removeDialogTabs = 'image:advanced;link:advanced';
};
I have downloaded the Wiris plugin from here and copied it to app/assets/javascripts/ckeditor/plugins
I tried adding this in config.js file:
CKEDITOR.editorConfig = function( config )
{
config.extraPlugins += (config.extraPlugins.length == 0 ? '' : ',') + 'ckeditor_wiris';
config.toolbar_Full.push({ name: 'wiris',
items : [ 'ckeditor_wiris_formulaEditor', 'ckeditor_wiris_CAS' ]});
};
But nothing seems to be working.
Any help will be appreciated!
WIRIS is now available for Ruby on Rails! You can see the CKeditor demo at http://www.wiris.com/plugins/demo/ckeditor/ruby/. You will find the links to the download and documentation on the demo page.
Our Ruby on Rails plugin is also available for TinyMCE and for generic HTML editors.
I'm trying to configure a few models with breeze.js
The first is session and I was able to get this working perfectly with a simple query like the below
var query = breeze.EntityQuery.from("sessions").toType("Session");
..but when I tried to add a related "speakers" array to the session I seem to be left with an empty array after the materialization step is complete
Do I need to write a custom json adapter for an api that looks like this?
/api/sessions/
[
{
"id": 1,
"name": "javascript",
"speakers": [
1
]
}
]
/api/speakers/1/
{
"id": 1,
"name": "Toran",
"session": 1
}
Here is my current model configuration (mostly working)
var ds = new breeze.DataService({
serviceName: 'api',
hasServerMetadata: false,
useJsonp: false
});
breeze.config.initializeAdapterInstance("modelLibrary", "backingStore", true);
this.instance = new breeze.EntityManager({dataService: ds});
this.instance.metadataStore.addEntityType({
shortName: "Speaker",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
session: { dataType: "Int64" }
},
navigationProperties: {
session: {
entityTypeName: "Session", isScalar: true,
associationName: "session", foreignKeyNames: ["session"]
}
}
});
this.instance.metadataStore.addEntityType({
shortName: "Session",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
speakers: { dataType: "Undefined" }
},
navigationProperties: {
speakers: {
entityTypeName: "Speaker", isScalar: false,
associationName: "speakers", foreignKeyNames: ["speakers"]
}
}
});
Thanks for the help !
note** I'm using ember.js (not backbone/ko/angular)
I tried to keep the above brief but if you need absolutely everything, checkout this single js file
https://github.com/toranb/embereeze/blob/master/website/static/website/js/app.js
update
if I remove the "speakers" dataProperty breeze gets fairly unhappy in this block of code (as it's not a dataProperty on the session model)
var fkProps = fkNames.map(function (fkName) {
//fkName is speakers .... yet it's not a data property so bad things happen :(
return parentEntityType.getDataProperty(fkName);
});
var fkPropCollection = parentEntityType.foreignKeyProperties;
// Array.prototype.push.apply(parentEntityType.foreignKeyProperties, fkProps);
fkProps.forEach(function (dp) {
I just did a PR - the association name should be the same on both ends, much like any relational database would have.
this.instance.metadataStore.addEntityType({
shortName: "Speaker",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" },
session: { dataType: "Int64" }
},
navigationProperties: {
sessionModel: {
entityTypeName: "Session", isScalar: true,
associationName: "Speaker_Sessions", foreignKeyNames: ["session"]
}
}
});
this.instance.metadataStore.addEntityType({
shortName: "Session",
namespace: "App",
dataProperties: {
id: { dataType: "Int64", isPartOfKey: true },
name: { dataType: "String" }
},
navigationProperties: {
speakers: {
entityTypeName: "Speaker", isScalar: false,
associationName: "Speaker_Sessions"
}
}
});
So I renamed the association, removed the extra speakers property on the Session (there is no property for the relationship, simply an inverse that should be mapped) and then removed the foreign key on the session as you don't need one there. By assigning passing session down from the API with the models shown above should be enough to let Breeze know
Speakers' have a session property, which is a foreign key pointing to a single session.
Sessions have a collection of speakers, which should be mapped on the other end
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>