spatie/schema-org

How to create ItemList of Objects?

Closed this issue · 8 comments

Nice work.

But so far I don't understand how to create an ItemList Object that consists of multiple Object-Types? For example Image or VideoObjects?

Is Graph the correct Collection-Type for that or ItemList?
Graph-Object at least seems to nearly produce what I want using "toScript", but some Google Chrome LD-Test extensions seem not to interpretate it correctly.

Looking into Google-Docs, ItemList should be what I'm searching for?
https://developers.google.com/search/docs/advanced/structured-data/video#item-list

I want to avoid having tons of <script type="application/ld+json"> in my markup and have a collection with at least all of the same object-type (f.e. Video, People, Images).

Is that possible with this library?

Hey,

everything you need is there:

schema-org/src/ItemList.php

Lines 116 to 139 in 066463b

/**
* For itemListElement values, you can use simple strings (e.g. "Peter",
* "Paul", "Mary"), existing entities, or use ListItem.
*
* Text values are best if the elements in the list are plain strings.
* Existing entities are best for a simple, unordered list of existing
* things in your data. ListItem is used with ordered lists when you want to
* provide additional context about the element in that list or when the
* same item might be in different places in different lists.
*
* Note: The order of elements in your mark-up is not sufficient for
* indicating the order or elements. Use ListItem with a 'position'
* property in such cases.
*
* @param \Spatie\SchemaOrg\Contracts\ListItemContract|\Spatie\SchemaOrg\Contracts\ListItemContract[]|\Spatie\SchemaOrg\Contracts\ThingContract|\Spatie\SchemaOrg\Contracts\ThingContract[]|string|string[] $itemListElement
*
* @return static
*
* @see https://schema.org/itemListElement
*/
public function itemListElement($itemListElement)
{
return $this->setProperty('itemListElement', $itemListElement);
}

You can define the ItemList and add an array of ListItem or any other Type with the above method.

Thanks. Does it anyway make sense to combine it with Graph or is this any separate declaration?!

I also noticed for VideoObject->duration that there is Type "Duration" is required, but for my surprise some types like Duration do not have the expected properties (like here "setDuration"), but have some kind of default-properties which don't make any sense in this Context (like "Image").

What is the idea behind this? How can I set $videoObject->duration?

I'm currently doing this:
$videoObject->duration(CarbonInterval::seconds($this->duration)->spec());

This at least seems to output what is required compared to JSON-LD specs, but gives syntax warning in PhpStorm, as the declaration expects Duration-Typed Object here.

Regarding the Duration: nothing we can do, schema.org itself doesn't have any more precise info and we also only generate the code from the jsonld standard files (like stated in the README).

The Graph is a way to group several top-level types for one page. So for example if you want to describe the Website and Movie types for a Netflix movie page. You can add both to the Graph and have them all in one script tag.
The graph also allows to cross-reference types - since #155 they are also referenced in the JSON-LD instead of just duplicated.
This allows to use the graph also as some kind of "Container" for all your types and enrich them from different places.
You could bind a Graph as singleton to your framework container and add types and enrich them from different places. In the final view it will render the full graph with all details. So you could add a basic website type for all pages in a middleware, add a Product from your Article-Detail Controller, register but hide your organization as "owner" to allow referencing it in all other types and so on.
So the Graph output is the proper way to go for multiple types on one page - but not required.
And for you as a developer it offers a ton of useful and great features to make your life easier.

Thanks for the help. Then the Graph does what I expected to do.

Regarding types like Duration, at least for VideoObject duration it has some more specific format here:

https://schema.org/Duration
For Duration it is ISO 8601-Format, and looks like string "PT00H30M5S" for a video that has 0 hours, 30 minutes and 5 seconds. For me the Carbon-Library was very handy to handle this (see above).

I think it's kind of improvement, but Duration should only handle the types that make sense. I don't think "default types" inherited from some kind of default object make any sense here (like image, name, ...).

Personally I would make it a class implementing some empty default Type for Types, may be SubType "Duration" and implement some static methods like:

createFromInt(int $seconds)
createFromDateTime(DateTime $dateTime)
createFromCarbon(Carbon $dateTime)
createFromFormat(string $string)

Just as suggestion how I would handle this :-)

I also found some other types with inherited "default" attributes that at least for me don't make sense.

For example "ItemList" also has bunch of methods/attributes that don't make sense (for the final usage) and should be implemented more near to the specifications to reach more intuitive usage:

shows these valid elements/attributes, see https://schema.org/ItemList

