{"id":1625,"date":"2026-06-23T04:15:25","date_gmt":"2026-06-23T04:15:25","guid":{"rendered":"https:\/\/discipleshiptraininginternational.com\/?page_id=1625"},"modified":"2026-06-23T04:38:17","modified_gmt":"2026-06-23T04:38:17","slug":"search-free-books","status":"publish","type":"page","link":"https:\/\/discipleshiptraininginternational.com\/?page_id=1625","title":{"rendered":"Search Free Books"},"content":{"rendered":"\n\n<div class=\"dti-free-search-wrapper\">\n\n  <h2 class=\"dti-free-search-title\">Search Free Books<\/h2>\n\n  <div class=\"dti-free-search-box\">\n    <input\n      type=\"text\"\n      id=\"dtiFreeBookSearchInput\"\n      placeholder=\"Search by title or catalog number...\"\n      autocomplete=\"off\"\n    >\n  <\/div>\n\n  <p id=\"dtiFreeBookCount\" class=\"dti-free-book-count\">Loading books&#8230;<\/p>\n\n  <div id=\"dtiFreeBookResults\" class=\"dti-free-book-results\"><\/div>\n\n  <div class=\"dti-free-pagination\" id=\"dtiFreePagination\" style=\"display:none;\">\n    <button id=\"dtiPrevPageBtn\" class=\"dti-page-button\" type=\"button\">Previous 50<\/button>\n    <span id=\"dtiPageInfo\" class=\"dti-page-info\"><\/span>\n    <button id=\"dtiNextPageBtn\" class=\"dti-page-button\" type=\"button\">Next 50<\/button>\n  <\/div>\n\n<\/div>\n\n<style>\n.dti-free-search-wrapper{\n  max-width:1000px;\n  margin:0 auto;\n  padding:30px 20px;\n  background:#f6f1e8;\n  border-radius:18px;\n}\n\n.dti-free-search-title{\n  text-align:center;\n  font-size:clamp(30px, 4vw, 54px);\n  margin:0 0 24px;\n  color:#2f241a;\n  font-weight:800;\n}\n\n.dti-free-search-box{\n  max-width:700px;\n  margin:0 auto 18px;\n}\n\n#dtiFreeBookSearchInput{\n  width:100%;\n  padding:16px 18px;\n  font-size:20px;\n  border:3px solid #6e4322;\n  border-radius:12px;\n  outline:none;\n}\n\n.dti-free-book-count{\n  text-align:center;\n  color:#2f241a;\n  font-size:17px;\n  margin:10px 0 25px;\n}\n\n.dti-free-book-results{\n  display:flex;\n  flex-direction:column;\n  gap:10px;\n}\n\n.dti-free-book-row{\n  display:flex;\n  justify-content:space-between;\n  align-items:center;\n  gap:14px;\n  background:#fffaf0;\n  border:1px solid rgba(0,0,0,.12);\n  border-radius:10px;\n  padding:13px 16px;\n  box-shadow:0 4px 10px rgba(0,0,0,.08);\n}\n\n.dti-free-book-info{\n  color:#2f241a;\n  font-size:17px;\n  line-height:1.35;\n}\n\n.dti-free-book-code{\n  font-weight:800;\n  color:#6e4322;\n  margin-right:8px;\n}\n\n.dti-free-book-title{\n  font-weight:600;\n}\n\n.dti-free-book-button{\n  white-space:nowrap;\n  padding:9px 14px;\n  background:#6e4322;\n  color:white;\n  text-decoration:none;\n  border-radius:8px;\n  font-weight:700;\n}\n\n.dti-free-book-button:hover{\n  background:#2f241a;\n  color:white;\n}\n\n.dti-free-book-button-disabled{\n  white-space:nowrap;\n  padding:9px 14px;\n  background:#999;\n  color:white;\n  border-radius:8px;\n  font-weight:700;\n  cursor:not-allowed;\n}\n\n.dti-free-pagination{\n  display:flex;\n  justify-content:center;\n  align-items:center;\n  gap:14px;\n  margin-top:24px;\n  flex-wrap:wrap;\n}\n\n.dti-page-button{\n  padding:10px 16px;\n  background:#6e4322;\n  color:#fff;\n  border:none;\n  border-radius:8px;\n  font-weight:700;\n  cursor:pointer;\n}\n\n.dti-page-button:hover{\n  background:#2f241a;\n}\n\n.dti-page-button:disabled{\n  background:#999;\n  cursor:not-allowed;\n}\n\n.dti-page-info{\n  font-size:16px;\n  font-weight:700;\n  color:#2f241a;\n}\n\n@media(max-width:650px){\n  .dti-free-book-row{\n    flex-direction:column;\n    align-items:flex-start;\n  }\n\n  .dti-free-book-button,\n  .dti-free-book-button-disabled{\n    width:100%;\n    text-align:center;\n    box-sizing:border-box;\n  }\n}\n<\/style>\n\n<script>\nconst dtiMasterCatalogUrl = \"https:\/\/discipleshiptraininginternational-books.s3.us-east-2.amazonaws.com\/master+catalogs\/dti-master-free-books-catalog-15.json?v=7\";\n\nlet dtiAllBooks = [];\nlet dtiFilteredBooks = [];\nlet dtiCurrentPage = 1;\nconst dtiBooksPerPage = 50;\n\nfunction normalizeSearchText(value){\n  return String(value || \"\")\n    .toLowerCase()\n    .replace(\/[\u2019']\/g, \"\")\n    .replace(\/[^a-z0-9]+\/g, \" \")\n    .trim();\n}\n\nfunction encodeS3Part(value){\n  return encodeURIComponent(String(value || \"\").trim()).replaceAll(\"%20\", \"+\");\n}\n\nfunction getBookCode(book){\n  return String(\n    book[\"Catalog Number\"] ||\n    book.catalogNumber ||\n    book.catalog_code ||\n    book.code ||\n    \"\"\n  ).trim();\n}\n\nfunction getBookType(book){\n  return String(\n    book[\"Book Code\"] ||\n    book.bookType ||\n    book.book_code ||\n    book.format_code ||\n    \"QT\"\n  ).trim();\n}\n\nfunction getTrimSize(book){\n  return String(\n    book[\"Trim Size\"] ||\n    book.trimSize ||\n    book.trim_size ||\n    \"4X6\"\n  ).trim();\n}\n\nfunction getBookTitle(book){\n  return String(\n    book[\"Title\"] ||\n    book.title ||\n    book.bookTitle ||\n    \"\"\n  ).trim();\n}\n\nfunction buildFssUrl(book){\n  const code = getBookCode(book);\n  const trim = getTrimSize(book);\n  const type = getBookType(book);\n  const title = getBookTitle(book);\n\n  return \"https:\/\/discipleshiptraininginternational-books.s3.us-east-2.amazonaws.com\/fss+books+33\/\"\n    + encodeS3Part(code) + \"\/\"\n    + encodeS3Part(code + \" \" + trim + \" \" + type + \" \" + title)\n    + \".html\";\n}\n\nfunction buildFssCoverUrl(book){\n  const code = getBookCode(book);\n\n  return \"https:\/\/discipleshiptraininginternational-books.s3.us-east-2.amazonaws.com\/fss+books+33\/\"\n    + encodeS3Part(code) + \"\/cover.jpg\";\n}\n\nfunction getBookCover(book){\n  const code = getBookCode(book);\n\n  if(code.startsWith(\"AD\")){\n    return buildFssCoverUrl(book);\n  }\n\n  return String(\n    book.coverUrl ||\n    book.cover ||\n    book.cover_url ||\n    book.coverURL ||\n    book[\"Cover JPG URL\"] ||\n    book[\"Cover JPG Url\"] ||\n    \"\"\n  ).trim();\n}\n\nfunction getBookUrl(book){\n  const code = getBookCode(book);\n\n  const rawUrl = String(\n    book.bookUrl ||\n    book.htmlUrl ||\n    book.html ||\n    book.html_url ||\n    book.url ||\n    book[\"HTML URL\"] ||\n    book.s3_html_url ||\n    \"\"\n  ).trim();\n\n  if(code.startsWith(\"AD\")){\n    return buildFssUrl(book);\n  }\n\n  return rawUrl;\n}\n\nfunction isGoodHtmlUrl(url){\n  return (\n    url &&\n    url.includes(\"discipleshiptraininginternational-books.s3\") &&\n    url.toLowerCase().includes(\".html\")\n  );\n}\n\nfunction bookMatchesSearch(book, searchValue){\n  const query = normalizeSearchText(searchValue);\n\n  if(!query){\n    return true;\n  }\n\n  const title = normalizeSearchText(getBookTitle(book));\n  const code = normalizeSearchText(getBookCode(book));\n\n  return title.includes(query) || code.includes(query);\n}\n\nfunction saveOpenedBook(book){\n  let openedBooks = JSON.parse(localStorage.getItem(\"dtiOpenedBooks\")) || [];\n\n  const code = getBookCode(book);\n  const title = getBookTitle(book);\n  const html = getBookUrl(book);\n  const cover = getBookCover(book);\n\n  openedBooks = openedBooks.filter(item => item.code !== code);\n\n  openedBooks.unshift({\n    code: code,\n    title: title,\n    cover: cover,\n    html: html,\n    building: \"Free Book Search\",\n    lastOpened: new Date().toLocaleString()\n  });\n\n  localStorage.setItem(\"dtiOpenedBooks\", JSON.stringify(openedBooks));\n}\n\nfunction renderBooks(){\n  const results = document.getElementById(\"dtiFreeBookResults\");\n  const count = document.getElementById(\"dtiFreeBookCount\");\n  const pagination = document.getElementById(\"dtiFreePagination\");\n  const prevBtn = document.getElementById(\"dtiPrevPageBtn\");\n  const nextBtn = document.getElementById(\"dtiNextPageBtn\");\n  const pageInfo = document.getElementById(\"dtiPageInfo\");\n\n  const totalBooks = dtiFilteredBooks.length;\n  const totalPages = Math.max(1, Math.ceil(totalBooks \/ dtiBooksPerPage));\n  const startIndex = (dtiCurrentPage - 1) * dtiBooksPerPage;\n  const endIndex = startIndex + dtiBooksPerPage;\n  const pageBooks = dtiFilteredBooks.slice(startIndex, endIndex);\n\n  if(totalBooks === 0){\n    count.textContent = \"0 books found.\";\n    results.innerHTML = \"<p>No books found.<\/p>\";\n    pagination.style.display = \"none\";\n    return;\n  }\n\n  count.textContent = totalBooks + \" books found. Showing \" + (startIndex + 1) + \"\u2013\" + Math.min(endIndex, totalBooks) + \".\";\n\n  results.innerHTML = pageBooks.map((book, index) => {\n    const code = getBookCode(book);\n    const title = getBookTitle(book);\n    const url = getBookUrl(book);\n    const goodUrl = isGoodHtmlUrl(url);\n\n    const buttonHtml = goodUrl\n      ? `<a\n          class=\"dti-free-book-button\"\n          href=\"${url}\"\n          target=\"_blank\"\n          rel=\"noopener\"\n          data-book-index=\"${index}\"\n        >Read Free<\/a>`\n      : `<span class=\"dti-free-book-button-disabled\">Link Not Ready<\/span>`;\n\n    return `\n      <div class=\"dti-free-book-row\">\n        <div class=\"dti-free-book-info\">\n          <span class=\"dti-free-book-code\">${code}<\/span>\n          <span class=\"dti-free-book-title\">${title}<\/span>\n        <\/div>\n        ${buttonHtml}\n      <\/div>\n    `;\n  }).join(\"\");\n\n  document.querySelectorAll(\".dti-free-book-button[href]\").forEach(button => {\n    button.addEventListener(\"click\", function(){\n      const realIndex = Number(this.getAttribute(\"data-book-index\"));\n      saveOpenedBook(pageBooks[realIndex]);\n    });\n  });\n\n  pagination.style.display = totalBooks > dtiBooksPerPage ? \"flex\" : \"none\";\n  prevBtn.disabled = dtiCurrentPage === 1;\n  nextBtn.disabled = dtiCurrentPage === totalPages;\n  pageInfo.textContent = \"Page \" + dtiCurrentPage + \" of \" + totalPages;\n}\n\nasync function loadDtiFreeBookSearch(){\n  const count = document.getElementById(\"dtiFreeBookCount\");\n\n  try{\n    const response = await fetch(dtiMasterCatalogUrl, { cache: \"no-store\" });\n\n    if(!response.ok){\n      throw new Error(\"Catalog failed to load: \" + response.status);\n    }\n\n    dtiAllBooks = await response.json();\n\n    if(!Array.isArray(dtiAllBooks)){\n      throw new Error(\"Catalog is not an array.\");\n    }\n\n    dtiFilteredBooks = [...dtiAllBooks];\n    renderBooks();\n\n    document.getElementById(\"dtiFreeBookSearchInput\").addEventListener(\"input\", function(){\n      const searchValue = this.value;\n      dtiFilteredBooks = dtiAllBooks.filter(book => bookMatchesSearch(book, searchValue));\n      dtiCurrentPage = 1;\n      renderBooks();\n    });\n\n    document.getElementById(\"dtiPrevPageBtn\").addEventListener(\"click\", function(){\n      if(dtiCurrentPage > 1){\n        dtiCurrentPage--;\n        renderBooks();\n        window.scrollTo({ top: 0, behavior: \"smooth\" });\n      }\n    });\n\n    document.getElementById(\"dtiNextPageBtn\").addEventListener(\"click\", function(){\n      const totalPages = Math.ceil(dtiFilteredBooks.length \/ dtiBooksPerPage);\n      if(dtiCurrentPage < totalPages){\n        dtiCurrentPage++;\n        renderBooks();\n        window.scrollTo({ top: 0, behavior: \"smooth\" });\n      }\n    });\n\n  } catch(error){\n    count.textContent = \"Books could not load right now.\";\n    console.error(error);\n  }\n}\n\nloadDtiFreeBookSearch();\n<\/script>\n```\n\n","protected":false},"excerpt":{"rendered":"<p>Search Free Books Loading books&#8230; Previous 50 Next 50 &#8220;`<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1625","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/discipleshiptraininginternational.com\/index.php?rest_route=\/wp\/v2\/pages\/1625","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/discipleshiptraininginternational.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/discipleshiptraininginternational.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/discipleshiptraininginternational.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/discipleshiptraininginternational.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1625"}],"version-history":[{"count":12,"href":"https:\/\/discipleshiptraininginternational.com\/index.php?rest_route=\/wp\/v2\/pages\/1625\/revisions"}],"predecessor-version":[{"id":1637,"href":"https:\/\/discipleshiptraininginternational.com\/index.php?rest_route=\/wp\/v2\/pages\/1625\/revisions\/1637"}],"wp:attachment":[{"href":"https:\/\/discipleshiptraininginternational.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1625"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}