如何按自定义产品属性过滤 WooCommerce 商店产品(产品循环)?

Mr.*_* Jo 1 php regex mysql wordpress woocommerce

我正在寻找一种简单的方法来通过自定义产品属性过滤商店循环内的所有 WooCommerce 商店产品,如下所示:

\n

在此输入图像描述

\n

这些属性可以有很多带有特殊字符(除了普通拉丁字符之外)的值,例如\xc3\xbc\xc3\x9f

\n

我在 Stack Overflow 上做了很多研究,但还没有找到好的解决方案。

\n

Mr.*_* Jo 5

当我在这里开始我的问题时,我认为这将是一次轻松的旅行 \xe2\x80\x93 哈哈。由于我没有及时得到答案,我又开始研究,并在 Stack Overflow 上发现了大量未回答或不具体的问题。一个快速而简单的解决方案是将所有属性添加为全局属性,并使用分类查询过滤器来检查每个产品,例如pa_xxxx.

\n

我的意思是,这个解决方案完全有效,但会根据您的产品数量增加大量的手动工作时间。所以我没有选择(> 4000 个产品)。

\n

在我的研究过程中,我找到了一个答案,它使用名为的 WooCommerce 过滤器挂钩来检查存储在每个产品的键下的表woocommerce_product_query_meta_query内的序列化自定义属性内是否有任何给定值:wp_postmeta_product_attributes