{
      "@id": "https://schema.org/Duration",
      "@type": "rdfs:Class",
      "rdfs:comment": "Quantity: Duration (use <a href=\"http://en.wikipedia.org/wiki/ISO_8601\">ISO 8601 duration format</a>).",
      "rdfs:label": "Duration",
      "rdfs:subClassOf": {
        "@id": "https://schema.org/Quantity"
      }
    }
{
      "@id": "https://schema.org/Quantity",
      "@type": "rdfs:Class",
      "rdfs:comment": "Quantities such as distance, time, mass, weight, etc. Particular instances of say Mass are entities like '3 Kg' or '4 milligrams'.",
      "rdfs:label": "Quantity",
      "rdfs:subClassOf": {
        "@id": "https://schema.org/Intangible"
      }
    }
{
      "@id": "https://schema.org/Intangible",
      "@type": "rdfs:Class",
      "rdfs:comment": "A utility class that serves as the umbrella for a number of 'intangible' things such as quantities, structured values, etc.",
      "rdfs:label": "Intangible",
      "rdfs:subClassOf": {
        "@id": "https://schema.org/Thing"
      }
    },
{
      "@id": "https://schema.org/Thing",
      "@type": "rdfs:Class",
      "rdfs:comment": "The most generic type of item.",
      "rdfs:label": "Thing"
    }
{
      "@id": "https://schema.org/duration",
      "@type": "rdf:Property",
      "https://schema.org/category": [
        "issue-1698",
        "issue-1457"
      ],
      "https://schema.org/domainIncludes": [
        {
          "@id": "https://schema.org/Event"
        },
        {
          "@id": "https://schema.org/Schedule"
        },
        {
          "@id": "https://schema.org/Movie"
        },
        {
          "@id": "https://schema.org/MusicRelease"
        },
        {
          "@id": "https://schema.org/MusicRecording"
        },
        {
          "@id": "https://schema.org/MediaObject"
        },
        {
          "@id": "https://schema.org/Audiobook"
        },
        {
          "@id": "https://schema.org/QuantitativeValueDistribution"
        }
      ],
      "https://schema.org/rangeIncludes": {
        "@id": "https://schema.org/Duration"
      },
      "https://schema.org/source": [
        {
          "@id": "https://github.com/schemaorg/schemaorg/issues/1698"
        },
        {
          "@id": "https://github.com/schemaorg/schemaorg/issues/1457"
        }
      ],
      "rdfs:comment": "The duration of the item (movie, audio recording, event, etc.) in <a href=\"http://en.wikipedia.org/wiki/ISO_8601\">ISO 8601 date format</a>.",
      "rdfs:label": "duration"
    }

These are the things we know about the Duration.
As long as we don't start implementing custom assumptions about children of https://schema.org/Quantity or https://schema.org/Intangible or any more precise types there's no way for us to do anything about your mentioned problem.
And this "as long" is a massive no, till now, as we explicitly decided to don't manage or customize the spec on our end but just read, parse and transform the mentioned spec.

And as schema.org doesn't come with any examples regarding the duration property there isn't any reliable resource to build any customizations on.
I'm open for reliable source how this property should look like to see what/how we could do. In case they just want a string there the easiest solution could be to add a union type of string to all properties expecting any sub-type of Quantity.
We already have very few of these mappings for booleans and DateTime for example. But without any reliable proof I'm happier with keeping the current "wrong" way instead of adding a new one. As the current one can be defended with the spec file we use.

Regarding the other types: that's something to discuss with the schema.org spec team. As even your link shows that the ItemList inherits all the attributes of Thing.
Bildschirmfoto 2021-08-25 um 14 59 51

That's what we also do from the spec file and that's also the final result for you as the library user.
We don't proofread the spec for any kind of common sense or whatever but just provide PHP code for what the spec says.

In case you want a higher level of API you can do this your own wrapping this package classes and methods to whatever you need/want/expect.

Okay thanks for the feedback. Well then I simply misunderstood, that google doesn't seem to have the actual final specs in its docs. Never the less I think at the end google will "define" the defacto standard as they seem to practive this already as "defacto standard".

But I understand your standing. May be I'll end up forking this great library implementing the actual google standards. Lets see.

Yes, we already had this discussion some times already. Google doesn't 100% follow the official specs. Sometimes they define their own spec. sometimes they use pending properties and so on.

And since always we stand our ground to only and always follow the official spec in the way it's provided by schema.org
As Google for example doesn't even provide an official Google-Spec we could follow but only would be a collection of adjustments from reported issues which is unmaintainable over time.

I'm open to an adjustment, like said, to fix the Quantity types (like Duration). As I'm sure that it's true that they always should accept a string. But before accepting a PR for it I would need several medium reliable sources stating it or a real source stating that a string is the expected value.
This would at least fix the static analyzer problem. But I won't start with exceptions like Duration accepts a DateTime, Price a Money object and so on. How you format that string is the user's responsibility. I would also keep these, potentially useless, type classes themselves as they are in the spec and provide additional details on what kind of string is expected.