Yoast 11 introduced schema data added by default. If your site already has schema added through your theme then this may break. At the time of writing, the documentation only shows how to extend an existing type (Person), not add a new one. So here I am going to show how to add event data by adding a new piece to the tree.
You can find the existing documentation for extending user details which gives a good overview here.
Hooking into the Graph Pieces
Firstly, I have created a file called yoast-schema.php and included that from the theme's functions.php file (Mine is in a folder called inc).
Within that file, I'm including another which contains my event class Schema_Event.php.
Then there is a filter for wpseo_schema_graph_pieces which we use to extend the existing pieces by adding an instance of the new class.
To add more schema types, I would include more classes and also add them to the pieces array.
The Schema_Event Class
The main difference between my Schema_Event class and the Team_Member class from the example is that I am not extending another class and therefore also need to remove the static parent generate function.
The following is based on the WPSEO_Schema_Person class which their example extends.
Within the is_needed function, I check to see if we are currently on a single page of the custom post type 'event'. We then return true or false accordingly.
If that function returns true, it moves on to the generate function which returns the actual array of schema data.
In my custom post type, I have added a set of custom fields. The first one is a checkbox which the user clicks if they want to add structured markup, which then reveals the other fields. So within the generate function, I'm checking to see if this field returns true using the WP core get_post_meta function and the post ID which is available through the context object $this->context->id.
The post custom fields:
I'm calling another function within generate called build_event_data but the logic within that function would also work directly within the generate function.
Building the Event Schema
Now we know the user has checked the box and filled in the fields we can start putting the data together. At the top of the build_event_data function, I call all of the custom fields to retrieve their values. Since most of them are required, only a couple need to be checked to see if they contain a value (end date and image).
The first part of the data array adds all of the required fields. For the id attribute of the graph, I'm using $this->context->canonical to add the URI of the current page affixed with #event. For the start date I'm converting the ACF date field to the required Y-m-d format (If you were to use a date/time picker then you would use 'Y-m-d\TG:i').
After the required fields, I then check to see if we have an end date or a description and if so I add them on to the array.
For the image, I'm checking to see if the post has a featured image. if it does, I get an array of the image data using the wp_prepare_attachment_for_js function. You could add another custom field for an image if they need to be different, or you could use the featured image as a fallback if no specific image is added.
NOTE: You do not need to json_encode any values when you put them into the data array. All values will be escaped correctly when outputted on the frontend.
And that's it. We return the data array to the generate function which then adds it to the pieces and if all is well and good, the single event posts now have structured event data.