createPages in Gatsby issues ; duplications and unrendered content - wordpress

I've had a few errors trying to render single blog posts.
I tried using the page template with /post/{post_name} and I was getting this error:
warn Non-deterministic routing danger: Attempting to create page: "/blog/", but
page "/blog" already exists
This could lead to non-deterministic routing behavior
I tried again with /blog/{post_name}.
I now have both routes, which I'm not sure how to clean up; but more importantly, on those pages, nothing renders, even though there should be an h1 with it's innerhtml set to the node.title and likewise a div for the content.
I've uploaded my config and components to https://github.com/zackrosegithub/gatsby so you can have a look.
Not sure how to fix
I just want to see my content rendered on the screen.
Developer tools don't seem to help when there's no content rendered as I can't find anything to inspect to try to access it another way.
Thank you for your help

Your approach is partially correct. You are using a promise-based approach but when using then() you are already settling and partially resolving it so you don't need to use the callback of resolve(), which may be causing a duplication of the promise function so try removing it.
Additionally, you may want to use a more friendly approach using async/await functions. Something like:
exports.createPages = async ({ graphql, actions, reporter }) => {
const yourQuery= await graphql(
`
{
allWordpressPost {
edges{
node{
id
title
slug
excerpt
content
}
}
}
}
`
if (yourQuery.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`);
return;
}
const postTemplate = path.resolve("./src/templates/post.js")
_.each(yourQuery.data.allWordpressPost.edges, edge => {
createPage({
path: `/post/${edge.node.slug}/`,
component: slash(postTemplate),
context: edge.node,
})
})
})
// and so on for the rest of the queries
};
In addition, place a console.log(pageContext) in your postTemplate to get what's reaching that point and name the template as:
const Post = ({pageContext}) => {
console.log("your pageContext is", pageContext);
return <div>
<h1>
{pageContext.title}
</h1>
</div>
}
export default Post;

Related

Contentful and Next JS - Issues with content not showing

So at the moment, I have a site I'm creating with Next Js on the front-end with contentful used as my CMS.
I have quite a few pages that use the contentful function to fetch the data:
export async function getStaticProps() {
const client = createClient({
space: process.env.NEXT_CONTENTFUL_SPACE_ID,
accessToken: process.env.NEXT_CONTENTFUL_ACCESS_TOKEN,
});
const res = await client.getEntries({ content_type: "MYCONTENT" });
return {
props: {
MYCONTENT: res.items,
},
};
}
So imagine this code on about 30 pages. I then filter and map through the items that I need using this code:
{MYCONTNET
.filter((e) => e.fields.tag === "design tools")
.map((content) => {
return (
<ToolsCard
key={content.fields.title}
title={content.fields.title}
para={content.fields.tagline}
url={content.fields.url}
img={content.fields.img.fields.file.url}
/>
);
})}
It was going well until I recently came across an issue whereby not all the items get passed to the front end.
My only solution is to republish the content on contentful but when I do it seems to have an effect on the other pages. Even when I tried to console log I cant see the data being passed.
It shows me this image and here is a more detailed image
I'm not sure what the issue is, it was working fine, but when I started adding more content this issue came up.
If anyone can help, that would be great. Thanks in advance.
Answer:
So I didn't realise, I needed to increase the limit parameter. I had over 113 but the default was 100.

What is the cypress cy.contains() equivalent in webdriverio?

I have mainly worked with cypress previously for e2e automated testing, I have now started working on webdriverIO. So for a cypress command such as
cy.get("[data-testid='nav-bar']").contains("Search Box").click();
What would be the equivalent for this in webdriverIO? I have tried the following approach in a PageObject Model.
class HomePage extends Page {
get navBar() {
return browser.$("[data-testid='nav-bar']");
}
openSearchBox() {
this.navBar().click('//*[text="Search Box"]');
}
}
However, this approach does not seem to work, any help on this would be appreciated.
Leaving Page Objects asside for now, you'd type this in WebdriverIO:
const bar = $('[data-testid='nav-bar']');
expect(bar.getText()).toInclude('Search Box');
bar.click();
You can use chai for the assertion instead of Jest Matchers:
const expectChai = require('chai').expect;
// ...
expectChai(bar.getText()).to.have.string('Search Box');
// ...
The exact analog to
cy.get("[data-testid='nav-bar']").contains("Search Box").click();
can be achieved with xpath selector
$("[data-testid='nav-bar']").$("./*[descendant-or-self::*[contains(text(), 'Search Box')]]").click();
It looks a bit ugly though, consider adding a custom command that would mimic Cypress's contains:
// put this to `before` hook in your wdio.conf.js
browser.addCommand('cyContains', function(text) {
this.waitForExist()
return this.$(`./*[descendant-or-self::*[contains(text(), '${text}')]]`)
}, true)
$("[data-testid='nav-bar']").cyContains("Search Box").click();
P.S.
Check out the selector in the browser console right on this page, paste in the browser console
$x("//span[descendant-or-self::*[contains(text(), 'Search Box')]]")

How to get HTML of each paragraph of a Word document with Office JS

I have MS Word documents where the table of contents, built using title 1 to title 4, is a hierarchy of more than 100 items.
I want to use Office JS to develop an add-in to import these documents in WordPress as a set of Pages with the same hierarchy as one of the tables of contents.
Each WP page would contain the HTML of all the paragraphs contained under each title level.
Looking at the Office JS samples, I have been able to log to the console the outline levels of all paragraphs in the document, but I am stuck with getting the HTML.
I think this is probably because I misunderstand context.sync().
Here is my code:
$("#exportToCMS").click(() => tryCatch(exportToCMS));
function exportToCMS() {
return Word.run(function (context) {
// Create a proxy object for the paragraphs collection
var paragraphs = context.document.body.paragraphs;
// Queue a command to load the outline level property for all of the paragraphs
paragraphs.load("outlineLevel");
return context.sync().then(function () {
// Queue a a set of commands to get the HTML of each paragraph.
paragraphs.items.forEach((paragraph) => {
// Queue a command to get the HTML of the paragraph.
var ooxml = paragraph.getOoxml();
return context.sync().then(function () {
console.log(ooxml.value);
console.log(paragraph.outlineLevel);
});
});
});
});
}
/** Default helper for invoking an action and handling errors. */
function tryCatch(callback) {
Promise.resolve()
.then(callback)
.catch(function (error) {
console.error(error);
});
}
If I comment out the line which logs ooxml.value, the script runs fine.
When uncommented, I get an error "Unhandled promise rejection".
Broken promise chains are common when you have a context.sync inside a loop. This is also bad from a performance standpoint. Your first step to fixing your code is to get the context.sync out of the forEach loop by following the guidance in this article: Avoid using the context.sync method in loops.

Vue JS AJAX computed property

Ok, I believe I am VERY close to having my first working Vue JS application but I keep hitting little snag after little snag. I hope this is the last little snag.
I am using vue-async-computed and axios to fetch a customer object from my API.
I am then passing that property to a child component and rendering to screen like: {{customer.fName}}.
As far as I can see, the ajax call is being made and the response coming back is expected, the problem is there is nothing on the page, the customer object doesnt seem to update after the ajax call maybe.
Here is the profile page .vue file I'm working on
http://pastebin.com/DJH9pAtU
The component has a computed property called "customer" and as I said, I can see in the network tab, that request is being made and there are no errors. The response is being sent to the child component here:
<app-customerInfo :customer="customer"></app-customerInfo>
within that component I am rendering the data to the page:
{{customer.fName}}
But, the page shows no results. Is there a way to verify the value of the property "customer" in inspector? is there something obvious I am missing?
I've been using Vue for about a year and a half, and I realize the struggle that is dealing with async data loading and that good stuff. Here's how I would set up your component:
<script>
export default {
components: {
// your components were fine
},
data: () => ({ customer: {} }),
async mounted() {
const { data } = await this.axios.get(`/api/customer/get/${this.$route.params.id}`);
this.customer = data;
}
}
</script>
so what I did was initialize customer in the data function for your component, then when the component gets mounted, send an axios call to the server. When that call returns, set this.customer to the data. And like I said in my comment above, definitely check out Vue's devtools, they make tracking down variables and events super easy!
I believed your error is with naming. The vue-async-computed plugin needs a new property of the Vue object.
computed: {
customer: async function() {
this.axios.get('/api/customer/get/' + this.$route.params.id).then(function(response){
return(response.data);
});
}
}
should be:
asyncComputed: {
async customer() {
const res = await this.axios.get(`/api/customer/get/${this.$route.params.id}`);
return res.data;
}
}

How can I change the subscriptions query parameters in react-komposer (meteor) from a child component?

I'm building an app with Meteor using the react-komposer package. It is very simple: There's a top-level component (App) containing a search form and a list of results. The list gets its entries through the props, provided by the komposer container (AppContainer). It works perfectly well, until I try to implement the search, to narrow down the results displayed in the list.
This is the code I've started with (AppContainer.jsx):
import { Meteor } from 'meteor/meteor';
import { composeWithTracker } from 'react-komposer';
import React, { Component } from 'react';
import Entries from '../api/entries.js';
import App from '../ui/App.jsx';
function composer(props, onData) {
if (Meteor.subscribe('entries').ready()) {
const entries = Entries.find({}).fetch();
onData(null, {entries});
};
};
export default composeWithTracker(composer)(App);
App simply renders out the whole list of entries.
What I'd like to achieve, is to pass query parameters to Entries.find({}).fetch(); with data coming from the App component (captured via a text input e.g.).
In other words: How can I feed a parameter into the AppContainer from the App (child) component, in order to search for specific entries and ultimately re-render the corresponding results?
To further clarify, here is the code for App.jsx:
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<div>
<form>
<input type="text" placeholder="Search" />
</form>
<ul>
{this.props.entries.map((entry) => (
<li key={entry._id}>{entry.name}</li>
))}
</ul>
</div>
);
}
}
Thanks in advance!
I was going to write a comment for this to clarify on nupac's answer, but the amount of characters was too restrictive.
The sample code you're looking for is in the search tutorial link provided by nupac. Here is the composer function with the corresponding changes:
function composer(props, onData) {
if (Meteor.subscribe('entries', Session.get("searchValues")).ready()) {
const entries = Entries.find({}).fetch();
onData(null, {entries});
};
};
The solution is the session package. You may need to add it to your packages file and it should be available without having to import it. Otherwise try with import { Session } from 'meteor/session';
You just need to set the session when submitting the search form. Like this for instance:
Session.set("searchValues", {
key: value
});
The subscription will fetch the data automatically every time the specific session value changes.
Finally, you'll be able to access the values in the publish method on the server side:
Meteor.publish('entries', (query) => {
if (query) {
return Entries.find(query);
} else {
return Entries.find();
}
});
Hope this helps. If that's not the case, just let me know.
There are 2 approaches that you can take.
The Subscription way,
The Meteor.call way,
The Subscription way
It involves you setting a property that you fetch from the url. So you setup your routes to send a query property to you Component.Your component uses that property as a param to send to your publication and only subscribe to stuff that fits the search criteria. Then you put your query in your fetch statement and render the result.
The Meteor.call way
Forget subscription and do it the old way. Send your query to an endpoint, in this case a Meteor method, and render the results. I prefer this method for one reason, $text. Minimongo does not support $text so you cannot use $text to search for stuff on the client. Instead you can set up your server's mongo with text indexes and meteor method to handle the search and render the results.
See what suits your priorities. The meteor.call way requires you to do a bit more work to make a "Search result" shareable through url but you get richer search results. The subscription way is easier to implement.
Here is a link to a search tutorial for meteor and read about $text if you are interested

Resources