Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add_post_type_fields for language is not working for woocomerce products #70

Open
PeteKoda opened this issue Feb 1, 2022 · 12 comments
Open

Comments

@PeteKoda
Copy link

PeteKoda commented Feb 1, 2022

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.

@brianpereradap
Copy link

@PeteKoda can you explain a bit more about the workaround? I'm also facing the same issue.

@PeteKoda
Copy link
Author

PeteKoda commented Jun 1, 2022

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!

@brianpereradap
Copy link

@PeteKoda thanks for the insight

@H-Nguyenx
Copy link

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?

@PeteKoda
Copy link
Author

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!
image

@hofewo
Copy link

hofewo commented Oct 31, 2022

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:

  • The output now returns the products classified per product category
  • This makes server side (via GraphQL) filtering/sorting of products not work as intended anymore, as the products are now filtered and sorted per product category. When the products of these seperated product categories are concat together, they will not be sorted correctly (as they're only sorted per product category). This makes sorting via GraphQL not viable anymore and requires client side sorting on top of it.
  • In my particular environment most parameters for the Query > Product Category > Products > where { ... } clause do not work at all anymore. Where as in the regular Query > Products > where { ... } clause they work fine. I'm not sure if this is a specific problem in my environment. The parameters that don't work anymore are First:, After: etc.

@hofewo
Copy link

hofewo commented Oct 31, 2022

@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"
        }
    }
})

@H-Nguyenx
Copy link

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! image

I do not know how to register the language fields to root query products. Please show me how to do it!

@H-Nguyenx
Copy link

@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.

@PeteKoda
Copy link
Author

PeteKoda commented Nov 3, 2022

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

@H-Nguyenx
Copy link

@PeteKoda thank you. It works.

@reqica7
Copy link

reqica7 commented Mar 22, 2023

@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;
		},
	]
);

}
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants