0

I have a plugin that stories a grid of integers in meta fields like so:

'pricing_info' => 
  array (
    0 => '1 | 1 | 1',
    1 => '1.5 | 1.5 | 1.5',
    2 => '22 | 22 | 22',
  ),

So its basically using the | as a divider. Not great design, but alas here we are.

The three integers within each array element represent 3 different variables.

How can I define my meta_query to search for each 3 of those variables with different user inputs.

Example: assume the three variables are $_POST['var1'], $_POST['var2'], $_POST['var3'].

We need to take those three variables and search with the each element of 'pricing_info' array using meta_query (where each variable is divided by |).

Is this even possible within meta-query?

Thank you so much for any guidance.

1
  • 1
    Pretty sure you cant. When you have the data in php it is a php array. When it is stored in MySQL it is stored as a string. You need to pull it out of the database and then query it in php. Commented May 6 at 3:08

1 Answer 1

0

For array and object meta values, WordPress serializes them to string representations using serialize(). Thus, your meta value looks like this in the database:

a:3:{i:0;s:9:"1 | 1 | 1";i:1;s:15:"1.5 | 1.5 | 1.5";i:2;s:12:"22 | 22 | 22";}

There is no built-in way to query within these serialized strings, but since these are strings with a consistent structure, one could consider using regular expressions in a meta query:

/**
 * Gets a regular expression for matching pricing info.
 *
 * @param {int}        $index Which pricing info value to lookup.
 * @param {string|int} $value The match against.
 * @return {string} A regular expression string to match for the pricing info
 *                  index and value.
 */
function get_regexp( $index, $value ) {
  return 'i:' . $index . ';s:\d+:"(|[^"]+\| )' . $value . '("| \|)';
}

$query = new WP_Query(
  array(
    // …
    'meta_query' => array(
      array(
        'key'     => 'pricing_info',
        'compare' => 'REGEXP',
        'value'   => get_regexp( 0, $_POST['var1'] ),
      ),
      array(
        'key'     => 'pricing_info',
        'compare' => 'REGEXP',
        'value'   => get_regexp( 1, $_POST['var2'] ),
      ),
      array(
        'key'     => 'pricing_info',
        'compare' => 'REGEXP',
        'value'   => get_regexp( 2, $_POST['var3'] ),
      ),
    ),
  ),
);

For example, where $index = 0 and $value = 1, the regular expression could be

i:0;s:\d+"(|[^"]+\| )1("| \|)

Which means:

  • i:0;s: matches the start of a serialized numerical array entry literally. The 0 is the array key.
  • \d+ matches one or more digits. This matches the s:9, s:15, etc. of the prefix before the array value.
  • " matches literal " character for the start of the array value.
  • (|[^"]+\| ) is a grouping with two distinct possibilities, separated by | (not to be confused with your syntax that also uses |):
    • Left side, (|, is asserting to match nothing. This is the case one when the value could be the first one in the list, i.e. s:9:"1.
    • Right side, |[^"]+\| ):
      • [^"]+ matches one or more characters as possible that are not the " character. This ensures we match only within the given array value string.
      • \| matches the pipe symbol | and then a single space literally. This ensures we are anchoring the regular expression match from the start of a number value, and not in the middle. For example, this partly ensures when 1 is passed in, we match 1 but not 515.
    • 1 matches the value we want to match literally.
    • ("| \|) is a grouping with two distinct possibilities, separated by |. These are needed to ensure we don't partially match a number. For example, this partly ensures when 1 is passed in, we match 1 but not 515
      • Left side, ", matches " literally to assert a match at the end of an array value.
      • Right side, \|, matches a single space and then the pipe symbol | literally.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.