Filter nested objects in WPGraphQL - wordpress

I'm using WPGraphQL to interact with a vanilla wordpress backend. gatsby-source-wordpress is used as a client.
What I would like to achieve with my query:
for a list of category ids, give me a list of posts that belong to each category
each list of posts should be filtered (posts not having a certain id, etc), and limited to a certain number. The filter/limit params would be the same for each category.
Now when I'm constructing my query, it seems like I can only filter the outer node (category), but not the attached post node:
// syntax from the gatsby-source-wordpress plugin
// https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-wordpress
query MyQuery {
allWpCategory(filter: {id: {in: ["dGVybTo0Mg=="]}}) {
nodes {
posts { // cannot filter here 🥲
nodes {
title
id
}
}
}
}
}
I tried adding the filter in different locations, without success. Searched for solutions, but didn't find any specific to this GraphQL implementation. Structurally, this looks like what I'm try to achieve, but it's a different platform altogether.
My questions:
is it possible to get this working (it seems like a pretty standard requirement to me)
if yes, how
if no, what's the limiting factor? (GraphQL, WPGraphQL, gatsby-source-wordpress)
🙏

I don't have your data structure and can't test. Does something like this work?
query MyQuery {
allWpCategory(
filter: {
posts: {
elemMatch: {
id: {
ne: "something"
}
}
}, {
id: {
in: ["dGVybTo0Mg=="]
}
}
})
{
nodes {
posts { // cannot filter here 🥲
nodes {
title
id
}
}
}
}
}

Related

Saleor Shopping Cart Sometimes Wrong/Older Version - Using GraphQL and Next.js

I am using Saleor shopping cart GraphQL, and actually Stepzen to merge it with a Strapi GraphQL. So all Saleor mutations and queries go through the Stepzen GraphQL.
I have followed Saleors tutorial here:
https://learn.saleor.io/checkout/displaying-cart-content/
This works 90% of the time so generally the code should be OK, but I must be missing something because occasionally when adding to the cart the contents are different. The item is not added. In fact, it's possible the cart seen is an older version but am not sure. I could add to cart 4 times and it updates to the correct products and quantities each time, then the 5th time it shows the cart from the last time or even time before.
After a few seconds, if you refresh the page, the cart displays correct.
EDIT: I have just noticed, if you refresh the page several times, the cart sometimes changes, and a refresh changes back, then a refresh it changes to something else and just keeps changing on refreshes!
When the cart works, there is a little delay adding it, but when it doesn't work the cart page loads much faster, almost instantly. It's as if when it works it waits for Saleors response for the cart items list, but when it doesn't it doesn't wait for the response. Just a hunch.
This is my query code to get cart items from Saleor. It does work, 90% of the time.
const Cart = () => {
const [token] = useCookies('["token"]')
const { data, loading, error } = useCheckoutFetchByTokenQuery({
variables: { checkoutToken: token.token },
skip: !token.token,
});
const [CheckoutremoveProduct] = useCheckoutRemoveProductMutation();
if (loading) return <div>Loading...</div>;
if (error) return <div>Error</div>;
if (!data || !data.saleorcheckout) return null;
const products = data.saleorcheckout?.lines || [];
return (
<Layout title="Cart">
.....
</Layout>
);
}
The actual saleorcheckout query:
query CheckoutFetchByToken($checkoutToken: saleorUUID!) {
saleorcheckout(token: $checkoutToken) {
id
email
lines {
id
quantity
totalPrice {
gross {
amount
currency
}
}
variant {
id
product {
id
name
slug
thumbnail {
url
alt
}
cmsContent {
SaleorID
Title
Featured_image
{
data
{
attributes
{
url
width
height
alternativeText
}
}
}
}
}
pricing {
price {
gross {
amount
currency
}
}
}
name
}
}
totalPrice {
gross {
amount
currency
}
}
}
}
Interestingly the saleorcheckoutLinesAdd mutation which adds lines to the cart returns with the correct products in the cart, after the new one is added, but on the cart page that uses saleorcheckout to fetch them returns a lower amount, until you refresh later.
The actual saleorcheckoutLinesAdd mutation:
mutation ProductAddVariantToCart($checkoutToken: saleorUUID!, $variantId: ID!) {
saleorcheckoutLinesAdd(
token: $checkoutToken
lines: [{ quantity: 1, variantId: $variantId }]
) {
checkout {
id
lines {
id
quantity
variant {
id
name
product {
name
}
}
}
}
errors {
message
}
}
}
Thanks
UPDATE:
My first post above included this below, but it may be a red herring as I have added the variant ID in the query now, and dont get this error below anymore, but the problem above still exists.
Previously when it doesn't work the following error was in console:
react_devtools_backend.js:4026 Cache data may be lost when replacing the variant field of a saleorCheckoutLine object.
To address this problem (which is not a bug in Apollo Client), either ensure all objects of type saleorProductVariant have an ID or a custom merge function, or define a custom merge function for the saleorCheckoutLine.variant field, so InMemoryCache can safely merge these objects:
existing: {"__typename":"saleorProductVariant","product":{"__ref":"saleorProduct:UHJvZHVjdDoxNjY="},"pricing":{"__typename":"saleorVariantPricingInfo","price":{"__typename":"saleorTaxedMoney","gross":{"__typename":"saleorMoney","amount":100,"currency":"USD"}}},"name":"UHJvZHVjdFZhcmlhbnQ6NDAy"}
incoming: {"__typename":"saleorProductVariant","name":"UHJvZHVjdFZhcmlhbnQ6NDAy","product":{"__typename":"saleorProduct","name":"52-00 Base Plate"}}
I have looked this up, and the solution is to set typePolicies the ApolloClient to state to merge the new and old carts. BUT I cannot get this to work, if it is the solution. Online some examples of typePolicies and merge have console.log() outputs but mine are just not firing. So I am assuming I have not set the typePolicies up correct perhaps.
This is my typePolicies code, although I have tried many variations, and the fact lines is nested may be complicating it.
const client = new ApolloClient({
uri: "https://my-stepzen-graphql-url.com/__graphql",
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
saleorcheckoutLinesAdd: {
lines: {
merge(existing, incoming, { mergeObjects }) {
console.log(existing)
console.log(incoming)
return mergeObjects(existing, incoming);
},
},
},
},
},
},
}),
})
I have tried many versions of the above typePolicies, but can never get console.log to fire, so assume I have fond the correct format.

