0

I have meta data to custom post "event", registered as non-single, i.e., there is an array od metadata "terms" (it is not WordPress term, I just call it term, it is a record containing start date of the event, end date of event and possibly start and end time of the event.

register_meta(
    'post',
    'term_definition',
    [
        'object_subtype' => 'event',
        'type' => 'object',
        'description' => 'object with time data of the event',
        'single' => false,
        'auth_callback' => __NAMESPACE__ . '\authentication',
        'sanitize_callback' => 'sanitization',
        'show_in_rest' => [
            'schema' => [
                'type' => 'object',
                'properties' => [
                    'ID' => [
                        'type' => 'integer'
                    ],
                    'startDate' => [
                        'type' => 'string'
                    ],
                    'endDate' => [
                        'type' => 'string'
                    ],
                    'startTime' => [
                        'type' => 'string'
                    ],
                    'endTime' => [
                        'type' => 'string'
                    ],
                ]
            ]
        ]
    ]
)

I want to get all posts of my custom type event, where startDate in metadata is after current datetime (or before current datetime). From documentation, it seems this is only possible for single, simple metadata, as described in the handbook. As a sidenote, I noticed that metadata created in this way get serialized and stored in the database like so:

meta_key: 'term_definition'
meta_value: a:3:{s:9:"startDate";s:19:"2021-12-09T16:36:00";s:2:"ID";i:0;s:7:"endDate";s:19:"2021-12-10T16:36:00";}
1
  • 4
    Your reading of the documentation is correct. As I see it you have two possibilities: 1 instead of storing an array, store each of them (or at least the ones you need for search) as single values. 2 write some crazy DB query. I would prefer option 1 by far.
    – kero
    Commented Dec 2, 2021 at 16:42

1 Answer 1

0

You are correct, this is not possible for serialised data. There are some hacks to try and get around this by searching for individual parts of the serialised string, but those throw up lots of false positives and can't be sorted.

Generally, it's an anti-pattern to store structured data inside a single meta value, and you can't query the internal data in a meta_query field. If you absolutely must store it, store it as JSON, but keep in mind you can't query or perform logic on the contents. ( serialised PHP values also open you up to object deserialisation attacks, and break when naive search replace queries are ran on the database if the length changes )

The solution here is to separate it out into individual atomic post meta, at least 5, do the sorting in PHP/JS,or to create child post types to represent your events so that you can use the standard date time columns

7
  • I find neither of these solutions good for my case. I can have several or more events of this type. Therefore, data is represented as Array. So I would have to develop a "mini framework" to do CRUD operations on these data. Adding another nested post type is too complicated solution for the customer. I am trying with keeping part of this data as it is in meta values and part which I need for retreiving posts in another custom table and do a custom SQL query.
    – Lovor
    Commented Dec 6, 2021 at 12:41
  • And I wouldn't agree that it is "an anti-pattern to store structured data inside a single meta value", since developers of WordPress did just that. When registering meta field, 'single' => false was added for a reason, which means that was intended this way. I cannot find it in documentation, but I think this is actually even default value.
    – Lovor
    Commented Dec 6, 2021 at 12:48
  • 1
    just because other people did it doesn't mean it's good to do, if you want to query data you can't put it inside a string that may or may not contain structured data, the database doesn't support it. It may be different if we were talking about a dedicated column in the JSON format in newer database versions. Otherwise early WP used the maybe serialise functions to make development easier for users who are new, that doesn't mean it's a best practice. And just because it's bad practice doesn't mean it'll be removed as that would break a lot of things
    – Tom J Nowell
    Commented Dec 6, 2021 at 15:22
  • 1
    Also, your issues with retrieving this in another query were neither mentioned nor are they insurmountable. If you have requirements in your question you need to list them. If the question you have and the question you asked are not the same then that needs to be fixed ASAP, I can only answer the question you wrote.
    – Tom J Nowell
    Commented Dec 6, 2021 at 15:23
  • 1
    here's some general info on deserialisation attacks: owasp.org/www-community/vulnerabilities/…, JSON doesn't suffer from this as you can't instantiate classes with it though it's not perfect either. If you want to stored serialised data in post meta that's fine, but you can't query by it. Strings are just strings at the end of the day, the database is unaware of any internal structure and WP_Query and SQL aren't built to parse it out without taking advantage of dedicated DB features
    – Tom J Nowell
    Commented Dec 6, 2021 at 15:26

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.