Kodeksidipo-LogoBaru-01-16x16 Kodeksidipo — Mission Impossible: Migrasi Ke Tema Blogger Layout V3

Mission Impossible: Migrasi Ke Tema Blogger Layout V3

Selama ini Saya memang asik utak-atik tema Blogger dengan layout versi 2 tapi setelah melihat tema Blogger lainnya yang ternyata memakai layout versi 3 bikin Saya tertarik untuk membuat sendiri.

Kerangka tema yang Saya pakai adalah tema tersebut punya dua sidebar disamping ruang postingan.

Kalo diakses pake hp maka ruang posting berada di atas dua sidebar yang memuat widget random dan recent posts.

Selain memanfaatkan blog pager, Saya juga pengen ada widget related posts di dalam ruang postingan.

Tiga widget yang Saya sebutkan bukan widget yang disediakan langsung oleh Blogger.

Dengan bantuan AI dari Google, Saya bisa mendapatkan kerangka tema tersebut dan untuk memolesnya supaya bisa tampil sesuai dengan kemauan Saya.

Ada tiga model CSS yang Saya pakai yaitu:

  • https://jdan.github.io/98.css/ pada halaman beranda.
  • Kodeksidipo-TemaBlogger-Layout3-01-Beranda
  • https://botoxparty.github.io/XP.css/
  • Kodeksidipo-TemaBlogger-Layout3-02-Indeks
  • https://khang-nd.github.io/7.css/
  • Kodeksidipo-TemaBlogger-Layout3-03-RuangPostingan

Saya menyebut tema Blogger yang dibuat ini dengan AEROCK2.

Struktur di dalam elemen <body>:

<div class='site-wrapper'>
  <header class='site-header' role='banner'>
    <b:section id='header-section' maxwidgets='1' showaddelement='no'>
      <b:widget id='Header1' locked='true' title='Header Blog' type='Header' version='2'>
        <b:includable id='main'>
          <b:if cond='data:view.isHomepage'>
            <h1 class='blog-title'><a expr:href='data:blog.homepageUrl'><data:title/></a></h1>
          <b:else/>
            <div class='blog-title'><a expr:href='data:blog.homepageUrl'><data:title/></a></div>
          </b:if>
          <p class='blog-description'><data:description/></p>
        </b:includable>
      </b:widget>
    </b:section>
  </header>

  <div class='main-container'>
    <aside class='sidebar-left' role='complementary'>
      <b:section id='sidebar-left-section' showaddelement='yes'>
        <b:widget id='HTML11' locked='false' title='Random Posts' type='HTML' version='2'>
          <b:includable id='main'>
            <h2 class='widget-title'><data:title/></h2>
            <div class='widget-content'>
              <ul id='random-posts-wrapper'>Memuat artikel...</ul>
            </div>
          </b:includable>
        </b:widget>
      </b:section>
    </aside>

    <main class='main-content' role='main'>
      <b:section id='main-post-section' showaddelement='no'>
        <b:widget id='Blog1' locked='true' title='Posting Blog' type='Blog' version='2'>
          <b:includable id='main' var='top'>
            <b:if cond='data:posts'>
              <b:loop values='data:posts' var='post'>
                <article expr:class='"post-item " + (data:post.labels any (l => l.name == "AdaVideo") ? "has-video " : "") + (data:post.labels any (l => l.name == "AdaIframe") ? "has-iframe " : "") + (data:post.labels any (l => l.name == "AdaSintaksH") ? "has-syntax " : "")'>
                  
                  <header class='post-title'>
                    <b:if cond='data:view.isPost'>
                      <h1><data:post.title/></h1>
                    <b:else/>
                      <h2><a expr:href='data:post.url'><data:post.title/></a></h2>
                    </b:if>
                  </header>

                  <div class='post-body'>
                    <b:if cond='data:view.isMultipleItems'>
                      <div class='post-loop-item'>
                        <div class='post-loop-thumbnail'>
                          <a expr:href='data:post.url'>
                            <img class='thumb-webp' height='100' width='100' expr:alt='data:post.title' expr:src='data:post.thumbnailUrl'/>
                          </a>
                        </div>
                        <div class='post-loop-text'>
                          <p><data:post.snippet/></p>
                          <a class='read-more-btn' expr:href='data:post.url'>Baca selengkapnya...</a>
                        </div>
                      </div>
                    </b:if>
                    <b:if cond='data:view.isSingleItem'>
                      <data:post.body/>
                    </b:if>
                  </div>

                  <!-- Ruang Pager & Widget Komentar diletakkan modular di sini -->
                </article>
              </b:loop>
            </b:if>
          </b:includable>
        </b:widget>
      </b:section>
    </main>

    <aside class='sidebar-right' role='complementary'>
      <b:section id='sidebar-right-section' showaddelement='yes'>
        <b:widget id='HTML12' locked='false' title='Recent Posts' type='HTML' version='2'>
          <b:includable id='main'>
            <h2 class='widget-title'><data:title/></h2>
            <div class='widget-content'>
              <ul id='recent-posts-wrapper'>Memuat artikel...</ul>
            </div>
          </b:includable>
        </b:widget>
      </b:section>
    </aside>
  </div>