ACF Custom Fields WP GraphQL suddenly starts returning null in Gatsby even though it used to work

I am using Wordpress as a headless CMS to manage content in my Gatsby Site. I used Advanced Custom Fields to create custom fields to easily manage the fields and contents to curate and pull into my Gatsby Application. Everything was working fine till I decided to start my Gatsby Project not long ago and started getting null errors. I went to the GraphQL page on Gatsby with this address localhost:8000/___graphql to query my data there only to see that all my fields were now returning null.
I also visited the remote wordpress page to test the GraphQL IDE but everything works fine there.
I have cleared the cache of my Gatsby Application but I am still getting the same error.
Here is an example of such Query for a custom field called homePage
query MyQuery {
wpPage {
homePage {
heroSubtitle
heroTitle
heroPlaystoreCtaText
heroImage {
localFile {
childImageSharp {
gatsbyImageData(width: 614, height: 477, quality: 100, placeholder: BLURRED)
}
}
altText
}
}
}
}
All these fields are returning null even though they were all working 7 hours ago. The most baffling thing is that the same exact query works when I decided to query through allWpPage and nodes. Why is it working here and NOT working on specific WpPage query. The first node result returns empty but the second node returns the correct data. Why did it suddenly stop working?
query MyQuery {
allWpPage {
nodes {
homePage {
heroSubtitle
heroTitle
heroPlaystoreCtaText
heroImage {
localFile {
childImageSharp {
gatsbyImageData(width: 614, height: 477, quality: 100, placeholder: BLURRED)
}
}
altText
}
}
}
}
}
Any help would be appreciated. Thank you!!!.
I finally found out the reason it wasn't working was because I added a new page which moved down the home page and caused it to always return null. I modified my query to general wpPages query and filtered by /(Home Page) which brought out the specific results for Home Page. Here is the Query I used now:
query HeroQuery {
hero: allWpPage(filter: {uri: {eq: "/"}}) {
edges {
node {
homePage {
heroSubtitle
heroTitle
heroPlaystoreCtaText
heroImage {
localFile {
childImageSharp {
gatsbyImageData(width: 614, height: 477, quality: 100, placeholder: BLURRED)
}
}
altText
}
}
}
}
}
}

GraphQl Query for Node image url without relationships with gatsby-source-drupal

