{"id":306,"date":"2026-06-26T12:09:27","date_gmt":"2026-06-26T12:09:27","guid":{"rendered":"https:\/\/tools.dwiyanti.com\/blog\/?p=306"},"modified":"2026-06-26T12:09:27","modified_gmt":"2026-06-26T12:09:27","slug":"schema-website-claude","status":"publish","type":"post","link":"https:\/\/tools.dwiyanti.com\/blog\/schema-website-claude","title":{"rendered":"Schema Website Claude"},"content":{"rendered":"<pre style=\"white-space:pre-wrap;\">\nSCHEMA WEBSITE DARI CLAUDE\n\n\/\/ Claude\n\/**\n * Universal Image Extractor for Schema\n * Mengambil semua gambar yang tampil di halaman dari rendered HTML\n * \n * @param int $limit      Maksimal jumlah gambar (default 10)\n * @param int $min_width  Filter gambar terlalu kecil (default 100px, skip icon\/pixel)\n * @return array          Array of ImageObject schema-ready\n *\/\nfunction get_all_page_images_for_schema( $limit = 10, $min_width = 100 ) {\n    $images = [];\n    $seen_urls = [];\n\n    \/\/ \u2500\u2500 1. Featured Image (prioritas utama) \u2500\u2500\u2500\u2500\u2500\u2500\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 ( has_post_thumbnail() ) {\n        $thumb_id = get_post_thumbnail_id();\n        $full     = wp_get_attachment_image_src( $thumb_id, 'full' );\n        $meta     = wp_get_attachment_metadata( $thumb_id );\n\n        if ( $full && ! in_array( $full[0], $seen_urls, true ) ) {\n            $seen_urls[] = $full[0];\n            $images[]    = build_schema_image_object(\n                $full[0],\n                $meta['width']  ?? $full[1],\n                $meta['height'] ?? $full[2],\n                get_post_meta( $thumb_id, '_wp_attachment_image_alt', true ) ?: get_the_title()\n            );\n        }\n    }\n\n    \/\/ \u2500\u2500 2. Gambar dari wp_get_attachment (Media Library) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    \/\/ Berguna jika template parts menggunakan get_template_part + WP_Query\n    $attached = get_posts([\n        'post_type'      => 'attachment',\n        'post_mime_type' => 'image',\n        'post_parent'    => get_the_ID(),\n        'posts_per_page' => $limit,\n        'post_status'    => 'inherit',\n    ]);\n\n    foreach ( $attached as $att ) {\n        $src  = wp_get_attachment_image_src( $att->ID, 'full' );\n        $meta = wp_get_attachment_metadata( $att->ID );\n\n        if ( ! $src ) continue;\n        if ( in_array( $src[0], $seen_urls, true ) ) continue;\n        if ( isset( $meta['width'] ) && $meta['width'] < $min_width ) continue;\n\n        $seen_urls[] = $src[0];\n        $images[]    = build_schema_image_object(\n            $src[0],\n            $meta['width']  ?? $src[1],\n            $meta['height'] ?? $src[2],\n            get_post_meta( $att->ID, '_wp_attachment_image_alt', true ) ?: $att->post_title\n        );\n\n        if ( count( $images ) >= $limit ) break;\n    }\n\n    \/\/ \u2500\u2500 3. Scan post_content (gambar di dalam konten) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    $post = get_post();\n    if ( $post && ! empty( $post->post_content ) ) {\n        $content_images = extract_images_from_html( $post->post_content, $seen_urls, $min_width );\n        foreach ( $content_images as $img ) {\n            if ( count( $images ) >= $limit ) break;\n            $seen_urls[] = $img['url'];\n            $images[]    = $img['schema'];\n        }\n    }\n\n    \/\/ \u2500\u2500 4. Fallback: OG image \/ default site image \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 ( empty( $images ) ) {\n        $default_url = get_site_icon_url( 512 ) ?: get_template_directory_uri() . 'wp-content\/themes\/lifestyle\/assets\/images\/DwiYanti.jpeg';\n        $images[]    = build_schema_image_object( $default_url, 1200, 630, get_bloginfo('name') );\n    }\n\n    return $images;\n}\n\n\n\/**\n * Helper: Build ImageObject array untuk Schema.org\n *\/\nfunction build_schema_image_object( $url, $width = null, $height = null, $caption = '' ) {\n    $obj = [\n        '@type' => 'ImageObject',\n        'url'   => esc_url( $url ),\n    ];\n    if ( $width )   $obj['width']   = (int) $width;\n    if ( $height )  $obj['height']  = (int) $height;\n    if ( $caption ) $obj['caption'] = esc_html( $caption );\n\n    return $obj;\n}\n\n\n\/**\n * Helper: Extract <img> dari string HTML mentah\n * Digunakan untuk scan post_content atau captured buffer\n *\n * @param string $html\n * @param array  &$seen_urls   Pass by reference agar deduplikasi global\n * @param int    $min_width\n * @return array [ ['url' => ..., 'schema' => ImageObject], ... ]\n *\/\nfunction extract_images_from_html( $html, &$seen_urls = [], $min_width = 100 ) {\n    $results = [];\n\n    if ( empty( $html ) ) return $results;\n\n    \/\/ Suppress libxml warnings untuk HTML tidak sempurna\n    libxml_use_internal_errors( true );\n    $dom = new DOMDocument();\n    $dom->loadHTML( mb_convert_encoding( $html, 'HTML-ENTITIES', 'UTF-8' ) );\n    libxml_clear_errors();\n\n    $img_tags = $dom->getElementsByTagName('img');\n\n    foreach ( $img_tags as $img ) {\n        \/\/ Ambil src \u2014 coba srcset dulu untuk kualitas terbaik\n        $src = '';\n\n        $srcset = $img->getAttribute('srcset');\n        if ( $srcset ) {\n            \/\/ Ambil URL dengan width terbesar dari srcset\n            $src = get_largest_srcset_url( $srcset );\n        }\n\n        if ( ! $src ) {\n            $src = $img->getAttribute('src');\n        }\n\n        \/\/ Skip data URIs, SVG inline, placeholder\n        if ( ! $src\n            || strpos( $src, 'data:' ) === 0\n            || strpos( $src, '.svg' ) !== false\n            || strpos( $src, 'placeholder' ) !== false\n        ) {\n            continue;\n        }\n\n        \/\/ Pastikan URL absolut\n        if ( strpos( $src, 'http' ) !== 0 ) {\n            $src = home_url( $src );\n        }\n\n        \/\/ Deduplicate\n        if ( in_array( $src, $seen_urls, true ) ) continue;\n\n        \/\/ Filter width dari atribut HTML (bukan meta)\n        $attr_width = (int) $img->getAttribute('width');\n        if ( $attr_width > 0 && $attr_width < $min_width ) continue;\n\n        $alt    = $img->getAttribute('alt') ?: '';\n        $width  = $attr_width ?: null;\n        $height = (int) $img->getAttribute('height') ?: null;\n\n        \/\/ Coba resolve ke WP attachment untuk metadata lengkap\n        $att_id = attachment_url_to_postid( $src );\n        if ( $att_id ) {\n            $meta   = wp_get_attachment_metadata( $att_id );\n            $width  = $meta['width']  ?? $width;\n            $height = $meta['height'] ?? $height;\n            $alt    = get_post_meta( $att_id, '_wp_attachment_image_alt', true ) ?: $alt;\n        }\n\n        $results[] = [\n            'url'    => $src,\n            'schema' => build_schema_image_object( $src, $width, $height, $alt ),\n        ];\n    }\n\n    return $results;\n}\n\n\n\/**\n * Helper: Ambil URL terbesar dari srcset string\n * \"img-300.jpg 300w, img-768.jpg 768w, img-1200.jpg 1200w\" \u2192 img-1200.jpg\n *\/\nfunction get_largest_srcset_url( $srcset ) {\n    $entries = array_map( 'trim', explode( ',', $srcset ) );\n    $best_url   = '';\n    $best_width = 0;\n\n    foreach ( $entries as $entry ) {\n        $parts = preg_split( '\/\\s+\/', trim( $entry ) );\n        if ( count( $parts ) < 2 ) {\n            \/\/ Tidak ada width descriptor, ambil sebagai fallback\n            if ( ! $best_url ) $best_url = $parts[0];\n            continue;\n        }\n        $w = (int) rtrim( $parts[1], 'w' );\n        if ( $w > $best_width ) {\n            $best_width = $w;\n            $best_url   = $parts[0];\n        }\n    }\n\n    return $best_url;\n}\n\n\/\/ Ambil semua gambar halaman depan\n$page_images = get_all_page_images_for_schema( 10 );\n\n$schema = [\n    '@context' => 'https:\/\/schema.org',\n    '@type'    => 'WebSite',\n    '@id'      => home_url('\/#website'),\n    'name'     => get_bloginfo('name'),\n    'url'      => home_url('\/'),\n    'image'    => count($page_images) === 1 ? $page_images[0] : $page_images,\n    \/\/ ... property lain\n];\n\n\/\/END Claude\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>SCHEMA WEBSITE DARI CLAUDE \/\/ Claude \/** * Universal Image Extractor for Schema * Mengambil semua gambar yang tampil di halaman dari rendered HTML * * @param int $limit Maksimal jumlah gambar (default 10) * @param int $min_width Filter gambar terlalu kecil (default 100px, skip icon\/pixel) * @return array Array of ImageObject schema-ready *\/ function [&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-306","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/posts\/306","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=306"}],"version-history":[{"count":1,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/posts\/306\/revisions"}],"predecessor-version":[{"id":308,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/posts\/306\/revisions\/308"}],"wp:attachment":[{"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/media?parent=306"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/categories?post=306"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tools.dwiyanti.com\/blog\/wp-json\/wp\/v2\/tags?post=306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}