From 681d36d037d2a436f8a744de3f5d589a05c42564 Mon Sep 17 00:00:00 2001 From: Sergei Date: Tue, 12 Apr 2022 23:29:57 +0200 Subject: [PATCH] upload 2.0.0 version --- Model/Category/CategoryModifier.php | 153 +++++++++++ .../CategoryTemplateRendererAdapter.php | 50 ++++ .../Category/Products/CategoryDataFiller.php | 155 +++++++++++ Model/LayeredFiltersProvider/GraphQl.php | 134 ++++++++++ Model/Product/ProductModifier.php | 100 +++++++ .../ProductTemplateRendererAdapter.php | 65 +++++ Model/RequestedFilterArgsStorage.php | 40 +++ .../AddSeoNameToCategoryCollectionPlugin.php | 53 ---- .../AddSeoNameToProductCollectionPlugin.php | 54 ---- Plugin/ModifyCategoryDescriptionPlugin.php | 114 -------- Plugin/ModifyCategoryNamePlugin.php | 96 ------- Plugin/ModifyCategoryParamsPlugin.php | 127 --------- Plugin/ModifyProductDescriptionsPlugin.php | 129 --------- Plugin/ModifyProductNamePlugin.php | 95 ------- Plugin/ModifyProductParamsPlugin.php | 138 ---------- Plugin/Query/Resolver/RenderSeoDataPlugin.php | 73 +++++ README.md | 251 +++++++++++++++++- composer.json | 4 +- etc/di.xml | 52 ---- etc/graphql/di.xml | 59 ++++ etc/schema.graphqls | 11 + 21 files changed, 1092 insertions(+), 861 deletions(-) create mode 100644 Model/Category/CategoryModifier.php create mode 100644 Model/Category/CategoryTemplateRendererAdapter.php create mode 100644 Model/Category/Products/CategoryDataFiller.php create mode 100755 Model/LayeredFiltersProvider/GraphQl.php create mode 100644 Model/Product/ProductModifier.php create mode 100644 Model/Product/ProductTemplateRendererAdapter.php create mode 100755 Model/RequestedFilterArgsStorage.php delete mode 100755 Plugin/AddSeoNameToCategoryCollectionPlugin.php delete mode 100755 Plugin/AddSeoNameToProductCollectionPlugin.php delete mode 100755 Plugin/ModifyCategoryDescriptionPlugin.php delete mode 100755 Plugin/ModifyCategoryNamePlugin.php delete mode 100755 Plugin/ModifyCategoryParamsPlugin.php delete mode 100755 Plugin/ModifyProductDescriptionsPlugin.php delete mode 100755 Plugin/ModifyProductNamePlugin.php delete mode 100755 Plugin/ModifyProductParamsPlugin.php create mode 100755 Plugin/Query/Resolver/RenderSeoDataPlugin.php delete mode 100755 etc/di.xml create mode 100755 etc/graphql/di.xml create mode 100755 etc/schema.graphqls diff --git a/Model/Category/CategoryModifier.php b/Model/Category/CategoryModifier.php new file mode 100644 index 0000000..c6d1231 --- /dev/null +++ b/Model/Category/CategoryModifier.php @@ -0,0 +1,153 @@ +categoryDynamicRenderer = $categoryDynamicRenderer; + $this->collectionFactory = $collectionFactory; + $this->requestedFilterArgsStorage = $requestedFilterArgsStorage; + $this->templateRendererAdapter = $categoryTemplateRendererAdapter; + $this->eventManager = $eventManager; + $this->attributes = $attributes; + } + + /** + * @param mixed|Value $resolvedValue + * @param ResolveInfo $info + * @param array|null $args + * @return mixed + */ + public function modify( + &$resolvedValue, + ResolveInfo $info, + array $args = null + ) { + $fieldSelection = $info->getFieldSelection(1); + $requestedAttributes = array_keys($fieldSelection['items']); + $attributes = array_intersect($requestedAttributes, $this->attributes); + + if ($attributes) { + $this->requestedFilterArgsStorage->disable(); + + $categoryIds = array_column($resolvedValue['items'], 'id'); + $collection = $this->getCategoryCollection($categoryIds, $attributes); + + foreach ($resolvedValue['items'] as $key => $categoryData) { + + foreach ($attributes as $attribute) { + + if (empty($categoryData[$attribute])) { + continue; + } + + $category = $collection->getItemById($categoryData['id']); + + if ($category) { + $category->setData($categoryData); + $renderedValue = $this->templateRendererAdapter->getRenderedValue( + $attribute, + $category + ); + $resolvedValue['items'][$key][$attribute] = $renderedValue; + } + } + } + + $this->requestedFilterArgsStorage->enable(); + } + } + + /** + * Retrieve loaded category collection + * + * @param array $ids + * @param array $attributes + * @return \Magento\Catalog\Model\ResourceModel\Category\Collection + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function getCategoryCollection(array $ids, array $attributes) + { + $collection = $this->collectionFactory->create(); + $collection->addIdFilter($ids); + $collection->addAttributeToSelect($attributes); + + $this->eventManager->dispatch( + 'mw_seoxtemplates_category_modifier_collection_load_before', + ['collection' => $collection] + ); + + $collection->addAttributeToSelect($this->getTemplateVariables()); + + $this->eventManager->dispatch( + 'mw_seoxtemplates_category_modifier_collection_load_after', + ['collection' => $collection] + ); + + return $collection; + } + + /** + * @todo we need to retrieve parsed SEO-template's variables + * @return string[] + */ + protected function getTemplateVariables(): array + { + return ['name']; + } +} diff --git a/Model/Category/CategoryTemplateRendererAdapter.php b/Model/Category/CategoryTemplateRendererAdapter.php new file mode 100644 index 0000000..08c8890 --- /dev/null +++ b/Model/Category/CategoryTemplateRendererAdapter.php @@ -0,0 +1,50 @@ +categoryDynamicRenderer = $categoryDynamicRenderer; + } + + /** + * @param string $attribute + * @param \Magento\Catalog\Model\Category $category + * @return string + */ + public function getRenderedValue($attribute, $category) + { + $attributeValue = ''; + + if ('meta_title' === $attribute) { + $this->categoryDynamicRenderer->modifyCategoryTitle($category, $attributeValue, true); + } elseif ('meta_description' === $attribute) { + $this->categoryDynamicRenderer->modifyCategoryMetaDescription($category, $attributeValue, true); + } elseif ('meta_keywords' === $attribute) { + $this->categoryDynamicRenderer->modifyCategoryMetaKeywords($category, $attributeValue, true); + } elseif ('description' === $attribute) { + $this->categoryDynamicRenderer->modifyCategoryDescription($category, $attributeValue, true); + } elseif ('category_seo_name' === $attribute) { + $attributeValue = $this->categoryDynamicRenderer->getModifiedCategorySeoName( + $category, + $category->getCategorySeoName(), + true + ); + } + + return $attributeValue; + } +} diff --git a/Model/Category/Products/CategoryDataFiller.php b/Model/Category/Products/CategoryDataFiller.php new file mode 100644 index 0000000..bfceb1b --- /dev/null +++ b/Model/Category/Products/CategoryDataFiller.php @@ -0,0 +1,155 @@ +categoryDynamicRenderer = $categoryDynamicRenderer; + $this->collectionFactory = $collectionFactory; + $this->requestedFilterArgsStorage = $requestedFilterArgsStorage; + $this->categoryTemplateRendererAdapter = $categoryTemplateRendererAdapter; + $this->eventManager = $eventManager; + $this->attributes = $attributes; + } + + /** + * @param mixed|Value $resolvedValue + * @param ResolveInfo $info + * @param array|null $args + * @return mixed + */ + public function modify( + &$resolvedValue, + ResolveInfo $info, + array $args = null + ) { + $fieldSelection = $info->getFieldSelection(1); + + if (!empty($fieldSelection['mw_seo_category_data']) + && !empty($resolvedValue['categories']) + && count($resolvedValue['categories']) === 1 + && $resolvedValue['layer_type'] === 'category' + ) { + $requestedAttributes = array_keys($fieldSelection['mw_seo_category_data']); + + $attributes = array_intersect($requestedAttributes, $this->attributes); + + if ($attributes) { + + $this->requestedFilterArgsStorage->set($args['filter']); + $collection = $this->getCategoryCollection([$resolvedValue['categories'][0]], $attributes); + /** @var \Magento\Catalog\Model\Category $category */ + $category = $collection->getFirstItem(); + + if ($category->getId()) { + $resolvedValue['mw_seo_category_data'] = $fieldSelection['mw_seo_category_data']; + + foreach ($attributes as $attribute) { + $renderedValue = $this->categoryTemplateRendererAdapter->getRenderedValue( + $attribute, + $category + ); + + $resolvedValue['mw_seo_category_data'][$attribute] = $renderedValue; + } + } + } + } + + return $resolvedValue; + } + + /** + * Retrieve loaded category collection + * + * @param array $ids + * @param array $attributes + * @return \Magento\Catalog\Model\ResourceModel\Category\Collection + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function getCategoryCollection(array $ids, array $attributes) + { + $collection = $this->collectionFactory->create(); + $collection->addIdFilter($ids); + $collection->addAttributeToSelect($attributes); + $collection->addAttributeToSelect($this->getTemplateVariables()); + + $this->eventManager->dispatch( + 'mw_seoxtemplates_category_data_filler_collection_load_before', + ['collection' => $collection] + ); + + $collection->load(); + + $this->eventManager->dispatch( + 'mw_seoxtemplates_category_data_filler_collection_load_after', + ['collection' => $collection] + ); + + return $collection; + } + + /** + * @todo we need to retrieve parsed SEO-template's variables + * @return string[] + */ + protected function getTemplateVariables() + { + return ['name']; + } +} diff --git a/Model/LayeredFiltersProvider/GraphQl.php b/Model/LayeredFiltersProvider/GraphQl.php new file mode 100755 index 0000000..f9c2010 --- /dev/null +++ b/Model/LayeredFiltersProvider/GraphQl.php @@ -0,0 +1,134 @@ +requestedFilterArgsStorage = $requestedFilterArgsStorage; + $this->storeManager = $storeManager; + $this->attributeResource = $attributeResource; + $this->attributeRepository = $attributeRepository; + } + + public function getCurrentLayeredFilters(): array + { + $attributes = $this->requestedFilterArgsStorage->get(); + + $filterData = []; + + foreach ($attributes as $attributeCode => $rule) { + if ('category_id' === $attributeCode) { + continue; + } + + if (!empty($rule['eq'])) { + $requestedOption = $rule['eq']; + + try { + $attribute = $this->attributeRepository->get($attributeCode); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + continue; + } + + $attribute->setData('store_id', $this->storeManager->getStore()->getId()); + $attributeOptions = $attribute->getOptions(); + + foreach ($attributeOptions as $option) { + + if ($option['value'] == $requestedOption) { + $filterData[] = [ + 'name' => $this->getAttributeLabel($attribute), + 'label' => $this->getAttributeOptionLabel($option), + 'code' => $attributeCode + ]; + } + } + } + } + + return $filterData; + } + + /** + * @param \Magento\Eav\Api\Data\AttributeInterface $attribute + * @return string|null + */ + protected function getAttributeLabel($attribute) + { + foreach ($attribute->getFrontendLabels() as $label) { + if ((int)$label->getStoreId() === (int)$this->storeManager->getStore()->getId()) { + return $label->getLabel(); + } + } + + return $attribute->getDefaultFrontendLabel(); + } + + /** + * @param \Magento\Eav\Api\Data\AttributeOptionInterface $option + * @return string|null + */ + protected function getAttributeOptionLabel($option) + { + $optionStoreLabel = $this->getOptionStoreLabel($option->getId()); + if ($optionStoreLabel) { + return $optionStoreLabel; + } + + return $option->getLabel(); + } + + /** + * @param (int)$optionId + * @return mixed + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + protected function getOptionStoreLabel($optionId) + { + $connection = $this->attributeResource->getConnection(); + $bind = [ + ':attribute_id' => (int)$optionId, + ':store_id' => (int)$this->storeManager->getStore()->getId() + ]; + $select = $connection->select()->from( + $this->attributeResource->getTable('eav_attribute_label'), + ['store_id', 'value'] + )->where( + 'attribute_id = :attribute_id' + )->where( + 'store_id = :store_id' + ); + + return $connection->fetchRow($select, $bind); + } +} diff --git a/Model/Product/ProductModifier.php b/Model/Product/ProductModifier.php new file mode 100644 index 0000000..36ef17e --- /dev/null +++ b/Model/Product/ProductModifier.php @@ -0,0 +1,100 @@ +productFactory = $productFactory; + $this->eventManager = $eventManager; + $this->templateRendererAdapter = $templateRendererAdapter; + $this->attributes = $attributes; + } + + /** + * @param mixed|Value $resolvedValue + * @param ResolveInfo $info + * @param array|null $args + * @return mixed + */ + public function modify( + &$resolvedValue, + ResolveInfo $info, + array $args = null + ) { + $fieldSelection = $info->getFieldSelection(1); + $requestedAttributes = array_keys($fieldSelection['items']); + $attributes = array_intersect($requestedAttributes, $this->attributes); + + if ($attributes) { + + foreach ($resolvedValue['items'] as $key => $productData) { + + foreach ($attributes as $attribute) { + + if (empty($productData[$attribute])) { + continue; + } + + $product = $this->productFactory->create(); + $product->setData($productData); + + $renderedValue = $this->templateRendererAdapter->getRenderedValue($attribute, $product); + + $resolvedValue['items'][$key][$attribute] = $renderedValue; + } + } + } + } +} diff --git a/Model/Product/ProductTemplateRendererAdapter.php b/Model/Product/ProductTemplateRendererAdapter.php new file mode 100644 index 0000000..0c9eb51 --- /dev/null +++ b/Model/Product/ProductTemplateRendererAdapter.php @@ -0,0 +1,65 @@ +metaTitleConverter = $metaTitleConverter; + $this->metaDescriptionConverter = $metaDescriptionConverter; + $this->metaKeywordsConverter = $metaKeywordsConverter; + $this->seoNameConverter = $seoNameConverter; + } + + /** + * @param string $attribute + * @param \Magento\Catalog\Model\Product $product + * @return string + */ + public function getRenderedValue($attribute, $product) + { + $attributeValue = ''; + + if ($attribute === 'meta_title') { + $attributeValue = $this->metaTitleConverter->convert($product, $product->getData($attribute), true); + } elseif ($attribute === 'meta_description') { + $attributeValue = $this->metaDescriptionConverter->convert($product, $product->getData($attribute), true); + } elseif ($attribute === 'meta_keyword') { + $attributeValue = $this->metaKeywordsConverter->convert($product, $product->getData($attribute), true); + } elseif ($attribute === 'product_seo_name') { + $attributeValue = $this->seoNameConverter->convert($product, $product->getData($attribute), true); + } + + return $attributeValue; + } +} diff --git a/Model/RequestedFilterArgsStorage.php b/Model/RequestedFilterArgsStorage.php new file mode 100755 index 0000000..3cd8779 --- /dev/null +++ b/Model/RequestedFilterArgsStorage.php @@ -0,0 +1,40 @@ +disabled = true; + } + + public function enable(): void + { + $this->disabled = false; + } + + public function set(array $filters) + { + $this->filters = $filters; + } + + public function get(): ?array + { + if ($this->disabled === false) { + return $this->filters; + } + + return []; + } +} diff --git a/Plugin/AddSeoNameToCategoryCollectionPlugin.php b/Plugin/AddSeoNameToCategoryCollectionPlugin.php deleted file mode 100755 index 8cd2e2e..0000000 --- a/Plugin/AddSeoNameToCategoryCollectionPlugin.php +++ /dev/null @@ -1,53 +0,0 @@ -helperData = $helperData; - } - - /** - * Adds "category_seo_name" attribute to category collection if needed - * - * @param AttributesJoiner $subject - * @param $result - * @param FieldNode $fieldNode - * @param AbstractCollection $collection - */ - public function afterJoin( - AttributesJoiner $subject, - $result, - FieldNode $fieldNode, - AbstractCollection $collection - ): void { - if ($collection instanceof \Magento\Catalog\Model\ResourceModel\Category\Collection) { - if ($this->helperData->isUseCategorySeoName()) { - if ($collection->isAttributeAdded('name')) { - $collection->addAttributeToSelect('category_seo_name'); - } - } - } - } -} \ No newline at end of file diff --git a/Plugin/AddSeoNameToProductCollectionPlugin.php b/Plugin/AddSeoNameToProductCollectionPlugin.php deleted file mode 100755 index e729de0..0000000 --- a/Plugin/AddSeoNameToProductCollectionPlugin.php +++ /dev/null @@ -1,54 +0,0 @@ -helperData = $helperData; - } - - /** - * @param CollectionProcessorInterface $subject - * @param Collection $result - * @param Collection $collection - * @param SearchCriteriaInterface $searchCriteria - * @param array $attributeNames - * @return Collection - */ - public function afterProcess( - CollectionProcessorInterface $subject, - Collection $result, - Collection $collection, - SearchCriteriaInterface $searchCriteria, - array $attributeNames - ) { - if ($this->helperData->isUseProductSeoName()) { - if ($result->isAttributeAdded('name')) { - $result->addAttributeToSelect('product_seo_name'); - } - } - - return $result; - } -} \ No newline at end of file diff --git a/Plugin/ModifyCategoryDescriptionPlugin.php b/Plugin/ModifyCategoryDescriptionPlugin.php deleted file mode 100755 index ef584a2..0000000 --- a/Plugin/ModifyCategoryDescriptionPlugin.php +++ /dev/null @@ -1,114 +0,0 @@ -helperData = $helperData; - $this->dynamicRenderer = $renderer; - } - - /** - * @param \Magento\CatalogGraphQl\Model\Resolver\Category\CategoryHtmlAttribute $subject - * @param string|null $result - * @param Field $field - * @param $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - */ - public function afterResolve( - $subject, - $result, - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - if (!$result) { - return $result; - } - - /** @var \Magento\Catalog\Model\Category $category */ - $category = $value['model']; - $fieldName = $field->getName(); - - if ($this->out($category, $fieldName)) { - return $result; - } - - if (!$this->isCurrentEntity($category, $info)) { - return $result; - } - - if ($this->dynamicRenderer->modifyCategoryDescription($category)) { - return $category->getData('description'); - } - - return $result; - } - - /** - * @param \Magento\Catalog\Model\Category $category - * @param ResolveInfo $info - * @return bool - */ - protected function isCurrentEntity($category, $info) - { - $variables = $info->variableValues; - - return !empty($variables['_filter_0']['category_url_path']['eq']) - && $variables['_filter_0']['category_url_path']['eq'] === $category->getUrlPath(); - } - - /** - * Check if go out - * - * @param \Magento\Catalog\Model\Category $category - * @param string $fieldName - * @return boolean - */ - protected function out($category, $fieldName) - { - if (!is_object($category)) { - return true; - } - - if ($fieldName !== 'description') { - return true; - } - - return false; - } -} \ No newline at end of file diff --git a/Plugin/ModifyCategoryNamePlugin.php b/Plugin/ModifyCategoryNamePlugin.php deleted file mode 100755 index 62eec9a..0000000 --- a/Plugin/ModifyCategoryNamePlugin.php +++ /dev/null @@ -1,96 +0,0 @@ -helperData = $helperData; - } - - /** - * @param \MageWorx\SeoAllGraphQl\Model\Resolver\Category\SeoRenderedElement $subject - * @param string|null $result - * @param Field $field - * @param $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - * - * @return strung - */ - public function afterResolve( - $subject, - $result, - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - if (!$result) { - return $result; - } - - /** @var \Magento\Catalog\Model\Category $category */ - $category = $value['model']; - $fieldName = $field->getName(); - - if ($this->out($category, $fieldName)) { - return $result; - } - - $categorySeoName = $category->getData('category_seo_name'); - $category->setData('name', $categorySeoName); - - return $categorySeoName; - } - - /** - * Check if go out - * - * @param \Magento\Catalog\Model\Category $category - * @param string $fieldName - * @return boolean - */ - protected function out($category, $fieldName) - { - if (!is_object($category)) { - return true; - } - - if ($fieldName !== 'name') { - return true; - } - - if (!$this->helperData->isUseCategorySeoName()) { - return true; - } - - if (empty($category->getData('category_seo_name'))) { - return true; - } - - return false; - } -} \ No newline at end of file diff --git a/Plugin/ModifyCategoryParamsPlugin.php b/Plugin/ModifyCategoryParamsPlugin.php deleted file mode 100755 index c402869..0000000 --- a/Plugin/ModifyCategoryParamsPlugin.php +++ /dev/null @@ -1,127 +0,0 @@ - 'modifyCategoryTitle', - 'meta_description' => 'modifyCategoryMetaDescription', - 'meta_keywords' => 'modifyCategoryMetaKeywords' - ]; - - /** - * ModifyCategoryDescriptionPlugin constructor. - * - * @param \MageWorx\SeoXTemplates\Helper\Data $helperData - * @param Renderer $renderer - */ - public function __construct( - \MageWorx\SeoXTemplates\Helper\Data $helperData, - Renderer $renderer - ) { - $this->helperData = $helperData; - $this->dynamicRenderer = $renderer; - } - - /** - * @param \MageWorx\SeoAllGraphQl\Model\Resolver\Category\SeoRenderedElement $subject - * @param string|null $result - * @param Field $field - * @param $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - */ - public function afterResolve( - $subject, - $result, - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - if (!$result) { - return $result; - } - - /** @var \Magento\Catalog\Model\Category $category */ - $category = $value['model']; - $fieldName = $field->getName(); - - if ($this->out($category, $fieldName)) { - return $result; - } - - if (!$this->isCurrentEntity($category, $info)) { - return $result; - } - - $methodName = $this->rendererMethods[$fieldName]; - $convertedResult = ''; - - - if ($this->dynamicRenderer->$methodName($category, $convertedResult)) { - return $convertedResult; - } - - return $result; - } - - /** - * @param \Magento\Catalog\Model\Category $category - * @param ResolveInfo $info - * @return bool - */ - protected function isCurrentEntity($category, $info) - { - $variables = $info->variableValues; - - return !empty($variables['_filter_0']['category_url_path']['eq']) - && $variables['_filter_0']['category_url_path']['eq'] === $category->getUrlPath(); - } - - /** - * Check if go out - * - * @param \Magento\Catalog\Model\Category $category - * @param string $fieldName - * @return boolean - */ - protected function out($category, $fieldName) - { - if (!is_object($category)) { - return true; - } - - if (empty($this->rendererMethods[$fieldName])) { - return true; - } - - return false; - } -} \ No newline at end of file diff --git a/Plugin/ModifyProductDescriptionsPlugin.php b/Plugin/ModifyProductDescriptionsPlugin.php deleted file mode 100755 index b37a764..0000000 --- a/Plugin/ModifyProductDescriptionsPlugin.php +++ /dev/null @@ -1,129 +0,0 @@ -helperData = $helperData; - $this->shortDescriptionConverter = $shortDescriptionConverter; - $this->descriptionConverter = $descriptionConverter; - } - - /** - * @param \Magento\CatalogGraphQl\Model\Resolver\Product\ProductComplexTextAttribute $subject - * @param string|null $result - * @param Field $field - * @param $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - */ - public function afterResolve( - $subject, - $result, - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - if (!$result) { - return $result; - } - - /** @var \Magento\Catalog\Model\Product $product */ - $product = $value['model']; - $fieldName = $field->getName(); - - if ($this->out($product, $fieldName)) { - return $result; - } - - if (empty($result['html'])) { - return $result; - } - - if (!$this->isCurrentEntity($product, $info)) { - return $result; - } - - if ($fieldName === 'short_description') { - $result['html'] = $this->shortDescriptionConverter->convert($product, $result['html'], true); - $product->setShortDescription($result['html']); - } - - if ($fieldName === 'description') { - $result['html'] = $this->descriptionConverter->convert($product, $result['html'], true); - $product->setDescription($result['html']); - } - - return $result; - } - - /** - * @param \Magento\Catalog\Model\Product $product - * @param ResolveInfo $info - * @return bool - */ - protected function isCurrentEntity($product, $info) - { - $variables = $info->variableValues; - - return !empty($variables['_filter_0']['url_key']['eq']) - && $variables['_filter_0']['url_key']['eq'] === $product->getUrlKey(); - } - - /** - * Check if go out - * - * @param \Magento\Catalog\Model\Product $product - * @param string $fieldName - * @return boolean - */ - protected function out($product, $fieldName) - { - if (!is_object($product)) { - return true; - } - - if (!in_array($fieldName, ['description', 'short_description'])) { - return true; - } - - return false; - } -} \ No newline at end of file diff --git a/Plugin/ModifyProductNamePlugin.php b/Plugin/ModifyProductNamePlugin.php deleted file mode 100755 index e8aba7e..0000000 --- a/Plugin/ModifyProductNamePlugin.php +++ /dev/null @@ -1,95 +0,0 @@ -helperData = $helperData; - } - - /** - * @param \MageWorx\SeoAllGraphQl\Model\Resolver\Product\SeoRenderedElement $subject - * @param string|null $result - * @param Field $field - * @param $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - * - * @return string - */ - public function afterResolve( - $subject, - $result, - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - if (!$result) { - return $result; - } - - /** @var \Magento\Catalog\Model\Product $product */ - $product = $value['model']; - $fieldName = $field->getName(); - - if ($this->out($product, $fieldName)) { - return $result; - } - - $productSeoName = $product->getData('product_seo_name'); - $product->setData('name', $productSeoName); - - return $productSeoName; - } - - /** - * Check if go out - * - * @param \Magento\Catalog\Model\Product $product - * @param string $fieldName - * @return boolean - */ - protected function out($product, $fieldName) - { - if (!is_object($product)) { - return true; - } - - if ($fieldName !== 'name') { - return true; - } - - if (!$this->helperData->isUseProductSeoName()) { - return true; - } - - if (empty($product->getData('product_seo_name'))) { - return true; - } - - return false; - } -} \ No newline at end of file diff --git a/Plugin/ModifyProductParamsPlugin.php b/Plugin/ModifyProductParamsPlugin.php deleted file mode 100755 index 920f6a9..0000000 --- a/Plugin/ModifyProductParamsPlugin.php +++ /dev/null @@ -1,138 +0,0 @@ -helperData = $helperData; - $this->metaTitleConverter = $metaTitleConverter; - $this->metaDescriptionConverter = $metaDescriptionConverter; - $this->metaKeywordsConverter = $metaKeywordsConverter; - } - - /** - * @param \MageWorx\SeoAllGraphQl\Model\Resolver\Product\SeoRenderedElement $subject - * @param string|null $result - * @param Field $field - * @param $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - */ - public function afterResolve( - $subject, - $result, - Field $field, - $context, - ResolveInfo $info, - array $value = null, - array $args = null - ) { - if (!$result) { - return $result; - } - - /** @var \Magento\Catalog\Model\Product $product */ - $product = $value['model']; - $fieldName = $field->getName(); - - if ($this->out($product, $fieldName)) { - return $result; - } - - if (!$this->isCurrentEntity($product, $info)) { - return $result; - } - - if ($fieldName === 'meta_title') { - $result = $this->metaTitleConverter->convert($product, $result, true); - $product->setMetaTitle($result); - } - - if ($fieldName === 'meta_description') { - $result = $this->metaDescriptionConverter->convert($product, $result, true); - $product->setMetaDescription($result); - } - - if ($fieldName === 'meta_keyword') { - $result = $this->metaKeywordsConverter->convert($product, $result, true); - $product->setMetaKeyword($result); - } - - return $result; - } - - /** - * @param \Magento\Catalog\Model\Product $product - * @param ResolveInfo $info - * @return bool - */ - protected function isCurrentEntity($product, $info) - { - $variables = $info->variableValues; - - return !empty($variables['_filter_0']['url_key']['eq']) - && $variables['_filter_0']['url_key']['eq'] === $product->getUrlKey(); - } - - /** - * Check if go out - * - * @param \Magento\Catalog\Model\Product $product - * @param string $fieldName - * @return boolean - */ - protected function out($product, $fieldName) - { - if (!is_object($product)) { - return true; - } - - if (!in_array($fieldName, ['meta_title', 'meta_description', 'meta_keyword'])) { - return true; - } - - return false; - } -} \ No newline at end of file diff --git a/Plugin/Query/Resolver/RenderSeoDataPlugin.php b/Plugin/Query/Resolver/RenderSeoDataPlugin.php new file mode 100755 index 0000000..f25c219 --- /dev/null +++ b/Plugin/Query/Resolver/RenderSeoDataPlugin.php @@ -0,0 +1,73 @@ +categoryDataModifier = $categoryDataModifier; + $this->categoryDataFiller = $categoryDataFiller; + $this->productsDataModifier = $productsDataModifier; + } + + /** + * @param ResolverInterface $subject + * @param mixed|Value $resolvedValue + * @param Field $field + * @param Context $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * @return mixed + */ + public function afterResolve( + ResolverInterface $subject, + $resolvedValue, + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if ($subject instanceof \Magento\CatalogGraphQl\Model\Resolver\CategoriesQuery) { + $this->categoryDataModifier->modify($resolvedValue, $info, $args); + } elseif ($subject instanceof \Magento\CatalogGraphQl\Model\Resolver\Products) { + $this->categoryDataFiller->modify($resolvedValue, $info, $args); + $this->productsDataModifier->modify($resolvedValue, $info, $args); + } + + return $resolvedValue; + } +} diff --git a/README.md b/README.md index 81a23b7..a80cf6e 100755 --- a/README.md +++ b/README.md @@ -10,4 +10,253 @@ GraphQL API module for Mageworx [Magento 2 SEO Suite Ultimate](https://www.magew - Execute the following command: `composer require mageworx/module-seoxtemplates-graph-ql` ## How to use -The SeoXTemplatesGraphQl modifies the necessary attributes of the entities of Product, categories and CMS pages, when you call these entities using the standard GraphQL requests. + +
+ Categories query example +All Category SEO-attributes (meta title, meta description, ...) set in "Bags[ - Filters: {filter_all}]" + +```graphql + +query GetCategories($id: String!, $pageSize: Int!, $currentPage: Int!, $filters: ProductAttributeFilterInput!, $sort: ProductAttributeSortInput) { + categories(filters: {ids: {in: [$id]}}) { + items { + uid + ...CategoryFragment + } + } + products(pageSize: $pageSize, currentPage: $currentPage, filter: $filters, sort: $sort) { + ...ProductsFragment + mw_seo_category_data { + meta_title + meta_description + meta_keywords + category_seo_name + } + } +} + +fragment CategoryFragment on CategoryTree { + uid + meta_title + meta_keywords + meta_description + category_seo_name +} + +fragment ProductsFragment on Products { + items { + id + uid + name + sku + url_key + } + page_info { + total_pages + } + total_count +} +``` + +Query Variables: + +```json +{ + "currentPage": 1, + "id": "4", + "filters": { + "color": { + "eq": "49" + }, + "category_id": { + "eq": "4" + } + }, + "pageSize": 1, + "sort": { + "position": "ASC" + } +} +``` + +Answer: + +```json +{ + "data": { + "categories": { + "items": [ + { + "uid": "NA==", + "meta_title": "Bags", + "meta_keywords": "Bags", + "meta_description": "Bags", + "category_seo_name": "Bags" + } + ] + }, + "products": { + "items": [ + { + "id": 7, + "uid": "Nw==", + "name": "Impulse Duffle", + "sku": "24-UB02", + "url_key": "impulse-duffle" + } + ], + "page_info": { + "total_pages": 4 + }, + "total_count": 4, + "mw_seo_category_data": { + "meta_title": "Bags - Filters: Color: Black", + "meta_description": "Bags - Filters: Color: Black", + "meta_keywords": "Bags - Filters: Color: Black", + "category_seo_name": "Bags - Filters: Color: Black" + } + } + } +} +``` + +
+ + +
+ Products query example + +All Product SEO-attributes (meta title, meta description, ...) set in "Wayfarer Messenger Bag[ in {categories}]" + +```graphql +query getProductDetailForProductPage($urlKey: String!) { + products(filter: {url_key: {eq: $urlKey}}) { + items { + id + uid + ...ProductDetailsFragment + } + } +} + +fragment ProductDetailsFragment on ProductInterface { + categories { + uid + breadcrumbs { + category_uid + } + } + id + uid + meta_title + meta_description + meta_keyword + product_seo_name + name + sku + url_key + ... on ConfigurableProduct { + configurable_options { + attribute_code + attribute_id + uid + label + values { + uid + default_label + label + store_label + use_default_value + } + } + variants { + attributes { + code + value_index + } + product { + uid + media_gallery_entries { + uid + disabled + file + label + position + } + sku + stock_status + } + } + } +} +``` + +Query Variables: + +```json +{ + "currentPage": 1, + "id": "4", + "filters": { + "color": { + "eq": "49" + }, + "category_id": { + "eq": "4" + } + }, + "pageSize": 1, + "sort": { + "position": "ASC" + } +} +``` + +Answer: + +```json +{ + "data": { + "products": { + "items": [ + { + "id": 4, + "uid": "NA==", + "categories": [ + { + "uid": "Mw==", + "breadcrumbs": null + }, + { + "uid": "NA==", + "breadcrumbs": [ + { + "category_uid": "Mw==" + } + ] + }, + { + "uid": "Nw==", + "breadcrumbs": null + }, + { + "uid": "OA==", + "breadcrumbs": null + } + ], + "meta_title": "Wayfarer Messenger Bag", + "meta_description": "Wayfarer Messenger Bag", + "meta_keyword": "Wayfarer Messenger Bag", + "product_seo_name": "Wayfarer Messenger Bag", + "name": "Wayfarer Messenger Bag", + "sku": "24-MB05", + "url_key": "wayfarer-messenger-bag" + } + ] + } + } +} + +``` + +
diff --git a/composer.json b/composer.json index a770964..3da4a08 100755 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "N/A", "type": "magento2-module", "require": { - "mageworx/module-seoxtemplates": ">= 2.8.8", + "mageworx/module-seoxtemplates": ">= 2.13.8", "magento/module-cms-graph-ql": ">= 100.3.1 < 101", "magento/module-catalog-graph-ql": ">= 100.3.1 < 101" }, @@ -19,5 +19,5 @@ "MageWorx\\SeoXTemplatesGraphQl\\": "" } }, - "version": "1.0.0" + "version": "2.0.0" } diff --git a/etc/di.xml b/etc/di.xml deleted file mode 100755 index 2db78cc..0000000 --- a/etc/di.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/etc/graphql/di.xml b/etc/graphql/di.xml new file mode 100755 index 0000000..d92264a --- /dev/null +++ b/etc/graphql/di.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + MageWorx\SeoXTemplatesGraphQl\Model\LayeredFiltersProvider\GraphQl + + + + + + + + meta_title + meta_description + meta_keywords + description + category_seo_name + + + + + + + + meta_title + meta_description + meta_keywords + description + category_seo_name + + + + + + + + meta_title + meta_description + meta_keyword + description + product_seo_name + + + + diff --git a/etc/schema.graphqls b/etc/schema.graphqls new file mode 100755 index 0000000..a0d8654 --- /dev/null +++ b/etc/schema.graphqls @@ -0,0 +1,11 @@ +type Products { + mw_seo_category_data: MwSeoCategoryData @doc(description: "An object that includes SEO data for category from filter.") +} + +type MwSeoCategoryData @doc(description: "SEO Category data for product list") { + meta_title: String @doc(description: "Category Meta Title") + meta_description: String @doc(description: "Category Meta Description") + meta_keywords: String @doc(description: "Category Meta Keywords") + description: String @doc(description: "Category Description") + category_seo_name: String @doc(description: "Category SEO Name") +}