• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ryanhefner / next-meta / de108891-9baf-478f-91b0-2412341022bc

21 Dec 2025 10:33PM UTC coverage: 53.241% (-45.6%) from 98.853%
de108891-9baf-478f-91b0-2412341022bc

Pull #5

circleci

ryanhefner
Add support for Pinterest Domain Verify code
Pull Request #5: v0.4.0

197 of 378 branches covered (52.12%)

Branch coverage included in aggregate %.

187 of 345 new or added lines in 5 files covered. (54.2%)

189 of 347 relevant lines covered (54.47%)

25.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

52.32
/src/renderMeta.tsx
1
import React from 'react'
2
import merge from 'lodash/merge'
3
import type { PageMetaProps, Image, Video, Audio } from './types'
4

5
export const getAbsoluteUrl = (
5✔
6
  url: string | undefined,
7
  baseUrl?: string,
8
): string | undefined => {
9
  if (baseUrl && url && url.indexOf('http') === -1) {
286✔
10
    return `${baseUrl}${url}`
16✔
11
  }
12

13
  return url
270✔
14
}
15

16
const DEFAULTS = {
5✔
17
  siteNameDelimiter: '|',
18
}
19

20
export const renderMeta = (
5✔
21
  props: PageMetaProps = {},
115✔
22
  context: PageMetaProps = {},
115✔
23
): React.ReactNode[] => {
24
  const {
25
    // Audio (array)
26
    audio,
27
    // General
28
    baseUrl,
29
    canonical,
30
    debug,
31
    description,
32
    determiner,
33
    // Image (array)
34
    images,
35
    locale,
36
    localeAlternates,
37
    pinterestDomainVerify,
38
    siteName,
39
    siteNameDelimiter,
40
    title,
41
    twitter,
42
    type,
43
    url,
44
    // Video (array)
45
    videos,
46
    // New general metadata
47
    author,
48
    updatedTime,
49
    seeAlso,
50
    richAttachment,
51
    tag,
52
    section,
53
    publishedTime,
54
    modifiedTime,
55
    releaseDate,
56
    expirationTime,
57
    startTime,
58
    endTime,
59
    // Location
60
    latitude,
61
    longitude,
62
    streetAddress,
63
    locality,
64
    region,
65
    postalCode,
66
    countryName,
67
    // Contact
68
    email,
69
    phoneNumber,
70
    faxNumber,
71
    // Product/Rating
72
    price,
73
    availability,
74
    isbn,
75
    rating,
76
    reviewCount,
77
    points,
78
    restrictions,
79
    ageRating,
80
    contentRating,
81
    // Article-specific
82
    article,
83
    // Book-specific
84
    book,
85
    // Profile-specific
86
    profile,
87
    // Music-specific
88
    music,
89
    // Video-specific (for video.other)
90
    videoOther,
91
  } = merge({}, DEFAULTS, context, props)
115✔
92

93
  const absoluteUrl = getAbsoluteUrl(url, baseUrl)
115✔
94
  const absoluteCanonicalUrl = getAbsoluteUrl(canonical, baseUrl)
115✔
95

96
  const tagsToRender: React.ReactNode[] = []
115✔
97

98
  // canonical
99
  if (absoluteCanonicalUrl) {
115✔
100
    tagsToRender.push(
5✔
101
      <link key="canonical" rel="canonical" href={absoluteCanonicalUrl} />,
102
    )
103
  }
104

105
  // title
106
  if (title) {
115✔
107
    tagsToRender.push(
17✔
108
      <title key="meta-title">{`${title}${
109
        siteName ? ` ${siteNameDelimiter} ${siteName}` : ''
17✔
110
      }`}</title>,
111
      <meta key="meta-og-title" property="og:title" content={title} />,
112
      <meta key="meta-twitter-title" name="twitter:title" content={title} />,
113
    )
114
  }
115

116
  // description
117
  if (description) {
115✔
118
    tagsToRender.push(
10✔
119
      <meta key="meta-description" name="description" content={description} />,
120
      <meta
121
        key="meta-og-description"
122
        property="og:description"
123
        content={description}
124
      />,
125
      <meta
126
        key="meta-twitter-description"
127
        name="twitter:description"
128
        content={description}
129
      />,
130
    )
131
  }
132

133
  // locale
134
  if (locale) {
115✔
135
    tagsToRender.push(
2✔
136
      <meta key="meta-og-locale" property="og:locale" content={locale} />,
137
    )
138
  }
139

140
  // locale alternates
141
  if (localeAlternates && localeAlternates.length) {
115✔
142
    tagsToRender.push(
2✔
143
      ...localeAlternates.map((localeAlternate) => (
144
        <meta
4✔
145
          key={`meta-og-locale-alternate-${localeAlternate}`}
146
          property="og:locale:alternate"
147
          content={localeAlternate}
148
        />
149
      )),
150
    )
151
  }
152

153
  // Pinterest domain verification
154
  if (pinterestDomainVerify) {
115✔
155
    tagsToRender.push(
1✔
156
      <meta
157
        key="meta-pinterest-domain-verify"
158
        name="p:domain_verify"
159
        content={pinterestDomainVerify}
160
      />,
161
    )
162
  }
163

164
  // Collect all images to render
165
  const allImages: Image[] = []
115✔
166

167
  if (images && images.length > 0) {
115✔
168
    allImages.push(...images)
14✔
169
  }
170

171
  // Render images array (Open Graph supports multiple images)
172
  if (allImages.length > 0) {
115✔
173
    allImages.forEach((img, index) => {
14✔
174
      const absoluteImgUrl = getAbsoluteUrl(img.url, baseUrl)
14✔
175
      if (absoluteImgUrl) {
14!
176
        tagsToRender.push(
14✔
177
          <meta
178
            key={`meta-og-image-${index}`}
179
            property="og:image"
180
            content={absoluteImgUrl}
181
          />,
182
        )
183

184
        // For Twitter, only use the first image
185
        if (index === 0) {
14!
186
          tagsToRender.push(
14✔
187
            <meta
188
              key="meta-twitter-image"
189
              name="twitter:image"
190
              content={absoluteImgUrl}
191
            />,
192
          )
193
        }
194

195
        // imageAlt
196
        if (img.alt) {
14✔
197
          tagsToRender.push(
3✔
198
            <meta
199
              key={`meta-og-image-alt-${index}`}
200
              property="og:image:alt"
201
              content={img.alt}
202
            />,
203
          )
204
          if (index === 0) {
3!
205
            tagsToRender.push(
3✔
206
              <meta
207
                key="meta-twitter-image-alt"
208
                name="twitter:image:alt"
209
                content={img.alt}
210
              />,
211
            )
212
          }
213
        }
214

215
        // imageWidth
216
        if (img.width !== undefined) {
14✔
217
          tagsToRender.push(
5✔
218
            <meta
219
              key={`meta-og-image-width-${index}`}
220
              property="og:image:width"
221
              content={String(img.width)}
222
            />,
223
          )
224
        }
225

226
        // imageHeight
227
        if (img.height !== undefined) {
14✔
228
          tagsToRender.push(
5✔
229
            <meta
230
              key={`meta-og-image-height-${index}`}
231
              property="og:image:height"
232
              content={String(img.height)}
233
            />,
234
          )
235
        }
236

237
        // imageType
238
        if (img.type) {
14!
NEW
239
          tagsToRender.push(
×
240
            <meta
241
              key={`meta-og-image-type-${index}`}
242
              property="og:image:type"
243
              content={img.type}
244
            />,
245
          )
246
        }
247
      }
248
    })
249
  }
250

251
  // determiner
252
  if (determiner) {
115✔
253
    tagsToRender.push(
2✔
254
      <meta
255
        key="meta-og-determiner"
256
        property="og:determiner"
257
        content={determiner}
258
      />,
259
    )
260
  }
261

262
  // siteName
263
  if (siteName) {
115✔
264
    tagsToRender.push(
8✔
265
      <meta
266
        key="meta-og-site-name"
267
        property="og:site_name"
268
        content={siteName}
269
      />,
270
    )
271
  }
272

273
  // Collect all videos to render
274
  const allVideos: Video[] = []
115✔
275

276
  if (videos && videos.length > 0) {
115✔
277
    allVideos.push(...videos)
9✔
278
  }
279

280
  // Render videos array (Open Graph supports multiple videos)
281
  if (allVideos.length > 0) {
115✔
282
    allVideos.forEach((vid, index) => {
9✔
283
      const absoluteVidUrl = getAbsoluteUrl(vid.url, baseUrl)
9✔
284
      if (absoluteVidUrl) {
9!
285
        tagsToRender.push(
9✔
286
          <meta
287
            key={`meta-og-video-${index}`}
288
            property="og:video"
289
            content={absoluteVidUrl}
290
          />,
291
        )
292

293
        // video secure_url
294
        const absoluteSecureUrl = getAbsoluteUrl(vid.secureUrl, baseUrl)
9✔
295
        if (absoluteSecureUrl || absoluteVidUrl.startsWith('https://')) {
9✔
296
          tagsToRender.push(
5✔
297
            <meta
298
              key={`meta-og-video-secure-url-${index}`}
299
              property="og:video:secure_url"
300
              content={absoluteSecureUrl || absoluteVidUrl}
10✔
301
            />,
302
          )
303
        }
304

305
        // videoType
306
        if (vid.type) {
9✔
307
          tagsToRender.push(
2✔
308
            <meta
309
              key={`meta-og-video-type-${index}`}
310
              property="og:video:type"
311
              content={vid.type}
312
            />,
313
          )
314
        }
315

316
        // videoWidth
317
        if (vid.width !== undefined) {
9!
NEW
318
          tagsToRender.push(
×
319
            <meta
320
              key={`meta-og-video-width-${index}`}
321
              property="og:video:width"
322
              content={String(vid.width)}
323
            />,
324
          )
325
        }
326

327
        // videoHeight
328
        if (vid.height !== undefined) {
9!
NEW
329
          tagsToRender.push(
×
330
            <meta
331
              key={`meta-og-video-height-${index}`}
332
              property="og:video:height"
333
              content={String(vid.height)}
334
            />,
335
          )
336
        }
337

338
        // videoDuration
339
        if (vid.duration !== undefined) {
9!
NEW
340
          tagsToRender.push(
×
341
            <meta
342
              key={`meta-og-video-duration-${index}`}
343
              property="og:video:duration"
344
              content={String(vid.duration)}
345
            />,
346
          )
347
        }
348

349
        // videoActor
350
        if (vid.actor && vid.actor.length > 0) {
9!
NEW
351
          vid.actor.forEach((actor, actorIndex) => {
×
NEW
352
            if (actor.name) {
×
NEW
353
              tagsToRender.push(
×
354
                <meta
355
                  key={`meta-og-video-actor-${index}-${actorIndex}`}
356
                  property="og:video:actor"
357
                  content={actor.name}
358
                />,
359
              )
360
            }
NEW
361
            if (actor.role) {
×
NEW
362
              tagsToRender.push(
×
363
                <meta
364
                  key={`meta-og-video-actor-role-${index}-${actorIndex}`}
365
                  property="og:video:actor:role"
366
                  content={actor.role}
367
                />,
368
              )
369
            }
370
          })
371
        }
372

373
        // videoDirector
374
        if (vid.director) {
9!
NEW
375
          const directors = Array.isArray(vid.director)
×
376
            ? vid.director
377
            : [vid.director]
NEW
378
          directors.forEach((director, dirIndex) => {
×
NEW
379
            tagsToRender.push(
×
380
              <meta
381
                key={`meta-og-video-director-${index}-${dirIndex}`}
382
                property="og:video:director"
383
                content={director}
384
              />,
385
            )
386
          })
387
        }
388

389
        // videoWriter
390
        if (vid.writer) {
9!
NEW
391
          const writers = Array.isArray(vid.writer) ? vid.writer : [vid.writer]
×
NEW
392
          writers.forEach((writer, writerIndex) => {
×
NEW
393
            tagsToRender.push(
×
394
              <meta
395
                key={`meta-og-video-writer-${index}-${writerIndex}`}
396
                property="og:video:writer"
397
                content={writer}
398
              />,
399
            )
400
          })
401
        }
402

403
        // videoReleaseDate
404
        if (vid.releaseDate) {
9!
NEW
405
          tagsToRender.push(
×
406
            <meta
407
              key={`meta-og-video-release-date-${index}`}
408
              property="og:video:release_date"
409
              content={vid.releaseDate}
410
            />,
411
          )
412
        }
413

414
        // videoTag
415
        if (vid.tag) {
9!
NEW
416
          const tags = Array.isArray(vid.tag) ? vid.tag : [vid.tag]
×
NEW
417
          tags.forEach((tagValue, tagIndex) => {
×
NEW
418
            tagsToRender.push(
×
419
              <meta
420
                key={`meta-og-video-tag-${index}-${tagIndex}`}
421
                property="og:video:tag"
422
                content={tagValue}
423
              />,
424
            )
425
          })
426
        }
427

428
        // videoSeries
429
        if (vid.series) {
9!
NEW
430
          tagsToRender.push(
×
431
            <meta
432
              key={`meta-og-video-series-${index}`}
433
              property="og:video:series"
434
              content={vid.series}
435
            />,
436
          )
437
        }
438

439
        // videoEpisode
440
        if (vid.episode) {
9!
NEW
441
          if (vid.episode.season !== undefined) {
×
NEW
442
            tagsToRender.push(
×
443
              <meta
444
                key={`meta-og-video-episode-season-${index}`}
445
                property="og:video:episode:season"
446
                content={String(vid.episode.season)}
447
              />,
448
            )
449
          }
NEW
450
          if (vid.episode.number !== undefined) {
×
NEW
451
            tagsToRender.push(
×
452
              <meta
453
                key={`meta-og-video-episode-number-${index}`}
454
                property="og:video:episode:number"
455
                content={String(vid.episode.number)}
456
              />,
457
            )
458
          }
459
        }
460
      }
461
    })
462
  }
463

464
  // Collect all audios to render
465
  const allAudios: Audio[] = []
115✔
466

467
  if (audio && audio.length > 0) {
115✔
468
    allAudios.push(...audio)
10✔
469
  }
470

471
  // Render audio array (Open Graph supports multiple audios)
472
  if (allAudios.length > 0) {
115✔
473
    allAudios.forEach((aud, index) => {
10✔
474
      const absoluteAudUrl = getAbsoluteUrl(aud.url, baseUrl)
10✔
475
      if (absoluteAudUrl) {
10!
476
        tagsToRender.push(
10✔
477
          <meta
478
            key={`meta-og-audio-${index}`}
479
            property="og:audio"
480
            content={absoluteAudUrl}
481
          />,
482
        )
483

484
        // audio secure_url
485
        const absoluteSecureUrl = getAbsoluteUrl(aud.secureUrl, baseUrl)
10✔
486
        if (absoluteSecureUrl || absoluteAudUrl.startsWith('https://')) {
10✔
487
          tagsToRender.push(
6✔
488
            <meta
489
              key={`meta-og-audio-secure-url-${index}`}
490
              property="og:audio:secure_url"
491
              content={absoluteSecureUrl || absoluteAudUrl}
12✔
492
            />,
493
          )
494
        }
495

496
        // audioType
497
        if (aud.type) {
10✔
498
          tagsToRender.push(
3✔
499
            <meta
500
              key={`meta-og-audio-type-${index}`}
501
              property="og:audio:type"
502
              content={aud.type}
503
            />,
504
          )
505
        }
506

507
        // audioDuration
508
        if (aud.duration !== undefined) {
10!
NEW
509
          tagsToRender.push(
×
510
            <meta
511
              key={`meta-og-audio-duration-${index}`}
512
              property="og:audio:duration"
513
              content={String(aud.duration)}
514
            />,
515
          )
516
        }
517

518
        // audioTitle
519
        if (aud.title) {
10!
NEW
520
          tagsToRender.push(
×
521
            <meta
522
              key={`meta-og-audio-title-${index}`}
523
              property="og:audio:title"
524
              content={aud.title}
525
            />,
526
          )
527
        }
528

529
        // audioArtist
530
        if (aud.artist) {
10!
NEW
531
          const artists = Array.isArray(aud.artist) ? aud.artist : [aud.artist]
×
NEW
532
          artists.forEach((artist, artistIndex) => {
×
NEW
533
            tagsToRender.push(
×
534
              <meta
535
                key={`meta-og-audio-artist-${index}-${artistIndex}`}
536
                property="og:audio:artist"
537
                content={artist}
538
              />,
539
            )
540
          })
541
        }
542

543
        // audioAlbum
544
        if (aud.album) {
10!
NEW
545
          tagsToRender.push(
×
546
            <meta
547
              key={`meta-og-audio-album-${index}`}
548
              property="og:audio:album"
549
              content={aud.album}
550
            />,
551
          )
552
        }
553
      }
554
    })
555
  }
556

557
  // Twitter
558
  if (twitter) {
115✔
559
    if (twitter.card) {
42✔
560
      tagsToRender.push(
8✔
561
        <meta
562
          key="meta-twitter-card"
563
          name="twitter:card"
564
          content={twitter.card}
565
        />,
566
      )
567
    }
568

569
    if (twitter.image) {
42✔
570
      tagsToRender.push(
1✔
571
        <meta
572
          key="meta-twitter-image"
573
          name="twitter:image"
574
          content={twitter.image.url || ''}
1!
575
        />,
576
      )
577

578
      if (twitter.image.alt) {
1!
579
        tagsToRender.push(
1✔
580
          <meta
581
            key="meta-twitter-image-alt"
582
            name="twitter:image:alt"
583
            content={twitter.image.alt}
584
          />,
585
        )
586
      }
587

588
      if (twitter.image.width) {
1!
589
        tagsToRender.push(
1✔
590
          <meta
591
            key="meta-twitter-image-width"
592
            name="twitter:image:width"
593
            content={String(twitter.image.width)}
594
          />,
595
        )
596
      }
597

598
      if (twitter.image.height) {
1!
599
        tagsToRender.push(
1✔
600
          <meta
601
            key="meta-twitter-image-height"
602
            name="twitter:image:height"
603
            content={String(twitter.image.height)}
604
          />,
605
        )
606
      }
607
    }
608

609
    if (twitter.site) {
42✔
610
      tagsToRender.push(
4✔
611
        <meta
612
          key="meta-twitter-site"
613
          name="twitter:site"
614
          content={twitter.site}
615
        />,
616
      )
617
    }
618

619
    if (twitter.creator) {
42✔
620
      tagsToRender.push(
6✔
621
        <meta
622
          key="meta-twitter-creator"
623
          name="twitter:creator"
624
          content={twitter.creator}
625
        />,
626
      )
627
    }
628

629
    if (twitter.app) {
42✔
630
      if (twitter.app.country) {
18✔
631
        tagsToRender.push(
2✔
632
          <meta
633
            key="meta-twitter-app-country"
634
            name="twitter:app:country"
635
            content={twitter.app.country}
636
          />,
637
        )
638
      }
639

640
      if (twitter.app.googlePlay) {
18✔
641
        if (twitter.app.googlePlay.name || twitter.app.name) {
6✔
642
          tagsToRender.push(
4✔
643
            <meta
644
              key="meta-twitter-app-name-googleplay"
645
              name="twitter:app:name:googleplay"
646
              content={twitter.app.googlePlay.name ?? twitter.app.name}
6✔
647
            />,
648
          )
649
        }
650

651
        if (twitter.app.googlePlay.id) {
6✔
652
          tagsToRender.push(
4✔
653
            <meta
654
              key="meta-twitter-app-id-googleplay"
655
              name="twitter:app:id:googleplay"
656
              content={twitter.app.googlePlay.id}
657
            />,
658
          )
659
        }
660

661
        if (twitter.app.googlePlay.url) {
6✔
662
          tagsToRender.push(
3✔
663
            <meta
664
              key="meta-twitter-app-url-googleplay"
665
              name="twitter:app:url:googleplay"
666
              content={twitter.app.googlePlay.url}
667
            />,
668
          )
669
        }
670
      }
671

672
      if (twitter.app.iPad) {
18✔
673
        if (twitter.app.iPad.name || twitter.app.name) {
5✔
674
          tagsToRender.push(
3✔
675
            <meta
676
              key="meta-twitter-app-name-ipad"
677
              name="twitter:app:name:ipad"
678
              content={twitter.app.iPad.name ?? twitter.app.name}
4✔
679
            />,
680
          )
681
        }
682

683
        if (twitter.app.iPad.id) {
5✔
684
          tagsToRender.push(
3✔
685
            <meta
686
              key="meta-twitter-app-id-ipad"
687
              name="twitter:app:id:ipad"
688
              content={twitter.app.iPad.id}
689
            />,
690
          )
691
        }
692

693
        if (twitter.app.iPad.url) {
5✔
694
          tagsToRender.push(
2✔
695
            <meta
696
              key="meta-twitter-app-url-ipad"
697
              name="twitter:app:url:ipad"
698
              content={twitter.app.iPad.url}
699
            />,
700
          )
701
        }
702
      }
703

704
      if (twitter.app.iPhone) {
18✔
705
        if (twitter.app.iPhone.name || twitter.app.name) {
5✔
706
          tagsToRender.push(
3✔
707
            <meta
708
              key="meta-twitter-app-name-iphone"
709
              name="twitter:app:name:iphone"
710
              content={twitter.app.iPhone.name ?? twitter.app.name}
4✔
711
            />,
712
          )
713
        }
714

715
        if (twitter.app.iPhone.id) {
5✔
716
          tagsToRender.push(
3✔
717
            <meta
718
              key="meta-twitter-app-id-iphone"
719
              name="twitter:app:id:iphone"
720
              content={twitter.app.iPhone.id}
721
            />,
722
          )
723
        }
724

725
        if (twitter.app.iPhone.url) {
5✔
726
          tagsToRender.push(
2✔
727
            <meta
728
              key="meta-twitter-app-url-iphone"
729
              name="twitter:app:url:iphone"
730
              content={twitter.app.iPhone.url}
731
            />,
732
          )
733
        }
734
      }
735
    }
736

737
    if (twitter.player) {
42✔
738
      if (twitter.player.url) {
9!
739
        tagsToRender.push(
9✔
740
          <meta
741
            key="meta-twitter-player"
742
            name="twitter:player"
743
            content={twitter.player.url}
744
          />,
745
        )
746
      }
747

748
      if (twitter.player.width) {
9✔
749
        tagsToRender.push(
4✔
750
          <meta
751
            key="meta-twitter-player-width"
752
            name="twitter:player:width"
753
            content={twitter.player.width}
754
          />,
755
        )
756
      }
757

758
      if (twitter.player.height) {
9✔
759
        tagsToRender.push(
4✔
760
          <meta
761
            key="meta-twitter-player-height"
762
            name="twitter:player:height"
763
            content={twitter.player.height}
764
          />,
765
        )
766
      }
767

768
      if (twitter.player.stream) {
9✔
769
        if (twitter.player.stream.url) {
4!
770
          tagsToRender.push(
4✔
771
            <meta
772
              key="meta-twitter-player-stream"
773
              name="twitter:player:stream"
774
              content={twitter.player.stream.url}
775
            />,
776
          )
777
        }
778

779
        if (twitter.player.stream.contentType) {
4✔
780
          tagsToRender.push(
3✔
781
            <meta
782
              key="meta-twitter-player-stream-content-type"
783
              name="twitter:player:stream:content_type"
784
              content={twitter.player.stream.contentType}
785
            />,
786
          )
787
        }
788
      }
789
    }
790
  }
791

792
  // type
793
  if (type) {
115✔
794
    tagsToRender.push(
2✔
795
      <meta key="meta-og-type" property="og:type" content={type} />,
796
    )
797
  }
798

799
  // url
800
  if (absoluteUrl) {
115✔
801
    tagsToRender.push(
8✔
802
      <meta key="meta-og-url" property="og:url" content={absoluteUrl} />,
803
    )
804
  }
805

806
  // General metadata
807
  if (author) {
115!
NEW
808
    const authors = Array.isArray(author) ? author : [author]
×
NEW
809
    authors.forEach((auth, authIndex) => {
×
NEW
810
      tagsToRender.push(
×
811
        <meta
812
          key={`meta-og-author-${authIndex}`}
813
          property="og:author"
814
          content={auth}
815
        />,
816
      )
817
    })
818
  }
819

820
  if (updatedTime) {
115!
NEW
821
    tagsToRender.push(
×
822
      <meta
823
        key="meta-og-updated-time"
824
        property="og:updated_time"
825
        content={updatedTime}
826
      />,
827
    )
828
  }
829

830
  if (seeAlso) {
115!
NEW
831
    const seeAlsoList = Array.isArray(seeAlso) ? seeAlso : [seeAlso]
×
NEW
832
    seeAlsoList.forEach((seeAlsoItem, seeAlsoIndex) => {
×
NEW
833
      tagsToRender.push(
×
834
        <meta
835
          key={`meta-og-see-also-${seeAlsoIndex}`}
836
          property="og:see_also"
837
          content={seeAlsoItem}
838
        />,
839
      )
840
    })
841
  }
842

843
  if (richAttachment !== undefined) {
115!
NEW
844
    tagsToRender.push(
×
845
      <meta
846
        key="meta-og-rich-attachment"
847
        property="og:rich_attachment"
848
        content={richAttachment ? 'true' : 'false'}
×
849
      />,
850
    )
851
  }
852

853
  if (tag) {
115!
NEW
854
    const tags = Array.isArray(tag) ? tag : [tag]
×
NEW
855
    tags.forEach((tagValue, tagIndex) => {
×
NEW
856
      tagsToRender.push(
×
857
        <meta
858
          key={`meta-og-tag-${tagIndex}`}
859
          property="og:tag"
860
          content={tagValue}
861
        />,
862
      )
863
    })
864
  }
865

866
  if (section) {
115!
NEW
867
    tagsToRender.push(
×
868
      <meta key="meta-og-section" property="og:section" content={section} />,
869
    )
870
  }
871

872
  if (publishedTime) {
115!
NEW
873
    tagsToRender.push(
×
874
      <meta
875
        key="meta-og-published-time"
876
        property="og:published_time"
877
        content={publishedTime}
878
      />,
879
    )
880
  }
881

882
  if (modifiedTime) {
115!
NEW
883
    tagsToRender.push(
×
884
      <meta
885
        key="meta-og-modified-time"
886
        property="og:modified_time"
887
        content={modifiedTime}
888
      />,
889
    )
890
  }
891

892
  if (releaseDate) {
115!
NEW
893
    tagsToRender.push(
×
894
      <meta
895
        key="meta-og-release-date"
896
        property="og:release_date"
897
        content={releaseDate}
898
      />,
899
    )
900
  }
901

902
  if (expirationTime) {
115!
NEW
903
    tagsToRender.push(
×
904
      <meta
905
        key="meta-og-expiration-time"
906
        property="og:expiration_time"
907
        content={expirationTime}
908
      />,
909
    )
910
  }
911

912
  if (startTime) {
115!
NEW
913
    tagsToRender.push(
×
914
      <meta
915
        key="meta-og-start-time"
916
        property="og:start_time"
917
        content={startTime}
918
      />,
919
    )
920
  }
921

922
  if (endTime) {
115!
NEW
923
    tagsToRender.push(
×
924
      <meta key="meta-og-end-time" property="og:end_time" content={endTime} />,
925
    )
926
  }
927

928
  // Location
929
  if (latitude !== undefined) {
115!
NEW
930
    tagsToRender.push(
×
931
      <meta
932
        key="meta-og-latitude"
933
        property="og:latitude"
934
        content={String(latitude)}
935
      />,
936
    )
937
  }
938

939
  if (longitude !== undefined) {
115!
NEW
940
    tagsToRender.push(
×
941
      <meta
942
        key="meta-og-longitude"
943
        property="og:longitude"
944
        content={String(longitude)}
945
      />,
946
    )
947
  }
948

949
  if (streetAddress) {
115!
NEW
950
    tagsToRender.push(
×
951
      <meta
952
        key="meta-og-street-address"
953
        property="og:street_address"
954
        content={streetAddress}
955
      />,
956
    )
957
  }
958

959
  if (locality) {
115!
NEW
960
    tagsToRender.push(
×
961
      <meta key="meta-og-locality" property="og:locality" content={locality} />,
962
    )
963
  }
964

965
  if (region) {
115!
NEW
966
    tagsToRender.push(
×
967
      <meta key="meta-og-region" property="og:region" content={region} />,
968
    )
969
  }
970

971
  if (postalCode) {
115!
NEW
972
    tagsToRender.push(
×
973
      <meta
974
        key="meta-og-postal-code"
975
        property="og:postal_code"
976
        content={postalCode}
977
      />,
978
    )
979
  }
980

981
  if (countryName) {
115!
NEW
982
    tagsToRender.push(
×
983
      <meta
984
        key="meta-og-country-name"
985
        property="og:country_name"
986
        content={countryName}
987
      />,
988
    )
989
  }
990

991
  // Contact
992
  if (email) {
115!
NEW
993
    tagsToRender.push(
×
994
      <meta key="meta-og-email" property="og:email" content={email} />,
995
    )
996
  }
997

998
  if (phoneNumber) {
115!
NEW
999
    tagsToRender.push(
×
1000
      <meta
1001
        key="meta-og-phone-number"
1002
        property="og:phone_number"
1003
        content={phoneNumber}
1004
      />,
1005
    )
1006
  }
1007

1008
  if (faxNumber) {
115!
NEW
1009
    tagsToRender.push(
×
1010
      <meta
1011
        key="meta-og-fax-number"
1012
        property="og:fax_number"
1013
        content={faxNumber}
1014
      />,
1015
    )
1016
  }
1017

1018
  // Product/Rating
1019
  if (price !== undefined) {
115!
NEW
1020
    tagsToRender.push(
×
1021
      <meta key="meta-og-price" property="og:price" content={String(price)} />,
1022
    )
1023
  }
1024

1025
  if (availability) {
115!
NEW
1026
    tagsToRender.push(
×
1027
      <meta
1028
        key="meta-og-availability"
1029
        property="og:availability"
1030
        content={availability}
1031
      />,
1032
    )
1033
  }
1034

1035
  if (isbn) {
115!
NEW
1036
    tagsToRender.push(
×
1037
      <meta key="meta-og-isbn" property="og:isbn" content={isbn} />,
1038
    )
1039
  }
1040

1041
  if (rating) {
115!
NEW
1042
    if (rating.value !== undefined) {
×
NEW
1043
      tagsToRender.push(
×
1044
        <meta
1045
          key="meta-og-rating"
1046
          property="og:rating"
1047
          content={String(rating.value)}
1048
        />,
1049
      )
1050
    }
1051

NEW
1052
    if (rating.scale !== undefined) {
×
NEW
1053
      tagsToRender.push(
×
1054
        <meta
1055
          key="meta-og-rating-scale"
1056
          property="og:rating:scale"
1057
          content={String(rating.scale)}
1058
        />,
1059
      )
1060
    }
1061

NEW
1062
    if (rating.count !== undefined) {
×
NEW
1063
      tagsToRender.push(
×
1064
        <meta
1065
          key="meta-og-rating-count"
1066
          property="og:rating:count"
1067
          content={String(rating.count)}
1068
        />,
1069
      )
1070
    }
1071
  }
1072

1073
  if (reviewCount !== undefined) {
115!
NEW
1074
    tagsToRender.push(
×
1075
      <meta
1076
        key="meta-og-review-count"
1077
        property="og:review_count"
1078
        content={String(reviewCount)}
1079
      />,
1080
    )
1081
  }
1082

1083
  if (points !== undefined) {
115!
NEW
1084
    tagsToRender.push(
×
1085
      <meta
1086
        key="meta-og-points"
1087
        property="og:points"
1088
        content={String(points)}
1089
      />,
1090
    )
1091
  }
1092

1093
  if (restrictions) {
115!
NEW
1094
    const restrictionsList = Array.isArray(restrictions)
×
1095
      ? restrictions
1096
      : [restrictions]
NEW
1097
    restrictionsList.forEach((restriction, restrictionIndex) => {
×
NEW
1098
      tagsToRender.push(
×
1099
        <meta
1100
          key={`meta-og-restrictions-${restrictionIndex}`}
1101
          property="og:restrictions"
1102
          content={restriction}
1103
        />,
1104
      )
1105
    })
1106
  }
1107

1108
  if (ageRating) {
115!
NEW
1109
    tagsToRender.push(
×
1110
      <meta
1111
        key="meta-og-age-rating"
1112
        property="og:age_rating"
1113
        content={ageRating}
1114
      />,
1115
    )
1116
  }
1117

1118
  if (contentRating) {
115!
NEW
1119
    tagsToRender.push(
×
1120
      <meta
1121
        key="meta-og-content-rating"
1122
        property="og:content_rating"
1123
        content={contentRating}
1124
      />,
1125
    )
1126
  }
1127

1128
  // Article-specific
1129
  if (article) {
115!
NEW
1130
    if (article.author) {
×
NEW
1131
      const authors = Array.isArray(article.author)
×
1132
        ? article.author
1133
        : [article.author]
NEW
1134
      authors.forEach((auth, authIndex) => {
×
NEW
1135
        tagsToRender.push(
×
1136
          <meta
1137
            key={`meta-og-article-author-${authIndex}`}
1138
            property="og:article:author"
1139
            content={auth}
1140
          />,
1141
        )
1142
      })
1143
    }
1144

NEW
1145
    if (article.publishedTime) {
×
NEW
1146
      tagsToRender.push(
×
1147
        <meta
1148
          key="meta-og-article-published-time"
1149
          property="og:article:published_time"
1150
          content={article.publishedTime}
1151
        />,
1152
      )
1153
    }
1154

NEW
1155
    if (article.modifiedTime) {
×
NEW
1156
      tagsToRender.push(
×
1157
        <meta
1158
          key="meta-og-article-modified-time"
1159
          property="og:article:modified_time"
1160
          content={article.modifiedTime}
1161
        />,
1162
      )
1163
    }
1164

NEW
1165
    if (article.expirationTime) {
×
NEW
1166
      tagsToRender.push(
×
1167
        <meta
1168
          key="meta-og-article-expiration-time"
1169
          property="og:article:expiration_time"
1170
          content={article.expirationTime}
1171
        />,
1172
      )
1173
    }
1174

NEW
1175
    if (article.section) {
×
NEW
1176
      tagsToRender.push(
×
1177
        <meta
1178
          key="meta-og-article-section"
1179
          property="og:article:section"
1180
          content={article.section}
1181
        />,
1182
      )
1183
    }
1184

NEW
1185
    if (article.tag) {
×
NEW
1186
      const tags = Array.isArray(article.tag) ? article.tag : [article.tag]
×
NEW
1187
      tags.forEach((tagValue, tagIndex) => {
×
NEW
1188
        tagsToRender.push(
×
1189
          <meta
1190
            key={`meta-og-article-tag-${tagIndex}`}
1191
            property="og:article:tag"
1192
            content={tagValue}
1193
          />,
1194
        )
1195
      })
1196
    }
1197
  }
1198

1199
  // Book-specific
1200
  if (book) {
115!
NEW
1201
    if (book.author) {
×
NEW
1202
      const authors = Array.isArray(book.author) ? book.author : [book.author]
×
NEW
1203
      authors.forEach((auth, authIndex) => {
×
NEW
1204
        tagsToRender.push(
×
1205
          <meta
1206
            key={`meta-og-book-author-${authIndex}`}
1207
            property="og:book:author"
1208
            content={auth}
1209
          />,
1210
        )
1211
      })
1212
    }
1213

NEW
1214
    if (book.isbn) {
×
NEW
1215
      tagsToRender.push(
×
1216
        <meta
1217
          key="meta-og-book-isbn"
1218
          property="og:book:isbn"
1219
          content={book.isbn}
1220
        />,
1221
      )
1222
    }
1223

NEW
1224
    if (book.releaseDate) {
×
NEW
1225
      tagsToRender.push(
×
1226
        <meta
1227
          key="meta-og-book-release-date"
1228
          property="og:book:release_date"
1229
          content={book.releaseDate}
1230
        />,
1231
      )
1232
    }
1233

NEW
1234
    if (book.tag) {
×
NEW
1235
      const tags = Array.isArray(book.tag) ? book.tag : [book.tag]
×
NEW
1236
      tags.forEach((tagValue, tagIndex) => {
×
NEW
1237
        tagsToRender.push(
×
1238
          <meta
1239
            key={`meta-og-book-tag-${tagIndex}`}
1240
            property="og:book:tag"
1241
            content={tagValue}
1242
          />,
1243
        )
1244
      })
1245
    }
1246
  }
1247

1248
  // Profile-specific
1249
  if (profile) {
115!
NEW
1250
    if (profile.firstName) {
×
NEW
1251
      tagsToRender.push(
×
1252
        <meta
1253
          key="meta-og-profile-first-name"
1254
          property="og:profile:first_name"
1255
          content={profile.firstName}
1256
        />,
1257
      )
1258
    }
1259

NEW
1260
    if (profile.lastName) {
×
NEW
1261
      tagsToRender.push(
×
1262
        <meta
1263
          key="meta-og-profile-last-name"
1264
          property="og:profile:last_name"
1265
          content={profile.lastName}
1266
        />,
1267
      )
1268
    }
1269

NEW
1270
    if (profile.username) {
×
NEW
1271
      tagsToRender.push(
×
1272
        <meta
1273
          key="meta-og-profile-username"
1274
          property="og:profile:username"
1275
          content={profile.username}
1276
        />,
1277
      )
1278
    }
1279

NEW
1280
    if (profile.gender) {
×
NEW
1281
      tagsToRender.push(
×
1282
        <meta
1283
          key="meta-og-profile-gender"
1284
          property="og:profile:gender"
1285
          content={profile.gender}
1286
        />,
1287
      )
1288
    }
1289
  }
1290

1291
  // Music-specific
1292
  if (music) {
115!
NEW
1293
    if (music.duration !== undefined) {
×
NEW
1294
      tagsToRender.push(
×
1295
        <meta
1296
          key="meta-og-music-duration"
1297
          property="og:music:duration"
1298
          content={String(music.duration)}
1299
        />,
1300
      )
1301
    }
1302

NEW
1303
    if (typeof music.album === 'string') {
×
NEW
1304
      tagsToRender.push(
×
1305
        <meta
1306
          key="meta-og-music-album"
1307
          property="og:music:album"
1308
          content={music.album}
1309
        />,
1310
      )
NEW
1311
    } else if (music.album) {
×
NEW
1312
      if (music.album.disc !== undefined) {
×
NEW
1313
        tagsToRender.push(
×
1314
          <meta
1315
            key="meta-og-music-album-disc"
1316
            property="og:music:album:disc"
1317
            content={String(music.album.disc)}
1318
          />,
1319
        )
1320
      }
1321

NEW
1322
      if (music.album.track !== undefined) {
×
NEW
1323
        tagsToRender.push(
×
1324
          <meta
1325
            key="meta-og-music-album-track"
1326
            property="og:music:album:track"
1327
            content={String(music.album.track)}
1328
          />,
1329
        )
1330
      }
1331
    }
1332

NEW
1333
    if (music.musician) {
×
NEW
1334
      const musicians = Array.isArray(music.musician)
×
1335
        ? music.musician
1336
        : [music.musician]
NEW
1337
      musicians.forEach((musician, musicianIndex) => {
×
NEW
1338
        tagsToRender.push(
×
1339
          <meta
1340
            key={`meta-og-music-musician-${musicianIndex}`}
1341
            property="og:music:musician"
1342
            content={musician}
1343
          />,
1344
        )
1345
      })
1346
    }
1347

NEW
1348
    if (music.releaseDate) {
×
NEW
1349
      tagsToRender.push(
×
1350
        <meta
1351
          key="meta-og-music-release-date"
1352
          property="og:music:release_date"
1353
          content={music.releaseDate}
1354
        />,
1355
      )
1356
    }
1357
  }
1358

1359
  // Video-specific (for video.other)
1360
  if (videoOther) {
115!
NEW
1361
    if (videoOther.url) {
×
NEW
1362
      const absoluteOtherUrl = getAbsoluteUrl(videoOther.url, baseUrl)
×
NEW
1363
      if (absoluteOtherUrl) {
×
NEW
1364
        tagsToRender.push(
×
1365
          <meta
1366
            key="meta-og-video-other"
1367
            property="og:video:other"
1368
            content={absoluteOtherUrl}
1369
          />,
1370
        )
1371
      }
1372
    }
1373

NEW
1374
    if (videoOther.secureUrl) {
×
NEW
1375
      const absoluteSecureUrl = getAbsoluteUrl(videoOther.secureUrl, baseUrl)
×
NEW
1376
      if (absoluteSecureUrl) {
×
NEW
1377
        tagsToRender.push(
×
1378
          <meta
1379
            key="meta-og-video-other-secure-url"
1380
            property="og:video:other:secure_url"
1381
            content={absoluteSecureUrl}
1382
          />,
1383
        )
1384
      }
1385
    }
1386

NEW
1387
    if (videoOther.type) {
×
NEW
1388
      tagsToRender.push(
×
1389
        <meta
1390
          key="meta-og-video-other-type"
1391
          property="og:video:other:type"
1392
          content={videoOther.type}
1393
        />,
1394
      )
1395
    }
1396

NEW
1397
    if (videoOther.width !== undefined) {
×
NEW
1398
      tagsToRender.push(
×
1399
        <meta
1400
          key="meta-og-video-other-width"
1401
          property="og:video:other:width"
1402
          content={String(videoOther.width)}
1403
        />,
1404
      )
1405
    }
1406

NEW
1407
    if (videoOther.height !== undefined) {
×
NEW
1408
      tagsToRender.push(
×
1409
        <meta
1410
          key="meta-og-video-other-height"
1411
          property="og:video:other:height"
1412
          content={String(videoOther.height)}
1413
        />,
1414
      )
1415
    }
1416

NEW
1417
    if (videoOther.duration !== undefined) {
×
NEW
1418
      tagsToRender.push(
×
1419
        <meta
1420
          key="meta-og-video-other-duration"
1421
          property="og:video:other:duration"
1422
          content={String(videoOther.duration)}
1423
        />,
1424
      )
1425
    }
1426

NEW
1427
    if (videoOther.stream) {
×
NEW
1428
      if (videoOther.stream.url) {
×
NEW
1429
        const absoluteStreamUrl = getAbsoluteUrl(videoOther.stream.url, baseUrl)
×
NEW
1430
        if (absoluteStreamUrl) {
×
NEW
1431
          tagsToRender.push(
×
1432
            <meta
1433
              key="meta-og-video-other-stream"
1434
              property="og:video:other:stream"
1435
              content={absoluteStreamUrl}
1436
            />,
1437
          )
1438
        }
1439
      }
1440

NEW
1441
      if (videoOther.stream.contentType) {
×
NEW
1442
        tagsToRender.push(
×
1443
          <meta
1444
            key="meta-og-video-other-stream-content-type"
1445
            property="og:video:other:stream:content_type"
1446
            content={videoOther.stream.contentType}
1447
          />,
1448
        )
1449
      }
1450

NEW
1451
      if (videoOther.stream.width !== undefined) {
×
NEW
1452
        tagsToRender.push(
×
1453
          <meta
1454
            key="meta-og-video-other-stream-width"
1455
            property="og:video:other:stream:width"
1456
            content={String(videoOther.stream.width)}
1457
          />,
1458
        )
1459
      }
1460

NEW
1461
      if (videoOther.stream.height !== undefined) {
×
NEW
1462
        tagsToRender.push(
×
1463
          <meta
1464
            key="meta-og-video-other-stream-height"
1465
            property="og:video:other:stream:height"
1466
            content={String(videoOther.stream.height)}
1467
          />,
1468
        )
1469
      }
1470

NEW
1471
      if (videoOther.stream.duration !== undefined) {
×
NEW
1472
        tagsToRender.push(
×
1473
          <meta
1474
            key="meta-og-video-other-stream-duration"
1475
            property="og:video:other:stream:duration"
1476
            content={String(videoOther.stream.duration)}
1477
          />,
1478
        )
1479
      }
1480

NEW
1481
      if (videoOther.stream.secureUrl) {
×
NEW
1482
        const absoluteStreamSecureUrl = getAbsoluteUrl(
×
1483
          videoOther.stream.secureUrl,
1484
          baseUrl,
1485
        )
NEW
1486
        if (absoluteStreamSecureUrl) {
×
NEW
1487
          tagsToRender.push(
×
1488
            <meta
1489
              key="meta-og-video-other-stream-secure-url"
1490
              property="og:video:other:stream:secure_url"
1491
              content={absoluteStreamSecureUrl}
1492
            />,
1493
          )
1494
        }
1495
      }
1496
    }
1497
  }
1498

1499
  return tagsToRender
115✔
1500
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc