{"id":310,"date":"2026-06-26T13:00:21","date_gmt":"2026-06-26T13:00:21","guid":{"rendered":"https:\/\/tools.dwiyanti.com\/blog\/?p=310"},"modified":"2026-06-26T13:00:21","modified_gmt":"2026-06-26T13:00:21","slug":"schema-blogposting-versi-claude","status":"publish","type":"post","link":"https:\/\/tools.dwiyanti.com\/blog\/schema-blogposting-versi-claude","title":{"rendered":"Schema BlogPosting Versi Claude"},"content":{"rendered":"<pre style=\"white-space:pre-wrap;\">\n\n\/\/ =============================================================================\n\/\/ SCHEMA BLOGPOSTING \u2014 dwiyanti.com\n\/\/ Versi: 2.0 \u2014 Full SEO Modern + AI Overview Optimization\n\/\/ Fix: @id, url, isPartOf, primaryImageOfPage, inLanguage, breadcrumb,\n\/\/      speakable, wordCount, articleSection, keywords, @type spesifik,\n\/\/      ImageObject @id + contentUrl, mainEntityOfPage sebagai @id reference\n\/\/ =============================================================================\n\nfunction add_blogposting_schema() {\n\n    \/\/ \u2500\u2500 Guard \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    if ( ! is_single() ) return;\n\n    global $post;\n\n    \/\/ \u2500\u2500 DATA DASAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    $title       = get_the_title( $post );\n    $url         = get_permalink( $post );\n    $published   = get_the_date( 'c', $post );\n    $modified    = get_the_modified_date( 'c', $post );\n    $description = get_optimized_meta_description(); \/\/ fungsi existing\n    $site_icon   = get_site_icon_url();\n    $site_url    = home_url();\n\n    \/\/ Word count \u2014 berguna untuk AI dan Google untuk menilai content depth\n    $content_raw = get_post_field( 'post_content', $post->ID );\n    $word_count  = str_word_count( wp_strip_all_tags( $content_raw ) );\n\n    \/\/ Tags sebagai keywords\n    $tags = get_the_tags( $post->ID );\n    $keywords = [];\n    if ( ! empty( $tags ) && ! is_wp_error( $tags ) ) {\n        foreach ( $tags as $tag ) {\n            $keywords[] = $tag->name;\n        }\n    }\n\n    \/\/ \u2500\u2500 BAHASA KONTEN \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    $in_language = 'id-ID';\n\n    \/\/ \u2500\u2500 AMBIL SEMUA GAMBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    $images        = [];\n    $primary_image = null;\n\n    \/\/ 1. Featured Image \u2014 primary\n    if ( has_post_thumbnail( $post->ID ) ) {\n        $image_id   = get_post_thumbnail_id( $post->ID );\n        $image_url  = wp_get_attachment_image_url( $image_id, 'full' );\n        $image_meta = wp_get_attachment_metadata( $image_id );\n        $image_alt  = get_post_meta( $image_id, '_wp_attachment_image_alt', true );\n        $image_cap  = wp_get_attachment_caption( $image_id );\n\n        $primary_image = [\n            '@type'      => 'ImageObject',\n            '@id'        => $image_url . '#primaryimage',\n            'url'        => $image_url,\n            'contentUrl' => $image_url,\n            'width'      => isset( $image_meta['width'] )  ? $image_meta['width']  : 1200,\n            'height'     => isset( $image_meta['height'] ) ? $image_meta['height'] : 630,\n        ];\n        if ( ! empty( $image_alt ) ) $primary_image['name']    = $image_alt;\n        if ( ! empty( $image_cap ) ) $primary_image['caption'] = $image_cap;\n\n        $images[] = $primary_image;\n    }\n\n    \/\/ 2. Gambar dari konten\n    preg_match_all( '\/<img[^>]+src=[\"\\']([^\"\\']+)[\"\\']\/i', $content_raw, $matches );\n\n    if ( ! empty( $matches[1] ) ) {\n        foreach ( $matches[1] as $img_url ) {\n            $is_duplicate = false;\n            foreach ( $images as $img ) {\n                if ( $img['url'] === $img_url ) { $is_duplicate = true; break; }\n            }\n            if ( ! $is_duplicate ) {\n                $images[] = [\n                    '@type'      => 'ImageObject',\n                    '@id'        => $img_url . '#image',\n                    'url'        => $img_url,\n                    'contentUrl' => $img_url,\n                    'width'      => 1200,\n                    'height'     => 630,\n                ];\n            }\n        }\n    }\n\n    \/\/ 3. Fallback\n    if ( empty( $images ) ) {\n        $fallback_url  = 'https:\/\/dwiyanti.com\/wp-content\/themes\/lifestyle\/assets\/images\/DwiYanti.jpeg';\n        $primary_image = [\n            '@type'      => 'ImageObject',\n            '@id'        => $fallback_url . '#primaryimage',\n            'url'        => $fallback_url,\n            'contentUrl' => $fallback_url,\n            'width'      => 1200,\n            'height'     => 630,\n            'name'       => 'Dwi Yanti',\n        ];\n        $images[] = $primary_image;\n    }\n\n    \/\/ \u2500\u2500 DETEKSI KATEGORI & ARTICLE TYPE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    \/\/ BlogPosting adalah sub-type SocialMediaPosting > Article.\n    \/\/ Untuk konten lifestyle\/beauty, BlogPosting sudah tepat.\n    \/\/ Untuk health, bisa pakai Article agar tidak konflik dengan MedicalWebPage.\n    $article_type     = 'BlogPosting';\n    $primary_category = '';\n    $article_section  = '';\n    $about_entity     = null;\n    $categories       = get_the_category();\n\n    if ( ! empty( $categories ) ) {\n        $primary_category = $categories[0]->name;\n        $article_section  = $primary_category; \/\/ articleSection = nama kategori\n        $cat_lower        = strtolower( $primary_category );\n\n        if ( in_array( $cat_lower, [ 'beauty', 'skincare', 'makeup' ] ) ) {\n            $article_type = 'BlogPosting';\n            $about_entity = [ '@type' => 'Thing', 'name' => $primary_category ];\n        } elseif ( in_array( $cat_lower, [ 'health', 'wellness', 'fitness' ] ) ) {\n            \/\/ Article lebih aman untuk konten health agar tidak misklaim medis\n            $article_type = 'Article';\n            $about_entity = [ '@type' => 'MedicalCondition', 'name' => $primary_category ];\n        } elseif ( in_array( $cat_lower, [ 'lifestyle', 'travel', 'fashion' ] ) ) {\n            $article_type = 'BlogPosting';\n            $about_entity = [ '@type' => 'Thing', 'name' => $primary_category ];\n        }\n    }\n\n    \/\/ \u2500\u2500 BREADCRUMB \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    $breadcrumb_items = [\n        [\n            '@type'    => 'ListItem',\n            'position' => 1,\n            'name'     => 'Home',\n            'item'     => $site_url . '\/',\n        ],\n    ];\n\n    if ( ! empty( $primary_category ) && ! empty( $categories ) ) {\n        $cat_link = get_category_link( $categories[0]->term_id );\n        $breadcrumb_items[] = [\n            '@type'    => 'ListItem',\n            'position' => 2,\n            'name'     => $primary_category,\n            'item'     => $cat_link,\n        ];\n        $breadcrumb_items[] = [\n            '@type'    => 'ListItem',\n            'position' => 3,\n            'name'     => $title,\n            'item'     => $url,\n        ];\n    } else {\n        $breadcrumb_items[] = [\n            '@type'    => 'ListItem',\n            'position' => 2,\n            'name'     => $title,\n            'item'     => $url,\n        ];\n    }\n\n    $breadcrumb_schema = [\n        '@type'           => 'BreadcrumbList',\n        '@id'             => $url . '#breadcrumb',\n        'itemListElement' => $breadcrumb_items,\n    ];\n\n    \/\/ \u2500\u2500 BANGUN BLOGPOSTING SCHEMA \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    $blogposting = [\n        '@type'             => $article_type,\n        '@id'               => $url . '#article',\n        'url'               => $url,\n        'headline'          => $title,\n        'name'              => $title,\n        'description'       => $description,\n        'inLanguage'        => $in_language,\n        'wordCount'         => $word_count,\n\n        \/\/ mainEntityOfPage \u2014 reference ke WebPage @id, bukan buat WebPage baru\n        'mainEntityOfPage'  => [\n            '@type' => 'WebPage',\n            '@id'   => $url . '#webpage',\n        ],\n\n        'isPartOf'          => [\n            '@type' => 'WebSite',\n            '@id'   => $site_url . '\/#website',\n        ],\n\n        'breadcrumb'        => [\n            '@id' => $url . '#breadcrumb',\n        ],\n\n        'author'            => [\n            '@type' => 'Person',\n            'name'  => 'Dwi Yanti',\n            '@id'   => 'https:\/\/me.dwiyanti.com\/#dwi-yanti',\n        ],\n\n        'publisher'         => [\n            '@type'         => 'Organization',\n            '@id'           => $site_url . '\/#organization',\n            'name'          => 'Dwi Yanti SEO',\n            'alternateName' => 'Dwi Yanti SEO Specialist & Technical SEO Strategist',\n            'logo'          => [\n                '@type' => 'ImageObject',\n                'url'   => $site_icon,\n            ],\n        ],\n\n        'datePublished'     => $published,\n        'dateModified'      => $modified,\n        'image'             => $images,\n\n        \/\/ articleSection \u2014 bantu Google klaster konten per topik\n        'articleSection'    => $article_section,\n\n        \/\/ Speakable \u2014 bantu AI Overview & Google SGE pilih konten utama\n        'speakable'         => [\n            '@type'       => 'SpeakableSpecification',\n            'cssSelector' => [ 'h1', '.entry-content p:first-of-type', '.post-excerpt' ],\n        ],\n    ];\n\n    \/\/ primaryImageOfPage \u2014 hanya kalau ada featured\/fallback image\n    if ( ! is_null( $primary_image ) ) {\n        $blogposting['primaryImageOfPage'] = [\n            '@id' => $primary_image['@id'],\n        ];\n    }\n\n    \/\/ Keywords \u2014 dari post tags\n    if ( ! empty( $keywords ) ) {\n        $blogposting['keywords'] = implode( ', ', $keywords );\n    }\n\n    \/\/ About entity \u2014 sesuai kategori\n    if ( ! is_null( $about_entity ) ) {\n        $blogposting['about'] = $about_entity;\n    }\n\n    \/\/ \u2500\u2500 BANGUN @GRAPH \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    $schema = [\n        '@context' => 'https:\/\/schema.org',\n        '@graph'   => [\n            $breadcrumb_schema,\n            $blogposting,\n        ],\n    ];\n\n    \/\/ \u2500\u2500 OUTPUT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    echo '<script type=\"application\/ld+json\">' . \"\\n\";\n    echo wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );\n    echo \"\\n\" . '<\/script>' . \"\\n\";\n}\nadd_action( 'wp_head', 'add_blogposting_schema' );\n\/\/ END BlogPosting Schema\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\/\/ ============================================================================= \/\/ SCHEMA BLOGPOSTING \u2014 dwiyanti.com \/\/ Versi: 2.0 \u2014 Full SEO Modern + AI Overview Optimization \/\/ Fix: @id, url, isPartOf, primaryImageOfPage, inLanguage, breadcrumb, \/\/ speakable, wordCount, articleSection, keywords, @type spesifik, \/\/ ImageObject @id + contentUrl, mainEntityOfPage sebagai @id reference \/\/ ============================================================================= function add_blogposting_schema() { \/\/ \u2500\u2500 Guard \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 if ( ! is_single() [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-310","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/posts\/310","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/comments?post=310"}],"version-history":[{"count":1,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/posts\/310\/revisions"}],"predecessor-version":[{"id":311,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/posts\/310\/revisions\/311"}],"wp:attachment":[{"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/media?parent=310"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/categories?post=310"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/tags?post=310"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}