Open PeteKoda opened 2 years ago
@PeteKoda can you explain a bit more about the workaround? I'm also facing the same issue.
Hey @brianpereradap , i tried adding the translations field to the product connection but it stopped working for me so I just created an API call that fetches the available translations for a single product. So it's a workaround but not a proper one, I will investigate this in more depth for a new project of mine, if I find a better solution I will let you know!
@PeteKoda thanks for the insight
Hi @PeteKoda, I'm trying to use this plugins to fetch all the products in one particular language. The WPgraphql does not support this query by default. Can you help me?
Hi @H-Nguyenx. You can fetch all the products of a particular language with this plugin by using the product category query and the language as the where parameter. If you want to fetch it from the root product query you need to register the language fields to it. If you describe exactly the problem you are facing I might be able to help you! I am attaching a screenshot of what I am referring in the fist comment of the issue, if it is what you need let me know!
Hi all, it's true that fetching the products via the Product Category query with a Language parameter works, however this shouldn't be the preferred way of querying by language in my opinion. As this brings a few complications:
@PeteKoda @brianpereradap @H-Nguyenx
I just inspected the code and basicly the plugin makes the "where: (language: XX)" clause available for the post types that are supported by default by the WPGraphQL plugin (via the get_allowed_post_types() function or "graphql_post_entities_allowed_post_types" filter hook). We basicly just have to hook the "product" post type in there and the "where: language = xx" clause will be available in the Products query without having to query Product Category first!
A very simple solution would be to install the "WPGraphQL Enable All Post Types" plugin! https://github.com/DalkMania/wp-graphql-cpt
This allows for querying products via the following scheme:
products(where: {
taxonomyFilter: {
filters: {
taxonomy: LANGUAGE,
terms: "EN"
}
}
})
Hi @H-Nguyenx. You can fetch all the products of a particular language with this plugin by using the product category query and the language as the where parameter. If you want to fetch it from the root product query you need to register the language fields to it. If you describe exactly the problem you are facing I might be able to help you! I am attaching a screenshot of what I am referring in the fist comment of the issue, if it is what you need let me know!
I do not know how to register the language fields to root query products. Please show me how to do it!
@PeteKoda @brianpereradap @H-Nguyenx
I just inspected the code and basicly the plugin makes the "where: (language: XX)" clause available for the post types that are supported by default by the WPGraphQL plugin (via the get_allowed_post_types() function or "graphql_post_entities_allowed_post_types" filter hook). We basicly just have to hook the "product" post type in there and the "where: language = xx" clause will be available in the Products query without having to query Product Category first!
A very simple solution would be to install the "WPGraphQL Enable All Post Types" plugin! https://github.com/DalkMania/wp-graphql-cpt
This allows for querying products via the following scheme:
products(where: { taxonomyFilter: { filters: { taxonomy: LANGUAGE, terms: "EN" } } })
Thank you! It works. I wonder if installing this plugin is going to have an impact on wordpress server.
add_post_type_fields(get_post_type_object('product'));
function add_post_type_fields(\WP_Post_Type $post_type_object) { if (!pll_is_translated_post_type($post_type_object->name)) { return; }
$type = ucfirst($post_type_object->graphql_single_name);
register_graphql_fields("RootQueryTo${type}ConnectionWhereArgs", [
'language' => [
'type' => 'LanguageCodeFilterEnum',
'description' => "Filter by ${type}s by language code (Polylang)",
],
'languages' => [
'type' => [
'list_of' => [
'non_null' => 'LanguageCodeEnum',
],
],
'description' => "Filter ${type}s by one or more languages (Polylang)",
],
]);
register_graphql_fields("Create${type}Input", [
'language' => [
'type' => 'LanguageCodeEnum',
],
]);
register_graphql_fields("Update${type}Input", [
'language' => [
'type' => 'LanguageCodeEnum',
],
]);
register_graphql_field(
$post_type_object->graphql_single_name,
'language',
[
'type' => 'Language',
'description' => __('Polylang language', 'wpnext'),
'resolve' => function (
\WPGraphQL\Model\Post $post,
$args,
$context,
$info
) {
$fields = $info->getFieldSelection();
$language = [
'name' => null,
'slug' => null,
'code' => null,
];
$post_id = $post->ID;
// The language of the preview post is not set at all so we
// must get the language using the original post id
if ($post->isPreview) {
$post_id = wp_get_post_parent_id($post->ID);
}
$slug = pll_get_post_language($post_id, 'slug');
if (!$slug) {
return null;
}
$language['code'] = $slug;
$language['slug'] = $slug;
$language['id'] = Relay::toGlobalId('Language', $slug);
if (isset($fields['name'])) {
$language['name'] = pll_get_post_language(
$post_id,
'name'
);
}
if (isset($fields['locale'])) {
$language['locale'] = pll_get_post_language(
$post_id,
'locale'
);
}
return $language;
},
]
);
}
This is what I am doing to expose the language to the product query, it is basically a copy paste from the plugin
@PeteKoda thank you. It works.
@PeteKoda I found a solution for this. So as you can see you added a type to support the post type "product" but you also need to query into products so here is an example : `<?php use GraphQLRelay\Relay; //On init to add post type product add_action('init', 'addProductLanguage');
function addProductLanguage(){ //add query args to the product query add_filter( 'graphql_map_input_fields_to_product_query', 'map_language_to_product_query_args', 10, 2 );
add_post_type_fields(get_post_type_object( 'product' ));
} //same logic as the plugin function map_language_to_product_query_args( array $query_args, array $where_args ) { $lang = ''; if ( isset($where_args['languages']) && is_array($where_args['languages']) && !empty($where_args['languages']) ) { $langs = $where_args['languages']; unset($where_args['languages']); $lang = implode(',', $langs); } elseif (isset($where_args['language'])) { $lang = $where_args['language']; unset($where_args['language']);
if ('all' === $lang) {
// No need to do anything. We show all languages by default
return $query_args;
}
if ('default' === $lang) {
$lang = pll_default_language('slug');
}
} else {
return $query_args;
}
$query_args['lang'] = $lang;
return $query_args;
} //same logic as plugin //Only change \WPGraphQL\Model\Post to \WPGraphQL\WooCommerce\Model\Product function add_post_type_fields(\WP_Post_Type $post_type_object) { if (!pll_is_translated_post_type($post_type_object->name)) { return; }
$type = ucfirst($post_type_object->graphql_single_name);
register_graphql_fields("RootQueryTo${type}ConnectionWhereArgs", [
'language' => [
'type' => 'LanguageCodeFilterEnum',
'description' => "Filter by ${type}s by language code (Polylang)",
],
'languages' => [
'type' => [
'list_of' => [
'non_null' => 'LanguageCodeEnum',
],
],
'description' => "Filter ${type}s by one or more languages (Polylang)",
],
]);
register_graphql_fields("Create${type}Input", [
'language' => [
'type' => 'LanguageCodeEnum',
],
]);
register_graphql_fields("Update${type}Input", [
'language' => [
'type' => 'LanguageCodeEnum',
],
]);
register_graphql_field(
$post_type_object->graphql_single_name,
'language',
[
'type' => 'Language',
'description' => __('Polylang language', 'wpnext'),
'resolve' => function (
\WPGraphQL\WooCommerce\Model\Product $post,
$args,
$context,
$info
) {
$fields = $info->getFieldSelection();
$language = [
'name' => null,
'slug' => null,
'code' => null,
];
$post_id = $post->ID;
// The language of the preview post is not set at all so we
// must get the language using the original post id
if ($post->isPreview) {
$post_id = wp_get_post_parent_id($post->ID);
}
$slug = pll_get_post_language($post_id, 'slug');
if (!$slug) {
return null;
}
$language['code'] = $slug;
$language['slug'] = $slug;
$language['id'] = Relay::toGlobalId('Language', $slug);
if (isset($fields['name'])) {
$language['name'] = pll_get_post_language(
$post_id,
'name'
);
}
if (isset($fields['locale'])) {
$language['locale'] = pll_get_post_language(
$post_id,
'locale'
);
}
return $language;
},
]
);
register_graphql_field(
$post_type_object->graphql_single_name,
'translation',
[
'type' => $type,
'description' => __(
'Get specific translation version of this object',
'wp-graphql-polylang'
),
'args' => [
'language' => [
'type' => [
'non_null' => 'LanguageCodeEnum',
],
],
],
'resolve' => function (
\WPGraphQL\WooCommerce\Model\Product $post,
array $args
) {
$translations = pll_get_post_translations($post->ID);
$post_id = $translations[$args['language']] ?? null;
if (!$post_id) {
return null;
}
return new \WPGraphQL\WooCommerce\Model\Product(
$post_id
);
},
]
);
register_graphql_field(
$post_type_object->graphql_single_name,
'translations',
[
'type' => [
'list_of' => $type,
],
'description' => __(
'List all translated versions of this post',
'wp-graphql-polylang'
),
'resolve' => function (\WPGraphQL\WooCommerce\Model\Product $post) {
$posts = [];
if ($post->isPreview) {
$parent = wp_get_post_parent_id($post->ID);
$translations = pll_get_post_translations($parent);
} else {
$translations = pll_get_post_translations($post->ID);
}
foreach ($translations as $lang => $post_id) {
$translation = \WP_Post::get_instance($post_id);
if (!$translation) {
continue;
}
if (is_wp_error($translation)) {
continue;
}
if ($post->ID === $translation->ID) {
continue;
}
// If fetching preview do not add the original as a translation
if ($post->isPreview && $parent === $translation->ID) {
continue;
}
$model = new \WPGraphQL\WooCommerce\Model\Product($translation->ID);
// If we do not filter out privates here wp-graphql will
// crash with 'Cannot return null for non-nullable field
// Post.id.'. This might be a wp-graphql bug.
// Interestingly only fetching the id of the translated
// post caused the crash. For example title is ok even
// without this check
if ($model->is_private()) {
continue;
}
$posts[] = $model;
}
return $posts;
},
]
);
} `
I am trying to access the translations of products and the current language but its not working. I searched for the get_allowed_post_types and I think there is a timing error so the product post type is not fetched. I don't know if this is a wp-graphql-polylang problem or a wp-graphql-woocomerce but I had to call again the add_post_type_fields in my function theme to make the language and the translation work for them.