I'm using drupal as a headless CMS for a Gatsby site.
Each node Type of Recipe has an associated image.
I'm trying to query for each Recipe image without having to hop through all it's relationships.
Is there a more direct graphql query for an image than through relationships with gatsby-source-drupal?
Gatsby's own gatsby-source-drupal example uses relationships to access a drupal node's images.
query($slug: String!) {
recipe: nodeRecipe(fields: { slug: { eq: $slug } }) {
title
...
relationships {
image: field_image {
localFile { // NodeType: 'File'
childImageSharp {
fluid(maxWidth: 470, maxHeight: 353) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
Context
According to a related question:
"Using Drupal nodes with Gatsby requires you to drill into the relationships between nodes and media entities, then into the relationship between the media entities and the files." #Spanners
I can't help but think there has to be a better way. The query in question yields a node type of 'File', which is a Gatsby built in. But since I need to append fields to the image's node, I'd really rather not do that to the builtin File node. It feels like there should be another node Type associated with the images.
Update:
This is what my localhost:8000/__graphql looks like
allRecipes { // Query.allRecipes: recipesConnection!
nodes { // recipesConnection.nodes: [recipes!]!
id
relationships { // recipes.relationships: recipesRelationships
image { // recipesRelationships.image: images
relationships { // images.relationships: imagesRelationships
imageFile { // imagesRelationships.imageFile: files
localFile { // files.localFile: File ...
url
} ```

Firebase orderByChild security rules

Given the firebase setup with the dinosaur example I would like to add a security rule for .read. If I add .read:true in the hierarchy like the following the query fails to provide any results.
{
"rules": {
"dinosaurs": {
"$dino": {
".read":true
}
}
}
}
If I use the following the queries work as expected.
{
"rules": {
"dinosaurs": {
".read":true
}
}
}
For my use case I need a setup more like the first example so that I can check each item for a condition before allowing a read to that item. To use the new orderByChild("property") style query however it would seems I have to allow access to the entire subtree. Is this the case?

AngularFire Loop denormalized data

I have categories and subcategories.
The structure of data is like the blog shows:
categories: {
-JF1RmYehtF3IoGN9xHG(categoryId): {
title: "Example",
subcategories: {
JF1RmYehtF3IoGN239GJ(subCategoryId): true
}
To now i retrieved the data this way(for just one category):[controller]
$scope.findOneCategory = function (categoryId) {
angularFire(Categories.find(categoryId), $scope, 'category');
}
And Categories service
find: function(categoryId) {
return FireRef.categories().child('/'+categoryId);
},
This works good!
But now i need to retrieve a list of subcategories in category and bind it to the scope and i dont know how...i have currently this:
The view:
<div ng-init="findSubCategories()">
<li class="list-group-item" ng-repeat="subCategory in subCategories">{{ subCategory.name }}</li>
The controller:
$scope.findSubCategories = function() {
angularFire(Categories.findSubCategories($routeParams.categoryId), $scope, 'subCategories');
}
And the service look like this i tried something but it's wrong and have no idea how it should looks like... if anyone could help i would be so glad!
findSubCategories: function(categoryId) {
var subCategoriesIdsList = FireRef.categories().child('/'+categoryId).child('subcategories');
subCategoriesIdsList.on("child_added", function(snap) {
FireRef.subcategories().child("/"+snap.name()).once("value", function(snap) {
// Render the comment on the link page.
console.log(snap.val());(i see the object in console but have no idea how to bind it now with the view...:(
});
});
},
dont know how to bind this with angular view
First, I'd recommend upgrading to the latest AngularFire version (currently 0.6), the API has changed quite a bit and it might be easier to accomplish what you're trying to do.
Second, you should only create one binding for each category and the subCategory IDs will automatically be included in that data since they're just the child nodes. Then you'll need to create a seperate binding just for the subcategory names, which you can then look up your ID.
Let's say your data looks like this:
categories: {
-JF1RmYehtF3IoGN9xHG: {
title: "Example",
subcategories: {
JF1RmYehtF3IoGN239GJ: true
}
}
},
subCategories: {
JF1RmYehtF3IoGN239GJ: {
name: "Example Subcategory",
}
}
You'll create two bindings, one for categories and another for subcategories:
function MyController($scope, $firebase) {
var ref = new Firebase("https://<my-firebase>.firebaseio.com/");
$scope.category = $firebase(ref.child("categories/" + categoryID));
$scope.subcategories = $firebase(ref.child("subCategories"));
}
And finally, in your view, use the ID you extract from $scope.category to get the sub category name from $scope.subcategories:
<ul ng-repeat="(id, val) in category.subcategories">
<li>{{subcategories[id].name}}</li>
</ul>

Resources