Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@id on BreadcrumbList #59

Closed
floflock opened this issue Jun 16, 2018 · 10 comments
Closed

@id on BreadcrumbList #59

floflock opened this issue Jun 16, 2018 · 10 comments

Comments

@floflock
Copy link

Hi!

Great package!
I've found one thing to consider. If you want to build a BreadcrumbList schema, it's not valid by Google because they want a @id parameter in the ListItem.

See: https://developers.google.com/search/docs/data-types/breadcrumb

<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "item": {
      "@id": "https://example.com/books",
      "name": "Books",
      "image": "http://example.com/images/icon-book.png"
    }
  },{
    "@type": "ListItem",
    "position": 2,
    "item": {
      "@id": "https://example.com/books/authors",
      "name": "Authors",
      "image": "http://example.com/images/icon-author.png"
    }
  },{
    "@type": "ListItem",
    "position": 3,
    "item": {
      "@id": "https://example.com/books/authors/annleckie",
      "name": "Ann Leckie",
      "image": "http://example.com/images/author-leckie-ann.png"
    }
  },{
    "@type": "ListItem",
    "position": 4,
    "item": {
      "@id": "https://example.com/books/authors/ancillaryjustice",
      "name": "Ancillary Justice",
      "image": "http://example.com/images/cover-ancillary-justice.png"
    }
  }]
}
</script>

I did not want to create a PR, because I do not exactly where this @id element should be assigned. It's not documented in schema.org, I think.

Possible solution is to add a method on Thing.php:

    /**
     * id parameter for BreadcrumbList for example
     *
     * @param string $id
     *
     * @return static
     */
    public function id($id)
    {
        return $this->setProperty('@id', $id);
    }

Other solution is to create a new schema class BreadcrumbListItem::class and put the @id property in there with extension of ListItem::class

Looking forward to your answer and happy coding! 👍

@Gummibeer
Copy link
Collaborator

Following schema.org itself this is done by https://schema.org/identifier this is already available in Thing

schema-org/src/Thing.php

Lines 76 to 92 in ea9dc67

/**
* The identifier property represents any kind of identifier for any kind of
* [[Thing]], such as ISBNs, GTIN codes, UUIDs etc. Schema.org provides
* dedicated properties for representing many of these, either as textual
* strings or as URL (URI) links. See [background
* notes](/docs/datamodel.html#identifierBg) for more details.
*
* @param PropertyValue|PropertyValue[]|string|string[] $identifier
*
* @return static
*
* @see http://schema.org/identifier
*/
public function identifier($identifier)
{
return $this->setProperty('identifier', $identifier);
}

The main problem is that all classes are created in a dynamic way. So to solve this issue it's required to add a method in a hardcoded way. 😕

@floflock
Copy link
Author

floflock commented Jul 9, 2018

@Gummibeer Yes, the problem is the dynamic class structure. However, my solution works fine for me.

@Gummibeer
Copy link
Collaborator

And the most major problem I see is that this is something Google related and not the general schema standard.
As a workaround you can call setPropery like in your wrapper method directly. I bet that this is the way to go if you want fields that aren't part of schema.org itself.

Or you extend the class and use this one in your code.
I'm curious if this is the only Google related special or if they do have more. If they have more it could be an idea to collect them and see how to get these consumer special things into this library. If it's the only one I would say that it's the easiest thing to call setProperty by your own - also to close discussions for every other consumer special thing in an early step.

@spatie-bot
Copy link

Dear contributor,

because this issue seems to be inactive for quite some time now, I've automatically closed it. If you feel this issue deserves some attention from my human colleagues feel free to reopen it.

@eSilverStrike
Copy link

eSilverStrike commented Jan 7, 2019

Hi I have been trying out your package and was trying to figure out breadcrumbs.

Can you give a code example on how to set the @id parameter in each listitem?

Here is the test code I have so far (currently I am using the thing type as a substitute)

use Spatie\SchemaOrg\Schema;

$gl_breadcrumbs = Schema::BreadcrumbList()
    ->itemListElement([
        Schema::ListItem()
            ->position(1)
            ->item(Schema::Thing()
                ->name('Dresses')
            )
        ,
        Schema::ListItem()
            ->position(2)
            ->item(Schema::Thing()
                ->name('Real Dresses')
            )
        ]);