</div>

JavaScript Efisiensi Tinggi (Single Fetch Dan DOM Smart Extractor)

<script type='text/javascript'>
//<![CDATA[
  // 1. GABUNGAN RECENT & RANDOM POSTS (1x Panggilan JSON Feed)
  fetch('/feeds/posts/summary?alt=json&max-results=15')
    .then(res => res.json())
    .then(data => {
      let entries = data.feed.entry;
      if (entries && entries.length > 0) {
        // Recent Posts
        let recentHtml = '';
        let rLimit = Math.min(entries.length, 5);
        for(let i=0; i<rLimit; i++) {
          let link = entries[i].link.find(l => l.rel === 'alternate').href;
          recentHtml += `<li><a href="${link}">${entries[i].title.$t}</a></li>`;
        }
        if(document.getElementById('recent-posts-wrapper')) document.getElementById('recent-posts-wrapper').innerHTML = recentHtml;

        // Random Posts
        let randomHtml = '';
        let rEntries = [...entries].sort(() => 0.5 - Math.random());
        let randLimit = Math.min(rEntries.length, 5);
        for(let i=0; i<randLimit; i++) {
          let link = rEntries[i].link.find(l => l.rel === 'alternate').href;
          randomHtml += `<li><a href="${link}">${rEntries[i].title.$t}</a></li>`;
        }
        if(document.getElementById('random-posts-wrapper')) document.getElementById('random-posts-wrapper').innerHTML = randomHtml;
      }
    });

  // 2. TIMEOUT / LAZY THUMBNAIL TO WEBP AUTO-EXTRACTOR
  document.addEventListener("DOMContentLoaded", function() {
    let images = document.querySelectorAll('.thumb-webp');
    images.forEach(function(img) {
      let src = img.getAttribute('src');
      if (src) {
        if (src.includes('/s72-c/')) { src = src.replace('/s72-c/', '/s320-c-rw/'); } 
        else if (src.includes('=s72-c')) { src = src.replace('=s72-c', '=s320-c-rw'); } 
        else if (src.match(/=w\d+-h\d+-p-k-no-nu/)) { src = src.replace(/=w\d+-h\d+-p-k-no-nu/, '=s320-c-rw'); }
        img.setAttribute('src', src);
      }
    });

    // 3. SKEMA VALIDASI RICH SNIPPET & DYNAMIC BACKGROUND VIA JS DOM
    let holder = document.getElementById('seo-data-holder');
    let articleContent = document.querySelector('.post-body');
    if (holder && articleContent) {
      let firstImg = articleContent.querySelector('img');
      let finalImg = firstImg ? firstImg.src : "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWhjHtVBJTANAclKcscpWNjmQtaav2XspBalTLa_0s8uc1AXW7vBUFUro3Z1OTg2CNZ4JYoPmRn_fwzMwppdypLqSwoUe8LuMzSXLroYOQ4LbyGlgN_7BigW8ZdZDKlPhf95F0N-zc3eP_FTiLT4sy9v8KVlSOsk0TzPE_01v8bSAo_Arlm_bWe7hjZMU9/s1600/Kodeksidipo-Logo150x150.png";

      // Jalankan Efek Background Gambar Utama Dinamis
      if(firstImg && firstImg.src) {
        document.body.style.backgroundImage = "linear-gradient(rgba(244, 246, 249, 0.88), rgba(244, 246, 249, 0.88)), url('" + firstImg.src + "')";
        document.body.style.backgroundSize = "cover";
        document.body.style.backgroundPosition = "center";
        document.body.style.backgroundAttachment = "fixed";
      }

      // Bangun Objek Struktur Data Google BlogPosting
      let seoData = {
        "@context": "https://schema.org",
        "@type": "BlogPosting",
        "mainEntityOfPage": { "@type": "WebPage", "@id": holder.getAttribute('data-url') },
        "headline": holder.getAttribute('data-title'),
        "description": holder.getAttribute('data-desc'),
        "image": { "@type": "ImageObject", "url": finalImg },
        "datePublished": holder.getAttribute('data-date'),
        "dateModified": holder.getAttribute('data-modified'),
        "author": { "@type": "Person", "name": holder.getAttribute('data-author'), "url": holder.getAttribute('data-authorurl') },
        "publisher": {
          "@type": "Organization",
          "name": holder.getAttribute('data-blogtitle'),
          "logo": { "@type": "ImageObject", "url": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEwE/no-image.png" }
        }
      };
      let script = document.createElement('script');
      script.type = 'application/ld+json';
      script.text = JSON.stringify(seoData);
      document.head.appendChild(script);
    }
  });

  // 4. TOGGLE LOAD KOMENTAR LAZY-LOAD
  window.loadBloggerComment = function() {
    let box = document.getElementById('blogger-comment-box');
    let btn = document.getElementById('show-comment-btn');
    if (box && box.style.display === 'none') {
      box.style.display = 'block';
      btn.innerText = 'Sembunyikan Komentar';
      box.scrollIntoView({ behavior: 'smooth' });
    } else if (box) {
      box.style.display = 'none';
      btn.innerText = 'Tampilkan Kolom Komentar';
    }
  };
//]]>
</script>

CSS Cerdas Dan Anti-Unused CSS

/* =======================================================
   KONDISIONAL KELAS KONTEN DENGAN EFFICIENCY MAKSIMAL
   ======================================================= */
/* CSS Gambar Utama Halaman */
.post-body .separator img {
  max-width: 100%;
  height: auto;
  border-radius: 8px;
  display: block;
  margin: 15px auto;
}

/* Video Responsif 16:9 - Hanya Aktif Jika Artikel Berlabel 'AdaVideo' */
.has-video .video-responsive {
  width: 100%;
  max-width: 680px;
  margin: 20px auto;
  aspect-ratio: 16 / 9;
  position: relative;
}
.has-video .video-responsive iframe {
  position: absolute;
  top: 0; left: 0; width: 100%; height: 100%; border: none;
}

/* Syntax Highlighting & Line Counter - Hanya Aktif Jika Artikel Berlabel 'AdaSintaksH' */
.has-syntax pre.code_syntax {
  counter-reset: line;
  margin: 0;
  margin-left: 2em;
  overflow-wrap: break-word;
  word-break: break-word;
  word-wrap: break-word;
}
.has-syntax .code_syntax > .line_wrapper {
  counter-increment: line;
}
.has-syntax .code_syntax > .line_wrapper::before {
  content: counter(line);
  user-select: none;
  text-indent: -2em;
  display: inline-block;
  width: 2em;
  color: #888;
}
Beranda
Sebelumnya ‹- Postingan -› Selanjutnya