\n
add_filter( \'woocommerce_product_query_meta_query\', \'filter_woocommerce_product_query_meta_query\', 10, 2 );\nfunction filter_woocommerce_product_query_meta_query( array $meta_query ): array {\n    if ( is_shop() || is_product_category() ) {\n        $meta_query[] = [\n            \'key\'     => \'_product_attributes\',\n            \'value\'   => \'gr\xc3\xbcn\',\n            \'compare\' => \'LIKE\'\n        ];\n    }\n\n    return $meta_query;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

(我添加了商店或类别页面的检查)

\n

首先,我真的很高兴,因为它有效。但几分钟后我意识到,这个设计完全没用,因为它忽略了所有属性名称,只是搜索gr\xc3\xbcn并且gr\xc3\xbcn可以是从颜色到漂亮草地的任何东西。所以没有精确过滤器的选择。

\n

然后我想起来,我可以在 MySQL 中使用非贪婪正则表达式。对我来说并不简单,但可能。

\n

由于稍后会在内部解析挂钩$wpdb,因此我尝试找出允许哪些比较操作:

\n
array( \'=\', \'IN\', \'BETWEEN\', \'LIKE\', \'REGEXP\', \'RLIKE\', \'>\', \'>=\', \'<\', \'<=\' )\n
Run Code Online (Sandbox Code Playgroud)\n

太好了,我们REGEXP有空。所以我开始编写我的正则表达式来检查内部序列化属性。几个小时后,我很自豪地向您介绍我的职能:

\n
add_filter( \'woocommerce_product_query_meta_query\', \'filter_woocommerce_product_query_meta_query\', 10, 2 );\nfunction filter_woocommerce_product_query_meta_query( array $meta_query ): array {\n    if ( is_shop() || is_product_category() ) {\n        $quoted_key   = preg_quote( \'farbe\', \'/\' );\n        $quoted_value = preg_quote( \'gr\xc3\xbcn\', \'/\' );\n\n        $meta_query[] = [\n            \'key\'     => \'_product_attributes\',\n            \'value\'   => \'s:[0-9]+:"\' . $quoted_key . \'";[a-z]:[0-9]+:\\{[a-z]:[0-9]+:"name";[a-z]:[0-9]+:"([a-zA-Z\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f0-9?!+*-_.:,;=&%$/()@<> ]+)";[a-z]:[0-9]+:"value";[a-z]:[0-9]+:"(\' . $quoted_value . \'[ ";]|([a-zA-Z\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f0-9?!+*-_.:,;=&%$/()@<> ]+ \\| )+(\' . $quoted_value . \'[ ";]))\',\n            \'compare\' => \'REGEXP\'\n        ];\n    }\n\n    return $meta_query;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

为了稍微解释一下我的正则表达式,我将向您展示一个直接来自我的数据库的序列化属性字符串的示例:

\n
\n

a:2:{s:5:"farbe";a:6:{s:4:"名称";s:5:"Farbe";s:5:"值";s:12:"Gr\xc3 \xbcn |\nGelb";s:8:"位置";i:0;s:10:"is_visible";i:1;s:12:"is_variation";i:1;s:11:"is_taxonomy" ;i:0;}s:7:"groesse";a:6:{s:4:"名称";s:7:"Gr\xc3\xb6\xc3\x9fe";s:5:"值" ;s:5:"S\n|\nM";s:8:"位置";i:1;s:10:"is_visible";i:1;s:12:"is_variation";i:1; s:11:"is_taxonomy";i:0;}}

\n
\n

正如您在上面看到的,在我的函数中,我们想要搜索名为 的键farbe并检查它是否包含 value gr\xc3\xbcn。当您检查我的数据示例时,您可以看到,我们有一个与我的搜索匹配的正确数据集。

\n

在深入研究我的正则表达式之前,我想解释一下preg_qoute(). 由于我们有一个正则表达式,因此可能会出现包含特殊符号的字符串,如果我们不对其进行转义,这些特殊符号将被识别为正则表达式的一部分。所以我们使用上面的函数来做到这一点。

\n

因此,让我们深入研究我的正则表达式(因为我们不能使用贪婪的正则表达式,所以我们需要构建所有内容,直到找到我们的值):

\n
    \n
  • s:[0-9]+:"这部分应该找到一个属性的开头,例如s:5:"以 a 开头s:和之间的任何数字,0-9直到结束,使用 a+后跟 a"
  • \n
  • 现在我们可以插入我们的钥匙,\' . $quoted_key . \'例如farbe,它将直接出现在一个"标志之后
  • \n
  • 现在我们要继续,直到使用 到达真实姓名字段(不是 WooCommerce 生成的密钥)";[a-z]:[0-9]+:\\{[a-z]:[0-9]+:"。我们再次在这里匹配所有可能的序列化结构值。可以看到,我们还需要对{属性集的开头进行转义,包括名称和值
  • \n
  • 此时,我们不会传递名称,但会通过使用“"name";[a-z]:[0-9]+:"([a-zA-Z\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f0-9?!+*-_.:,;=&%$/()@<> ]+)";我们允许名称包含在 中定义的所有符号”来期望一个名称[]";我们还包括一个模式来仍然匹配序列化的字符串结构并再次关闭所有内容
  • \n
  • 最后我们有我们的值检查部分[a-z]:[0-9]+:"value";[a-z]:[0-9]+:"(\' . $quoted_value . \'[ ";]|([a-zA-Z\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f0-9?!+*-_.:,;=&%$/()@<> ]+ \\| )+(\' . $quoted_value . \'[ ";]))。首先,我们尝试再次匹配序列化的字符串结构,[a-z]:[0-9]+:"后跟value标识符。现在事情变得棘手了。如您所见,我将 qouted 值传递给 2 个循环。一个检查值是否放在开头,另一个检查值内部,用符号分隔并再次|结束";
  • \n
\n

我不想描述 RegEx 的每一个部分,但我想你已经明白了。由于我不是 RegEx 专业人士,因此 RegEx 可能包括优化工作。另外,我还没有涵盖所有可用的语言或符号,因为我不需要它们。

\n

您还可以放置一个 PHPforeach循环,该循环遍历一组值,以将具有不同值的 RegEx 多次添加到数组中$meta_query。因为我想让事情变得简单,所以我故意决定不使用像这样的值组,(gr\xc3\xbcn|rot|gelb)因为它似乎有潜在的错误。

\n

您可以在编辑器中找到正则表达式:https://extendsclass.com/regex/6cc8142

\n

我希望我能通过本教程为您提供一些帮助,让您的一天过得更好。请随意发布您对我的正则表达式的改进。干杯。

\n

更新:2022年10月26日

\n

我的上述解决方案适用于AND数据库内部的关系。例如,这意味着:WHERE color = red AND blue AND green。如果您想通过向查询添加另一个属性检查来扩展显示的产品数量,您应该OR通过嵌套查询本身并添加以下键来在查询内使用关系relation

\n
add_filter( \'woocommerce_product_query_meta_query\', \'filter_woocommerce_product_query_meta_query\', 10, 2 );\nfunction filter_woocommerce_product_query_meta_query( array $meta_query ): array {\n    if ( is_shop() || is_product_category() ) {\n        $quoted_key   = preg_quote( \'farbe\', \'/\' );\n        $quoted_value = preg_quote( \'gr\xc3\xbcn\', \'/\' );\n\n        $meta_query[] = [\n            \'relation\' => \'OR\',\n            [\n                \'key\'     => \'_product_attributes\',\n                \'value\'   => \'s:[0-9]+:"\' . $quoted_key . \'";[a-z]:[0-9]+:\\{[a-z]:[0-9]+:"name";[a-z]:[0-9]+:"([a-zA-Z\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f0-9?!+*-_.:,;=&%$/()@<> ]+)";[a-z]:[0-9]+:"value";[a-z]:[0-9]+:"(\' . $quoted_value . \'[ ";]|([a-zA-Z\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f0-9?!+*-_.:,;=&%$/()@<> ]+ \\| )+(\' . $quoted_value . \'[ ";]))\',\n                \'compare\' => \'REGEXP\'\n            ]\n            // Add multiple arrays like the one above here to extend the check\n        ];\n    }\n\n    return $meta_query;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果要添加另一个属性检查,则需要在主数组内第一个子数组之后添加另一个子数组。

\n

  • 如果对你有帮助,请给我点个赞吧:) (2认同)