title: Show ebook online (using epub.js + WordPress)
body: <p>I want to show an ebook (epub-format) on a website that's built with a custom theme for WordPress.</p>
  <p>I have, among other things, tried to find answers in the <a href="https://github.com/futurepress/epub.js" rel="nofollow noreferrer">epub.js documentation</a> but I can't make sense of it and need help.</p>
  <p><strong>What it does now:</strong></p>
  <ul>
  <li>It loads the example ebook, but not correctly/as I want it.</li>
  <li>It doesn't load anything at all when I try to use my own ebook.</li>
  </ul>
  <p><strong>What I wish it would do:</strong></p>
  <ul>
  <li>That the ebook will load 100% in the specified field.</li>
  <li>Be able to show an ebook uploaded to the site through WordPress Media
  Library.</li>
  <li>Make it easy to manage ebooks in WordPress.
  On a &quot;project&quot; (custom post type) do I want to be able to show two buttons if necessary, one to download the associated ebook and one button that will redirect to an &quot;ebook&quot; page (another custom post type) for reading online. Not all &quot;project&quot; pages will have ebooks associated with them, so it must be easy to add/change/remove ebooks. But some projects may even have more than one ebook associated with them.</li>
  </ul>
  <p><strong>Additional information:</strong></p>
  <ul>
  <li>WordPress doesn't originally allow epub-files to be uploaded. I've fixed that by adding this to functions.php in my theme.</li>
  </ul>
  <blockquote>
  <pre><code>/* Allows uploading .MOBI and .EPUB files */
  function allow_personal_uploads ( $existing_mimes=array() ) {
   
      // allow uploading .MOBI and .EPUB files
      $existing_mimes['mobi'] = 'application/x-mobipocket-ebook'; 
      $existing_mimes['epub'] = 'application/epub+zip'; 
   
      // return amended array
      return $existing_mimes;
  }
  add_filter('upload_mimes', 'allow_personal_uploads');
  </code></pre>
  </blockquote>
  <ul>
  <li><p>I'm using the plugin Download Monitor to make it possible to download ebooks. Maybe it's possible to use <a href="https://www.download-monitor.com/kb/download-repository-retrieve_single/" rel="nofollow noreferrer">retrieve_single</a> to get the URL?</p>
  </li>
  <li><p>If it's to any help, I also have the plugin Advanced Custom Fields
  PRO.</p>
  </li>
  </ul>
  <p>Please keep in mind that I'm still quite new to javascript.</p>
  <p>Thanks in advance!</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>/* Dropdown */
  $(function () {
      var $window = $(window);
      var toggleMenu = function() {
        if($window.width() ) {
          $(".toc-list").slideToggle(250);  
        }  
      };
      var collapseMenu = function() {
        if($window.width() ) {
          $(".toc-list").slideUp(250);  
        }  
      };
    
      $(".toc-toggle").click(toggleMenu);
      
      $(".toc-list a").click(collapseMenu);
      
      $(document).click(function (event) {
      console.log(!$(event.target).closest('.table-of-contents').length);
      if(!$(event.target).closest('.table-of-contents').length) {
        collapseMenu();
      }
    });
      
      var handleMatchMedia = function(md) {
        if(md.matches) {
          $(".toc-list").show();
        }
        else {
          $(".toc-list").hide();
        }
      };
      
      var mq = window.matchMedia("(min-width: " + "px)");
      handleMatchMedia(mq);
      mq.addListener(handleMatchMedia);
    });
  
  /* EPUB */
  // Load the opf
  var book = ePub("https://s3.amazonaws.com/moby-dick/moby-dick.epub");
  var rendition = book.renderTo("viewer", {
  height: "100%"
  });
  var hash = window.location.hash.slice(2);
  // console.log(hash);
  rendition.display(hash || undefined);
  
  
  var next = document.getElementById("next");
  next.addEventListener("click", function(e){
    rendition.next();
    e.preventDefault();
  }, false);
  
  var prev = document.getElementById("prev");
  prev.addEventListener("click", function(e){
    rendition.prev();
    e.preventDefault();
  }, false);
  
  rendition.on("rendered", function(section){
    var nextSection = section.next();
    var prevSection = section.prev();
  
    if(nextSection) {
      nextNav = book.navigation.get(nextSection.href);
  
      if(nextNav) {
        nextLabel = nextNav.label;
      } else {
        nextLabel = "next";
      }
  
      next.textContent = nextLabel + " »";
    } else {
      next.textContent = "";
    }
  
    if(prevSection) {
      prevNav = book.navigation.get(prevSection.href);
  
      if(prevNav) {
        prevLabel = prevNav.label;
      } else {
        prevLabel = "previous";
      }
  
      prev.textContent = "« " + prevLabel;
    } else {
      prev.textContent = "";
    }
  
    // Add CFI fragment to the history
    //history.pushState({}, '', section.href);
    window.location.hash = "#/"+section.href
  });
  
  rendition.on("relocated", function(location){
    console.log(location);
  });
  
  book.loaded.navigation.then(function(toc){
    var $nav = document.getElementById("toc"),
        docfrag = document.createDocumentFragment();
    var addTocItems = function (parent, tocItems) {
      var $ul = document.createElement("ul");
      tocItems.forEach(function(chapter) {
        var item = document.createElement("li");
        var link = document.createElement("a");
        link.textContent = chapter.label;
        link.href = chapter.href;
        item.appendChild(link);
  
        if (chapter.subitems) {
          addTocItems(item, chapter.subitems)
        }
  
        link.onclick = function(){
          var url = link.getAttribute("href");
          rendition.display(url);
          return false;
        };
  
        $ul.appendChild(item);
      });
      parent.appendChild($ul);
    };
  
    addTocItems(docfrag, toc);
  
    $nav.appendChild(docfrag);
  
    if ($nav.offsetHeight + 60 &lt; window.innerHeight) {
      $nav.classList.add("fixed");
    }
  
  });
  
  book.loaded.metadata.then(function(meta){
    var $title = document.getElementById("title");
    var $author = document.getElementById("author");
    var $cover = document.getElementById("cover");
  
    $title.textContent = meta.title;
    $author.textContent = meta.creator;
    if (book.archive) {
      book.archive.createUrl(book.cover)
        .then(function (url) {
        $cover.src = url;
      })
    } else {
      $cover.src = book.cover;
    }
  
  });</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>/* http://meyerweb.com/eric/tools/css/reset/ 
     v2.0 | 20110126
     License: none (public domain)
  */
  
  html,
  body,
  div,
  span,
  applet,
  object,
  iframe,
  h1,
  h2,
  h3,
  h4,
  h5,
  h6,
  p,
  blockquote,
  pre,
  a,
  abbr,
  acronym,
  address,
  big,
  cite,
  code,
  del,
  dfn,
  em,
  img,
  ins,
  kbd,
  q,
  s,
  samp,
  small,
  strike,
  strong,
  sub,
  sup,
  tt,
  var,
  b,
  u,
  i,
  center,
  dl,
  dt,
  dd,
  ol,
  ul,
  li,
  fieldset,
  form,
  label,
  legend,
  table,
  caption,
  tbody,
  tfoot,
  thead,
  tr,
  th,
  td,
  article,
  aside,
  canvas,
  details,
  embed,
  figure,
  figcaption,
  footer,
  header,
  hgroup,
  menu,
  nav,
  output,
  ruby,
  section,
  summary,
  time,
  mark,
  audio,
  video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
  }
  
  
  /* HTML5 display-role reset for older browsers */
  
  article,
  aside,
  details,
  figcaption,
  figure,
  footer,
  header,
  hgroup,
  menu,
  nav,
  section {
    display: block;
  }
  
  body {
    line-height: 1;
  }
  
  ol,
  ul {
    list-style: none;
  }
  
  blockquote,
  q {
    quotes: none;
  }
  
  blockquote:before,
  blockquote:after,
  q:before,
  q:after {
    content: '';
    content: none;
  }
  
  table {
    border-collapse: collapse;
    border-spacing: 0;
  }
  /* End */
  
  body {
    background-color: tan;
  }
  
  .hidden {
    display: none;
  }
  
  .container {
    height: 100vh;
    position: relative;
  }
  
  #test1 {
    background-color: orange;
    height: 2rem;
    width: 100%;
  }
  
  #test2 {
    background-color: yellow;
    height: 2rem;
    width: 100%;
  }
  
  /* Table of contents */
  #toc-container {
    box-sizing: border-box;
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 1px;
    margin: 0 auto;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    background-color: #171717;
    top: 0;
    position: absolute;
    width: 100%;
    color: #ffffff;
    list-style-type: none;
    z-index: 2;
  }
  
  .table-of-contents {
    box-sizing: border-box;
  }
  
  #toc&gt;ul {
    list-style: none;
    padding: 1.5rem 0;
    top: calc(1.5rem*2);
    background-color: #171717;
    height: 100%;
  }
  
  #toc&gt;ul&gt;li {
    padding: 1rem;
    display: block;
  }
  
  #toc a {
    border-bottom: 2px solid #171717;
    padding-bottom: calc(1.5rem/6);
    text-decoration: none;
    color: #9e9ea1;
    display: inline-block;
  }
  
  #toc a:hover {
    border-bottom: 2px solid #ffffff;
    color: #ffffff;
    padding-bottom: calc(1.5rem/6);
    display: inline-block;
  }
  
  #toc {
    max-height: 80vh;
    overflow: auto;
    left: 0;
    right: 0;
    margin: 0 auto;
  }
  
  .toc-toggle {
    padding: 1rem;
    margin-right: 1rem;
  }
  
  /*pagination*/
  #pagination {
    background-color: #171717;
    position: absolute;
    bottom: 0;
    width: 100%;
    box-sizing: border-box;
    margin: 0 auto;
    padding: 1rem;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: #ffffff;
  }
  
  #pagination a {
    border-bottom: 2px solid #171717;
    padding-bottom: calc(1.5rem/6);
    text-decoration: none;
    color: #9e9ea1;
  }
  
  #pagination a:hover {
    border-bottom: 2px solid #ffffff;
    color: #ffffff;
    padding-bottom: calc(1.5rem/6);
  }
  
  #prev {
    text-align: left;
    float: left;
  }
  
  #next {
    text-align: right;
    float: right;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;head&gt;
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdn.jsdelivr.net/npm/epubjs@0.3.83/dist/epub.min.js"&gt;&lt;/script&gt;
  &lt;/head&gt;
  
  &lt;div id="test1"&gt;
  &lt;/div&gt;
  
  &lt;div class="container"&gt;
  
    &lt;div id="toc-container"&gt;
      &lt;div class="table-of-contents"&gt;
        &lt;div class="toc-toggle"&gt;
          &lt;span&gt;Table of contents&lt;/span&gt;
        &lt;/div&gt;
        &lt;div id="navigation" class="toc-list"&gt;
          &lt;div id="toc"&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  
    &lt;div id="main" class=""&gt;
      &lt;div id="viewer" class=""&gt;&lt;/div&gt;
    &lt;/div&gt;
  
    &lt;div id="pagination"&gt;
      &lt;a id="prev" href="#prev" class="arrow"&gt;...&lt;/a&gt;
      &lt;a id="next" href="#next" class="arrow"&gt;...&lt;/a&gt;
    &lt;/div&gt;
  
  
  &lt;/div&gt;
  
  &lt;div id="test2"&gt;
  &lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>
  <p><strong>! The code worked before when I tested it, but when I paste it in here it doesn't. I don't understand. Here's the link to where it works:
  <a href="https://codepen.io/CutePixel/pen/xxZvZOP" rel="nofollow noreferrer">https://codepen.io/CutePixel/pen/xxZvZOP</a></strong></p>