echo $gl_breadcrumbs->toScript(); 

What would be the php code needed to generate the JSON-LD example on
https://schema.org/BreadcrumbList
so I can add the ID "https://example.com/dresses" to position 1 and "https://example.com/dresses/real" to position 2

Thanks

@Gummibeer
Copy link
Collaborator

A simple call to setProperty('@id', 'value') should solve your problem. At the moment there is no specific method to set the ID because of the special-char @.
And the fact that @id isn't part of the original schema definition - it's only part of what Google wants. Like said above schema only knows identifier.

At all this is a tricky question. The code is auto generated by the schema XML - so there is no space/way for custom methods. The only way I see would be a special Google schema XML which adds the method to the breadcrumb-listitem.

@eSilverStrike
Copy link

Based on the conversation above I figured I needed to use setProperty('@id', 'value') but am unsure how to add it to the item parameter and what do I change the Schema::Thing() too so the type is not set for the item and the following is returned:

    <script type="application/ld+json">
    {
     "@context": "http://schema.org",
     "@type": "BreadcrumbList",
     "itemListElement":
     [
      {
       "@type": "ListItem",
       "position": 1,
       "item":
       {
        "@id": "https://example.com/dresses",
        "name": "Dresses"
        }
      },
      {
       "@type": "ListItem",
      "position": 2,
      "item":
       {
         "@id": "https://example.com/dresses/real",
         "name": "Real Dresses"
       }
      }
     ]
    }
    </script>

Could you modify the code in my previous comment for an example?

@Gummibeer
Copy link
Collaborator

Gummibeer commented Jan 8, 2019

@eSilverStrike so far I see google has solved it now by their own:
https://developers.google.com/search/docs/data-types/breadcrumb

{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "name": "Books",
    "item": "https://example.com/books"
  },{
    "@type": "ListItem",
    "position": 2,
    "name": "Authors",
    "item": "https://example.com/books/authors"
  },{
    "@type": "ListItem",
    "position": 3,
    "name": "Ann Leckie",
    "item": "https://example.com/books/authors/annleckie"
  },{
    "@type": "ListItem",
    "position": 4,
    "name": "Ancillary Justice",
    "item": "https://example.com/books/authors/ancillaryjustice"
  }]
}

https://search.google.com/structured-data/testing-tool

They auto-convert the string in item to @id and a @type = Thing.

For you this would be

\Spatie\SchemaOrg\Schema::BreadcrumbList()
    ->itemListElement([
        \Spatie\SchemaOrg\Schema::ListItem()
            ->position(1)
            ->name('Dresses')
            ->item('https://example.com/dresses'),
        \Spatie\SchemaOrg\Schema::ListItem()
            ->position(2)
            ->name('Real Dresses')
            ->item('https://example.com/dresses/real'),
    ])
    ->toScript();

Your IDE will tell you that the value of item() should be of type Thing or Thing[] but got string - you can ignore this.
If you don't want to ignore it just do:

\Spatie\SchemaOrg\Schema::BreadcrumbList()
    ->itemListElement([
        \Spatie\SchemaOrg\Schema::ListItem()
            ->position(1)
            ->name('Dresses')
            ->item(
                \Spatie\SchemaOrg\Schema::Thing()
                    ->setProperty('@id', 'https://example.com/dresses')
            ),
        \Spatie\SchemaOrg\Schema::ListItem()
            ->position(2)
            ->name('Real Dresses')
            ->item(
                \Spatie\SchemaOrg\Schema::Thing()
                    ->setProperty('@id', 'https://example.com/dresses/real')
            ),
    ])
    ->toScript();

This will have the name on the ListItem and not the Thing (following googles example). Just move the name() method to the Thing if you want it there.

Following https://schema.org/ListItem item has to be of type Thing and nothing else. Same for https://schema.org/item but the example doesn't have a @type property.
At all most schema readers are pretty flexible - this package also allows all this flexibility but the type-hints and methods are 100% what's listed in the schema RDFA (state of the last commit which changed the src).

Just to complete the list: if you don't want the @type key just use an array for item().

[
  '@id' => 'https://example.com/dresses',
  'name' => 'Dresses',
]

This will generate exact what is in the example of the schema page.

@eSilverStrike
Copy link

Thanks!

@Gummibeer
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants