<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Pressbooks posts</title>
	<subtitle>A feed of the latest posts from our blog.</subtitle>
	<link href="https://pressbooks.org/feed.xml" rel="self"/>
	<link href="https://pressbooks.org/"/>
	<updated>2021-07-14T12:00:00Z</updated>
	<id>https://pressbooks.org</id>
	<author>
    <name>Book Oven Inc.</name>
    <email>code@pressbooks.com</email>
	</author>
	
    
    <entry>
      <title>Planned deprecation notice: Pressbooks LTI Provider plugin</title>
      <link href="https://pressbooks.org/blog/2021/07/14/planned-deprecation-notice-pressbooks-lti-provider-plugin/"/>
      <updated>2021-07-14T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2021/07/14/planned-deprecation-notice-pressbooks-lti-provider-plugin/</id>
      <content type="html"><![CDATA[
        <p>IMS Global
<a href="https://www.imsglobal.org/lti-security-announcement-and-deprecation-schedule">recently announced</a>
that they will no longer certify legacy versions of LTI after June 30, 2021. They also
announced that all support for pre-LTI 1.3 versions will end on June 30, 2022.</p>
<p>Due to this specification being retired, we will be discontinuing active development of
our
<a href="https://github.com/pressbooks/pressbooks-lti-provider">Pressbooks LTI Provider plugin</a>
and archiving the repository. Like other plugins and themes that we have previously
archived, this repository will remain publicly available in read-only mode, though we will
be unable to provide support for users who wish to maintain or extend the project.</p>
<p>For our enterprise Pressbooks clients, we have developed and maintain an
<a href="https://site.imsglobal.org/certifications/pressbooks/pressbooks-lti-13">IMS Global certified</a>
replacement plugin, which supports the LTI 1.3 specification as well as the Assignment and
Grade Services extension. We call this product
<a href="https://pressbooks.com/our-products/#:~:text=Pressbooks%20Results%20for%20LMS">'Pressbooks Results for LMS'</a>.
It is currently available as an optional add-on for our enterprise clients. For more
information, please <a href="https://pressbooks.com/contact-pressbooks/">contact our sales team</a>
directly.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Planned Deprecation Notice: MOBI exports</title>
      <link href="https://pressbooks.org/blog/2021/07/14/planned-deprecation-notice-mobi-exports/"/>
      <updated>2021-07-14T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2021/07/14/planned-deprecation-notice-mobi-exports/</id>
      <content type="html"><![CDATA[
        <p>Last year, Amazon announced that they were
<a href="https://goodereader.com/blog/kindle/amazon-discontinues-kindlegen">discontinuing their KindleGen command line tool</a>
that Pressbooks uses to generate MOBI files, and Amazon
<a href="https://www.amazon.com/gp/feature.html?ie=UTF8&amp;docId=1000765211">recommended</a> that users
use EPUB format for publishing new reflowable titles and updating previously published
titles in the Kindle ecosystem.</p>
<p>Because the tool we use to generate MOBI files is no longer supported, and Amazon suggests
delivering EPUBs into their ecosystem, we have decided to remove support for MOBI exports
from the Pressbooks platform in a forthcoming release.</p>
<p>Going forward, our flowable ebook export efforts will focus exclusively on the EPUB
format. Users who still wish to produce MOBI files for personal use will be encouraged to
generate these files using Pressbooks EPUB exports and freely available desktop
applications like
<a href="https://www.amazon.com/gp/feature.html?ie=UTF8&amp;docId=1000765261">Kindle Previewer</a> or
<a href="https://manual.calibre-ebook.com/conversion.html">Calibre</a>.</p>
<p>If you're interested in tracking the progress of this task, please see this GitHub issue:
https://github.com/pressbooks/pressbooks/issues/2193</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>New time, format, &amp; title for monthly Open Source Calls</title>
      <link href="https://pressbooks.org/blog/2020/03/23/new-time-format-and-title-for-monthly-open-source-calls/"/>
      <updated>2020-03-23T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2020/03/23/new-time-format-and-title-for-monthly-open-source-calls/</id>
      <content type="html"><![CDATA[
        <p>Hi all,</p>
<p>The monthly &quot;open source calls&quot; we previously held on the first Monday of each month are
being replaced by a monthly &quot;product update webinar.&quot; These product update meetings will
be held from 2-3pm ET on the last Thursday of each month; the first of them will be this
Thursday, March 26. These meetings have <a href="https://docs.google.com/document/d/1BcvX0V-iDi6fJO_W8pHVOL_lec_9OTXujAfw6tFpZlQ/edit?usp=sharing">a running agenda which includes the Zoom link</a>. A
recurring event for these meetings has been published to
<a href="https://calendar.google.com/event?action=TEMPLATE&amp;tmeid=N3BqbXBsbTRhMW1pMmVlbDNnYWRmNDVvN2tfMjAyMDAzMjZUMTgwMDAwWiBzdGVlbEBwcmVzc2Jvb2tzLmNvbQ&amp;tmsrc=steel%40pressbooks.com&amp;scp=ALL">Google Calendar</a>.</p>
<p>Meetings will include a demonstration of recent improvements we've released and overview
of projects that we're currently working on. We’ll also leave conversation space for
attendees to share news and updates about local development projects of interest, and to
provide input on your Pressbooks-related product needs and desires.</p>
<p>The March 26 webinar will include an update on recent progress we've made on two
long-awaited projects: 1) a searchable, filterable directory of public books across all
known Pressbooks networks and 2) updates to our LTI provider plugin to make it compatible
with the new 1.3 specification and add support for grade passback to the Learning
Management System.</p>
<p>Hope to see you later this week!</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Font Selector Theme Option</title>
      <link href="https://pressbooks.org/blog/2019/09/24/font-selector-theme-option/"/>
      <updated>2019-09-24T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2019/09/24/font-selector-theme-option/</id>
      <content type="html"><![CDATA[
        <p>When users think about picking the right theme for the book they've written with
Pressbooks, they sometimes face difficult choices. They may like the overall design and
aesthetic of a given theme, but want to use a typeface that they've seen in a different
theme, or which isn't currently part of any of supported themes. They may also have
different typeface preferences for webbooks and their ebook or PDF (print) exports.</p>
<p>A less enlightened developer might have just laughed out loud and said 'Too bad! We can't
have amateurs ruining our beautiful books with their questionable typography choices, now
can we?' Luckily for me, I work with people (like Taylor McGrath) who believe that the
best designers and developers listen to and respond to their users. And for some time now,
Taylor and others on our support team have heard from users who'd like to have more
control over typography and font choices when theming their books.</p>
<p>Enter what we're calling 'Shape Shifter': a nerdy code name for theme options that allows
book administrators to choose typefaces from a curated list of open fonts for Headers and
Body text. These font selector options are designed to function separately for webbooks,
PDF exports, and ebooks so that users could for example choose to use Alegreya (a serif
typeface) for the body text in PDF exports and Barlow (a sans serif typeface) for the body
text in the webook.</p>
<p><a href="https://github.com/orgs/pressbooks/projects/43">In the current sprint</a>, we added the code
to do this in <a href="https://github.com/pressbooks/pressbooks/pull/1792">Pressbooks</a> and
<a href="https://github.com/pressbooks/pressbooks-book/pull/602">McLuhan</a>. Next week, we're
rolling out the fully-baked feature for our EDU customers in a new premium theme called
Malala, where we'll test and get user feedback before deciding whether to add these theme
options to other of our themes. Open source users get ... this blog post!</p>
<p>Developers who want to take advantage of this feature need to convert their
<a href="https://github.com/pressbooks/pressbooks/blob/dev/inc/class-globaltypography.php">Global Typography</a>
SCSS.</p>
<p>Here's how it could be done for
<a href="https://github.com/pressbooks/pressbooks-clarke/blob/8a87708bd9a8be712e3dcba39007eeac2f5cb8cb/assets/styles/web/_fonts.scss#L1">Clarke</a>, one of our existing open-source book themes.</p>
<p>Before:</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@import</span> <span class="token string">"font-stack-web"</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$serif-web</span></span><span class="token punctuation">:</span> serif <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$sans-serif-web</span></span><span class="token punctuation">:</span> sans-serif <span class="token statement keyword">!default</span><span class="token punctuation">;</span>

<span class="token property"><span class="token variable">$font-1</span></span><span class="token punctuation">:</span> <span class="token string">"Times New Roman"</span><span class="token punctuation">,</span> Georgia<span class="token punctuation">,</span> <span class="token variable">$serif-web</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-2</span></span><span class="token punctuation">:</span> Helvetica<span class="token punctuation">,</span> Arial<span class="token punctuation">,</span> <span class="token variable">$sans-serif-web</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-3</span></span><span class="token punctuation">:</span> <span class="token variable">$font-2</span><span class="token punctuation">;</span></code></pre>
<p>After:</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Load dynamically generated Global Typography fonts</span>
<span class="token keyword">@import</span> <span class="token string">"font-stack-web"</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$serif-web</span></span><span class="token punctuation">:</span> serif <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$sans-serif-web</span></span><span class="token punctuation">:</span> sans-serif <span class="token statement keyword">!default</span><span class="token punctuation">;</span>

<span class="token comment">// Load Shape Shifter fonts, if any.</span>
<span class="token keyword">@import</span> <span class="token string">"shapeshifter-font-stack-web"</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$shapeshifter-font-1-is-serif</span></span><span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$shapeshifter-font-2-is-serif</span></span><span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token statement keyword">!default</span><span class="token punctuation">;</span>

<span class="token comment">// Insert custom fonts for your theme into the font stacks below. Always end the</span>
<span class="token comment">// stack with $serif-web or $sans-serif-web, as appropriate—this allows custom</span>
<span class="token comment">// language support to be added dynamically.</span>

<span class="token keyword">@if</span> <span class="token function">variable-exists</span><span class="token punctuation">(</span>shapeshifter-font-1<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$font-1</span></span><span class="token punctuation">:</span> <span class="token variable">$shapeshifter-font-1</span><span class="token punctuation">,</span> <span class="token function">if</span><span class="token punctuation">(</span><span class="token variable">$shapeshifter-font-1-is-serif</span><span class="token punctuation">,</span> <span class="token variable">$serif-web</span><span class="token punctuation">,</span> <span class="token variable">$sans-serif-web</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">@else</span> <span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$font-1</span></span><span class="token punctuation">:</span> <span class="token string">"Times New Roman"</span><span class="token punctuation">,</span> Georgia<span class="token punctuation">,</span> <span class="token variable">$serif-web</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">@if</span> <span class="token function">variable-exists</span><span class="token punctuation">(</span>shapeshifter-font-2<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$font-2</span></span><span class="token punctuation">:</span> <span class="token variable">$shapeshifter-font-2</span><span class="token punctuation">,</span> <span class="token function">if</span><span class="token punctuation">(</span><span class="token variable">$shapeshifter-font-2-is-serif</span><span class="token punctuation">,</span> <span class="token variable">$serif-web</span><span class="token punctuation">,</span> <span class="token variable">$sans-serif-web</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">@else</span> <span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$font-2</span></span><span class="token punctuation">:</span> Helvetica<span class="token punctuation">,</span> Arial<span class="token punctuation">,</span> <span class="token variable">$sans-serif-web</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token property"><span class="token variable">$font-3</span></span><span class="token punctuation">:</span> <span class="token variable">$font-2</span><span class="token punctuation">;</span></code></pre>
<p>Make changes like the above to:</p>
<ul>
<li><code>assets/styles/epub/_fonts.scss</code></li>
<li><code>assets/styles/epub/_fonts.scss</code></li>
<li><code>assets/styles/prince/_fonts.scss</code></li>
</ul>
<p>Pay special attention to variable names <em>(replace
$sans-serif-web to $sans-serif-epub or
$sans-serif-prince, for example)</em> If you have
<code>@import</code> statements move them from the bottom of the file into the <code>else</code> conditions.</p>
<p>To finish, add this code snippet in your theme's <code>functions.php</code> file:</p>
<pre class="language-php"><code class="language-php"><span class="token function">add_filter</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'pb_is_shape_shifter_compatible'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'__return_true'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Once activated, the theme should have new Theme Options for each format:</p>
<p><img src="/images/Shape-Shifter-Feature.png" alt="Shape Shifter Feature"></p>
<blockquote>
<p>&quot;<a href="https://www.zeldman.com/2015/12/24/the-year-in-design/">90 percent of design is typography. And the other 90 percent is whitespace</a>&quot;</p>
</blockquote>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Pressbooks 2018: The Year in Review, part 2</title>
      <link href="https://pressbooks.org/blog/2019/01/16/pressbooks-2018-the-year-in-review-part-2/"/>
      <updated>2019-01-16T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2019/01/16/pressbooks-2018-the-year-in-review-part-2/</id>
      <content type="html"><![CDATA[
        <p>In a
<a href="https://pressbooks.education/news/2019/01/pressbooks-2018-the-year-in-review-part-1/">previous post</a>,
I took a look at the year in review for the Pressbooks community (the people who make and
use our software). In this post, I’ll take a closer look as Pressbooks as a product,
covering some of the exciting changes and developments to our software made in 2018 by our
hard-working developers and generous contributors.</p>
<p>On January 1, 2018, Pressbooks software was the following:</p>
<ol>
<li>Pressbooks (our core plugin): version 4.5.0</li>
<li>Pressbooks default book theme: pressbooks-book 1.12.0 [Luther]</li>
<li>Pressbooks root theme: Pressbooks Publisher 3.1.3</li>
<li>A handful of smaller plugins, including Pressbooks Stats 1.4.0 and DocRaptor for
Pressbooks 2.1.0</li>
</ol>
<p>Over the course of the year we made major updates to each piece of our core product and
introduced several new tools and plugins. The most significant new releases were our new
Learning Tools Interoperability (LTI) provider and single sign-on (SSO) plugins, designed
to help educational institutions connect their Pressbooks networks with their Learning
Management Systems and enterprise login systems, and Buckram, a set of style components
that makes book theming easier and more powerful.</p>
<p>In 2018, we also made it easier for anyone who wants to get a more granular look at
planned releases and ongoing development work by creating and maintaining GitHub project
boards for the <a href="https://github.com/orgs/pressbooks/projects">project in general</a> and for
versioned releases of specific components like
<a href="https://github.com/pressbooks/pressbooks/projects">Pressbooks</a>,
<a href="https://github.com/pressbooks/pressbooks-book/projects">pressbooks-book</a>
(McLuhan/Buckram), <a href="https://github.com/pressbooks/pressbooks-aldine/projects">Aldine</a>, and
<a href="https://github.com/pressbooks/pressbooks-lti-provider/projects/1">Pressbooks LTI Provider</a>.
These project boards are regularly updated by our dev team to include reference
information about planned and completed releases.</p>
<p>We’re enormously grateful to the various institutions who funded different parts of this
work and for their shared interest in contributing back to an open source product that
benefits the entire community of users. eCampusOntario, Ryerson University, Rutgers
University Libraries and Bay Path University each made significant contributions to our
2018 development work, and Brad Payne and Alex Paredes from BCcampus contributed code to
two big new features that were added to our core product this year. Thank you, all!</p>
<h3 id="pressbooks" tabindex="-1">Pressbooks</h3>
<p>Our core product is Pressbooks, a WordPress plugin that transforms a WordPress multisite
into a powerful book publishing system that makes accessible webbooks and several types of
exports, including ebooks, print-ready PDFs, and various XML flavors.</p>
<p>In 2018 we brought out 25 minor releases and 7 major releases of core Pressbooks
(beginning with Pressbooks 5.0.0 in late February, running all the way up to Pressbooks
5.6.0, released in November). The last version of Pressbooks to be released in 2018 was
5.6.3, which came out on December 12. All told Pressbooks received
<a href="https://github.com/pressbooks/pressbooks/graphs/contributors?from=2018-01-01&amp;to=2018-12-31&amp;type=c">a net addition of more than 16,000 lines of code from humans in 2018</a>,
with ~10,000 coming from Dac (across 161 commits), ~5,000 from Ned (across 322 commits),
~1,600 from BCcampus’ Brad Payne (across 8 commits), and ~100 from Lukas Kaiser (across 3
commits).</p>
<p>So those are the raw numbers. But what do they mean? How did Pressbooks improve over the
last year? Well, in lots of ways. The obsessive among you are welcome to view a detailed
<a href="/docs/changelog/pressbooks/">changelog</a> for a more exhaustive
record of everything we shipped this past year, but the following list is a baker’s dozen
of our favorite improvements from the past year:</p>
<ul>
<li>
<p>Major overhaul to the ‘Organize’ page: We improved the page’s accessibility for keyboard
navigation and screen reader users and its usability when displayed on mobile devices.
We made it easier to manage the visibility of content across web and exports; all
content now has two binary options: “Show in Web” and “Show in Exports.” We also added
book navigation options to the edit screen.</p>
</li>
<li>
<p><strong>Import &amp; Export improvements:</strong> We added support for importing individual chapters
from Pressbooks webbooks and for importing all supported file types from local and
web-based sources. We added
<a href="https://pressbooks.education/news/2018/03/enhanced-interactivity-video-audio-h5p-now-available-in-pressbooks/">graceful fallbacks for interactive content</a>
that can’t be fully experienced in ebook and PDF exports. We enabled the inclusion of
TablePress tables in eBook and PDF exports. We allowed users to produce
<a href="http://oreillymedia.github.io/HTMLBook/">HTMLBook</a> exports, made our XHTML and HTMLBook
outputs cleaner and more readable, and added a link to the diagnostics page which lets
users to preview and debug PDF export issues directly in their browser using the XHTML
source preview without having to repeatedly generate PDF exports.</p>
</li>
<li>
<p><strong>Cloning improvements:</strong> We also built on the book cloning feature (funded by Ryerson
University) and the chapter-cloning feature (funded by eCampus Ontario) with a whole
raft of cloning improvements, like adding a book source URL to Book Info for cloned
books; allowing users to specify a new title for cloned books at the time of cloning;
adding a theme option to let readers compare a clone book to its source; and adding
cloning support for media attachments, media metadata (including attribution
statements), and glossary terms.</p>
</li>
<li>
<p><strong>Glossary tool:</strong> We added a native glossary tool that allows authors to provide
rollover and clickable definitions for glossary terms and to auto-generate a glossary
list as a back matter type in their books. We’re very grateful to Brad Payne and Alex
Paredes of BCcampus for contributing the first version of this feature.</p>
</li>
<li>
<p><strong>Shortcodes for authors:</strong> Thanks to support from Bay Path University, we added
<a href="https://guide.pressbooks.com/chapter/shortcodes/">more than a dozen new shortcodes</a>
that work in both the visual editor and in document imports. These shortcodes make it
easier for authors to include well-structured HTML elements without having to learn
HTML.</p>
</li>
<li>
<p><strong>Interactive and other third party content:</strong> We added
<a href="https://guide.pressbooks.com/chapter/embedded-media-interactive-content/">support for interactive content</a>
(like H5P activities, PhET simulations, Open Embeddable Assessments, Knight Lab
timelines, and eduMedia interactives). We made it so that iframes embedded from trusted
sources were automatically converted to shortcodes rather than being stripped and
deleted. We also disabled the display of related videos in YouTube OEmbeds once videos
are finished playing.</p>
</li>
<li>
<p><strong>Cover generator tool:</strong> We made our
<a href="https://guide.pressbooks.com/chapter/how-to-design-your-book-cover/">self-service cover generator tool</a>
part of our core plugin, making it available to open-source users. This tool makes it
easier for authors to make attractive print-ready covers for their books.</p>
</li>
<li>
<p><strong>LaTeX and Mathematical Notation:</strong> We made it easier for users to use mathematical
notation by improving support for
<a href="https://wordpress.org/plugins/wp-quicklatex/">WP QuickLaTeX</a>, adding support for
QuickLaTeX rendering within TablePress tables, and permitting the use of TablePress
tables and SVG files in ebook formats.</p>
</li>
<li>
<p><strong>Centralized contributor management:</strong> We made it much easier for book admins to manage
and display authors, editors, translators, reviewers, illustrators, and generic
contributors to books. We also moved contributor management from the “Organize” menu to
a more logical place under the “Book Info” menu in the dashboard.</p>
</li>
<li>
<p><strong>Better Textboxes:</strong> We improved the markup and display options for educational
textboxes (learning objectives, key takeaways, exercises, examples) and added a new
“sidebar” textbox that’s especially helpful for textbook content.</p>
</li>
<li>
<p><strong>Licensing and Attribution Improvements:</strong> We moved license types into a taxonomy and
now differentiate between the CC0 license and public domain work. Pressbooks now allows
users to add and display image attribution metadata, making it easier to properly credit
CC and other openly licensed images when they’re reused in book (big thanks to Brad and
Alex from BCcampus for their work on this feature).</p>
</li>
<li>
<p><strong>GDPR Compliance:</strong> We added support for
<a href="https://wordpress.org/news/2018/05/wordpress-4-9-6-privacy-and-maintenance-release/">WordPress 4.9.6 privacy policy management</a>
to help Pressbooks networks comply with the new requirements of The General Data
Protection Regulation (GDPR), a regulation on privacy and data protection now in effect
throughout the European Union.</p>
</li>
<li>
<p><strong>More script and language support:</strong> We added support for the Devanagari script and
several languages, including Bengali, Kannada, Malayalam, Odia, and Telugu, making our
software more inclusive of the millions of people who use this script or these
languages.</p>
</li>
</ul>
<h3 id="pressbooks-default-book-theme" tabindex="-1">Pressbooks Default Book Theme</h3>
<p>At the start of 2018, the default book theme for all Pressbooks networks was Luther (also
known as pressbooks-book 1.12.0 for any version heads out there). When we released
Pressbooks 5.0.0 in late February 2018, it was accompanied by McLuhan, a new book theme.
Upon its release as pressbooks-book 2.0.0, McLuhan replaced Luther as the default theme
for all new books, and Luther subsequently became available as a separate, standalone
legacy theme. The development of McLuhan was supported by eCampus Ontario, and the theme
itself was designed with textbooks in mind, although it supports all kinds of content.</p>
<p>Since its initial appearance, McLuhan has seen more than a dozen additional releases and
is now on version 2.6.1 (interested readers can consult the detailed
<a href="/docs/changelog/pressbooks-book/">changelog</a>). All told the
pressbook-book repo saw
<a href="https://github.com/pressbooks/pressbooks-book/graphs/contributors?from=2018-01-01&amp;to=2018-12-31&amp;type=c">the net addition of more than 80,000 lines of code by humans</a>,
with ~78,000 coming from Ned (across 397 commits), ~3,000 from Daniel (across 59 commits),
and ~200 from Dac (across 19 commits). Of the many improvements we made to the default
book theme in 2018, here are some of the biggest highlights:</p>
<ul>
<li>
<ul>
<li><strong>Support for new features:</strong> We added support in this theme for a number of new
features now available in Pressbooks, including: an increased default webbook reading
width and three new variable reading width options; collapsible sections; automatic
resizing of webbook contents when the Hypothesis annotation pane is expended; optional
lightbox for linked images; book and section Digital Object Identifiers (DOIs);
glossary term lists; automatic graceful fallback for interactive content in ebook and
PDF exports; and differentiated link styles for print and digital PDFs.
<ul>
<li><strong>Accessibility improvements:</strong> Thanks to support from Ryerson University, we added
a keyboard-accessible table of contents and customizable colours and logos
(inherited from network settings). We also improved webbook accessibility by adding
more context to webbook navigation, using better HTML5 markup for images, improving
focus styles, and enhancing the markup for headings and our table of contents.</li>
<li><strong>New theme options:</strong> Book admins now have several
<a href="https://guide.pressbooks.com/chapter/new-theme-options/">new theme options</a> for
customizing the appearance and functionality of their webbooks as well as eBook and
PDF exports. These additional theme options are currently only available in the 8
themes we’ve converted to use Buckram (more on that later).</li>
<li><strong>Better navigation:</strong> We made webbook navigation consistent on all screen sizes,
allowed authors to customize part/chapter labels in the webbook display and in
exports, and now display more descriptive labels and/or chapter short titles in
previous/next nav links.</li>
<li><strong>Table of Contents improvements:</strong> Books now indicate the current section in the
dropdown ToC. We also added  &quot;Show All&quot;/&quot;Hide All&quot; buttons to the webbook ToC, and
improved the appearance and overall functionality of ToC in all locations.</li>
<li><strong>New features for cloned books:</strong> Cloned books include a reference and link back to
their source and an optional comparison tool that lets you compare current versions
of cloned and source texts.</li>
<li><strong>LMS-specific theming:</strong> We also added settings which allow extraneous navigational
elements to be suppressed when content is loaded via LTI within a Learning
Management System (as these typically have their own internal navigation).</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="pressbooks-root-theme" tabindex="-1">Pressbooks Root Theme</h3>
<p>In late February, we replaced Pressbooks Publisher with a new Pressbooks root theme,
called Aldine. Aldine’s creation was one of the major improvements supported by Ryerson
University. Since its initial appearance, Aldine has seen an additional eight releases and
is now on version 1.5.0 (interested readers can consult the
<a href="/docs/changelog/pressbooks-aldine/">changelog</a>).</p>
<p>Aldine was designed to make customizing the look and feel of Pressbooks networks easier.
It gives network managers tools to add institutional branding to a Pressbooks network by
letting them globally change default colors, logos and contact information for a network,
introduces a standalone catalog page which can be sorted, filtered, and searched by
subject or license, and makes it much easier to create and display additional pages to the
network root (like “About Us,” “Get Help,” “Terms of Service,” etc.).</p>
<p>Following its initial release, we’ve added specific buttons to the page editor to insert
shortcodes for page sections and calls to action; added more customizer options; made it
possible to edit the contact form email directly from the Customizer; and made privacy and
anti-spamming improvements.</p>
<h3 id="other-plugins" tabindex="-1">Other Plugins</h3>
<p>We made a few <a href="/docs/changelog/pressbooks-stats/">minor updates</a> to
the small <a href="https://github.com/pressbooks/pressbooks-stats">Pressbooks Stats</a> plugin, with
<a href="/blog/2019/01/04/q1-roadmap-preview/">some bigger work planned for early 2019</a>
(‘improving usage statistics at the network level’ refers to ongoing efforts to give
network managers better tools for understanding how their networks are being used). The
current version of Pressbooks Stats is now 1.6.2.</p>
<p>At the beginning of 2018, we also maintained a plugin which implemented a DocRaptor export
module for Pressbooks as a drop-in replacement for PrinceXML. This standalone plugin
<a href="https://github.com/pressbooks/pressbooks/issues/1238">was rolled into Pressbooks core</a>
with the release of Pressbooks 5.4.0 in July, and we are no longer maintaining the
standalone plugin separately.</p>
<h2 id="new-development" tabindex="-1">New Development</h2>
<h3 id="lti-provider-plugin" tabindex="-1">LTI Provider plugin</h3>
<p>In May, we released a stable version of
<a href="https://github.com/pressbooks/pressbooks-lti-provider">Pressbooks LTI Provider</a>, thanks
to support from Rutgers University Libraries. This plugin allows Pressbooks to act as an
LTI provider, registering any number of LTI consumers, and supports both deep linking and
the creation of Thin Common Cartridge exports with LTI links. LTI, which is short for
Learning Tools Interoperability, is a specification maintained by IMS Global which allows
third-party tools (like Pressbooks) to integrate with Learning Management Systems (like
Canvas, Moodle, and Blackboard) in a standardized way. Using LTI makes it easier and more
convenient for schools to securely plug learning tools and content into their LMS and make
those tools and content feel native/seamless for learners.</p>
<p>In late 2017, while still employed at UW-Madison,
<a href="https://medium.com/@steelwagstaff/connecting-pressbooks-to-canvas-4e0a33c65740">I wrote in more detail about why I was so excited about using LTI to connect Pressbooks with LMSes</a>.
Much of what I wrote then still rings true for me today. In my opinion, our LTI Provider
plugin is a hugely exciting feature for anyone interested in using Pressbooks content
inside of a Learning Management System (a common desire for teachers, both in K-12 and
higher ed settings). Our plugin is now on version 1.1.2, released in November
(<a href="/docs/changelog/pressbooks-lti-provider/">changelog</a>). In Q1 2019,
we plan to pursue official IMS Global certification against both the LTI and Thin Common
Cartridge standards.</p>
<h3 id="sso-plugins" tabindex="-1">SSO plugins</h3>
<p>In 2018 we also developed and released two plugins that enable single sign-on for common
authentication systems used in higher education. These integrations allow log in to
Pressbooks networks using using their institutional NetID and password as login
credentials (authenticating through either CAS or SAML2).</p>
<ul>
<li>In May, we released the stable version of
<a href="https://github.com/pressbooks/pressbooks-cas-sso">our SSO plugin for CAS</a> (Central
Authentication System). Our work on this plugin was funded by Rutgers University
Libraries. This plugin is now on version 1.1.1.</li>
<li>In late July, we also released the initial version of
<a href="https://github.com/pressbooks/pressbooks-shibboleth-sso">our SSO plugin for SAML2 (Shibboleth)</a>.
This plugin is now on version 0.0.5.</li>
</ul>
<p>These SSO plugins are now available on Gold PressbooksEDU networks with a one-time
configuration fee.</p>
<h3 id="buckram" tabindex="-1">Buckram</h3>
<p>In April, our lead developer Ned Zimmerman published a helpful introduction to
<a href="/blog/2018/04/09/book-themes-part-1-frames-and-pictures/">Pressbooks themes</a> on our open
source blog, and in July he did the same for
<a href="/blog/2018/07/03/book-themes-part-2-whats-buckram/">Buckram</a>, “a set of styled components
for book theming, with corresponding markup, that can be customized with SASS variables,”
which we released in an initial stable version that same month.</p>
<p>While it’s largely invisible to most end users, the work we did in 2018 to develop and
release Buckram is important because it is provides the foundation for some really
exciting theming and customization possibilities for Pressbooks. Buckram is what enabled
all of the new theme options that we introduced in
<a href="https://github.com/pressbooks/pressbooks-clarke/releases/tag/2.0.0">Clarke 2.0</a>, for
example. In 2018, we converted a
<a href="https://guide.pressbooks.com/chapter/new-theme-options/">batch</a> of Pressbooks themes to
use Buckram [Andreessen, Asimov, Jacobs, McLuhan, Andreesen, Dillard, Christie, and
Baker], and development work on Buckram continues apace (it’s now at version 1.2.1), with
many more theme conversions planned for 2019.</p>
<p>In the course of researching and writing this two part series, my already considerable
esteem for my new Pressbooks colleagues grew enormously. I hope that you’ll agree that
2018 saw really significant improvements in Pressbooks as a software product and a
community. If you want to know more about what we’ve got planned for the first few months
of 2019, we’d invite you to take a look at our
<a href="https://pressbooks.education/news/2019/01/pressbooks-2019-q1-roadmap/">published Q1 roadmap</a>
and give us your <a href="mailto:support@pressbooks.com">feedback</a>.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Pressbooks 2018: The Year in Review, part 1</title>
      <link href="https://pressbooks.org/blog/2019/01/14/pressbooks-2018-the-year-in-review-part-1/"/>
      <updated>2019-01-14T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2019/01/14/pressbooks-2018-the-year-in-review-part-1/</id>
      <content type="html"><![CDATA[
        <p>When others ask me what Pressbooks is, I often say that it’s two things: 1) terrific
open-source book publishing software and 2) the people who make, use, and care about that
software. If there’s still time and interest, I go on to explain that Pressbooks is a
collection of open-source software components, largely built on top of the WordPress
Content Management System, that gives authors, teachers, publishers, and educational
institutions a powerful and relatively easy-to-use book publishing system. Pressbooks is
also the small team of employees that makes and supports Pressbooks software and a larger
global community of contributors, users, and backers who collectively give our software
life.</p>
<p>In a series of two posts I want to talk about what 2018 meant for Pressbooks, looking at
both the software product and the human community that shapes and sustains that product.
I’ll talk about the people first, well, because that’s how we try to do things.</p>
<h2 id="the-people" tabindex="-1">The People</h2>
<p>2018 was an exciting year for for Pressbooks and brought with it some pretty dramatic
changes. Nothing makes this more obvious than a closer look at the people making and
supporting Pressbooks. At the beginning of 2018, Pressbooks had two people working on the
project full time (our developers Ned &amp; Dac) and another four (Hugh, Liz, Zoe, Apurva) who
split their time between Pressbooks and other projects. Throughout 2018, our team grew,
matured, and specialized in response to the needs of our user communities.</p>
<h3 id="departures" tabindex="-1">Departures</h3>
<p>In June, the Rebus Foundation (a non-profit organization founded by Pressbooks CEO Hugh
McGuire), received
<a href="https://www.mellon.org/grants/grants-database/grants/rebus-foundation/1801-05258/">a large Mellon Foundation grant to develop a web-based application for digital reading, research, annotations, and collections management</a>.
This change in Rebus’s fortunes meant that Zoe Wake Hyde and Apurva Ashok, two colleagues
who had been splitting time between Rebus and Pressbooks, left Pressbooks to devote their
energies full time to Rebus work. Midway through 2018, Pressbooks bid Zoe and Apurva a
fond farewell. All of us working on Pressbooks continue to wish them well as they advance
Rebus’s efforts to build a
<a href="https://about.rebus.community/">vibrant community of collaborators on open textbook projects</a>;
resources, best practices and software to support that community’s open publishing
efforts; and a <a href="https://rebus.foundation/projects/">better scholarly reading ecosystem</a>.</p>
<h3 id="a-growing-pressbooks-team" tabindex="-1">A growing Pressbooks team</h3>
<p>Early in 2018, Pressbooks
<a href="https://pressbooks.com/blog/meet-new-pressbooks-team-members-daniel-jc-and-phil/">added three new team members</a>:
JC Guan, our first official product manager; Daniel Fernandes, who spent most of the year
improving our existing web themes; and Phil Nelson, who had previously worked with
Pressbooks as a contractor but began managing DevOps, systems administration, and
infrastructure issues for our SaaS hosting offerings in a more formal capacity.</p>
<p>In 2018, Pressbooks also brought Liz Mays into a full-time role as our director of sales
and marketing (she had previously been splitting her time between Rebus and Pressbooks)
and welcomed Taylor McGrath to our team, first as an intern and later as a full-time
communications and support specialist. Finally, in November,
<a href="https://pressbooks.education/news/2018/10/welcome-steel-wagstaff-pressbooksedu-client-manager/">I joined the team as our first educational client manager</a>,
with a specific mandate to support our growing base of educational clients using
Pressbooks as a platform for open education and open textbook initiatives.</p>
<p>Much of this change in staffing was undertaken in response to our growing base of
educational clients and their desire to use Pressbooks networks to develop open
educational resources in a variety of modalities and deliver them at no cost to students.
While Pressbooks began as and remains an excellent tool for individual authors to
<a href="https://pressbooks.com/">self-publish their own books</a>, we’ve been gratified to see our
<a href="https://pressbooks.education/pressbooksedu-plans/">SaaS hosted platform for educational institutions (PressbooksEDU)</a>
become a popular choice for colleges and universities around the world who are interested
in developing and publishing open educational resources. By the end of 2018, we were
thrilled to be hosting standalone PressbooksEDU networks for more than forty colleges and
universities in North America and Australia.</p>
<h3 id="pressbooks-edu-news" tabindex="-1">PressbooksEDU News</h3>
<p>Along with growth in the number of educational institutions using Pressbooks to support
their publishing initiatives and a corresponding growth in Pressbooks staff to support
them, 2018 also saw invigoration of our
<a href="https://pressbooks.education/news/">PressbooksEDU news blog</a>. Our EDU-focused blog
averaged a new post every two weeks in 2018, focusing primarily on an audience of
educational users and network managers of hosted EDU networks. Over the past year, Liz and
Taylor used the blog to draw attention to educational uses for new Pressbooks features and
provide a detailed glimpse into how Pressbooks has been used in OER publishing efforts
undertaken by a
<a href="https://pressbooks.education/news/2018/03/tim-craigs-cool-japan-finds-success-as-textbook/">retired professor</a>,
the
<a href="https://pressbooks.education/news/2018/09/university-of-florida-looks-to-expand-open-textbook-initiatives/">University of Florida</a>,
the
<a href="https://pressbooks.education/news/2018/08/uw-madison-pressbooksedu-instance-supports-70-open-publishing-projects/">University of Wisconsin-Madison</a>,
the
<a href="https://pressbooks.education/news/2018/08/the-ohio-state-university-has-60-books-in-development-as-part-of-textbook-affordability-initiative/">Ohio State University</a>,
the
<a href="https://pressbooks.education/news/2018/08/university-of-texas-at-arlington-kicks-off-oer-program-with-eight-books-in-development/">University of Texas at Arlington</a>,
the
<a href="https://pressbooks.education/news/2018/09/university-of-minnesota-publishes-research-on-affordable-content/">University of Minnesota</a>,
and the
<a href="https://pressbooks.education/news/2018/10/pressbooks-is-backbone-for-nascent-oer-efforts-at-university-of-central-florida/">University of Central Florida</a>.</p>
<p>The story from 2018 that we’re most proud of at Pressbooks, though,
<a href="https://pressbooks.education/news/2018/03/open-textbook-built-on-pressbooks-wins-open-education-award/">was the announcement in March</a>
that
<a href="https://press.rebus.community/makingopentextbookswithstudents/">A Guide to Making Open Textbooks with Students</a>,
a collaboratively-built resource edited by our very own Liz Mays, had won
<a href="https://www.oeconsortium.org/projects/open-education-awards-for-excellence/2018-winners-of-oe-awards/2018-oe-award-winners-resources-tools-practices/">the 2018 Open Education Award for Excellence in the Open Textbook category</a>
from an international panel of judges at the Open Educational Consortium. A Guide to
Making Open Textbooks with Students was originally published by Rebus Community using
Pressbooks in August 2017 under the CC-BY 4.0 license, but continued to
<a href="https://press.rebus.community/makingopentextbookswithstudents/back-matter/as-seen-in/">attract attention and praise</a>
throughout 2018.</p>
<p>We’ve got another series of case studies and feature updates planned for 2019, and are
really excited to continue learning from and sharing the successes of our educational
users. One of my biggest goals for 2019 will be establishing community resources and
venues that meet the needs of network managers and our educational clients. Stay tuned for
more news on this in the first half of 2019.</p>
<h3 id="support" tabindex="-1">Support</h3>
<p>No matter how easy to use its makers think a piece of software is, everyone who’s ever
been involved in learning a new program will tell you that end users often need help and
support. Pressbooks is no exception. While we work hard to make our
<a href="/blog/2018/05/01/our-accessibility-policy-and-forthcoming-accessibility-improvements/">software accessible</a>
and accompany it with <a href="/docs/">clear technical documentation</a> and
helpful <a href="https://guide.pressbooks.com/">user guides</a>, we still get a lot of support
requests from our Pressbooks.com and PressbooksEDU offerings. In 2018, for example,
Pressbooks staff received and responded to nearly 3,500 support requests. When it came to
client support, Taylor, Liz, Apurva, and JC led the way in 2018, each resolving hundreds
of support tickets.</p>
<p>In fact, most of the Pressbooks staffing changes in 2018 were made to ensure that we could
continue to provide best-in-class support for our clients. To that end, Taylor overhauled
and improved our
<a href="https://pressbooks.groovehq.com/help_center">Knowledge Base/FAQ documentation</a> and
<a href="https://guide.pressbooks.com/">Pressbooks user guide</a> and published and now maintains
<a href="https://networkmanagerguide.pressbooks.com/">a new guide explicitly for network managers</a>.
JC, Taylor and I also provided personalized training and support for dozens of network
managers at client institutions throughout the year, a responsibility that I’m looking
forward to continuing in 2019. In late November, Taylor and I also began offering
regularly recorded webinars for our EDU clients highlighting how users can leverage new
features to do more with Pressbooks; we held
<a href="https://www.youtube.com/watch?v=1nS5btUI9ek">the first webinar</a> in the series to
accompany the release of Pressbooks 5.6.0.</p>
<p>Because I joined the team specifically to help educational clients succeed with their OER
and other publishing efforts, my top priority for this year is to better understand the
needs of our growing educational user base and to provide even more ways for PressbooksEDU
network managers to engage with us, our software, and each other. Before making any
specific plans, my first order of business is to conduct a thorough ‘listening tour’ of
all of our existing educational clients so that I can better understand what their hopes,
needs, and ambitions are. Over the next few months we will begin synthesizing responses
and formulating new approaches and support tools that meet common needs.</p>
<h3 id="forum-improvements" tabindex="-1">Forum Improvements</h3>
<p>Some of these changes are already underway in our open source and developer community. For
example, in September 2018, we decided to close our open source Slack channel and focus
our open source community efforts on the
<a href="https://pressbooks.community/">public Discourse forum</a>, which we’ve been operating
since early 2016. We now hold our monthly open source development calls (these are open to
all!) in Zoom rather than Slack, and post regular public updates about development and
upcoming calls on our <a href="/blog/">open source blog</a> and in the
<a href="https://pressbooks.community/c/development">Development category</a> of Discourse.</p>
<p>Our Discourse forum continued to flourish as a place for Pressbooks developers and other
users to ask technical questions of each other. 2018 saw the addition of more than 60 new
members, 340 new topics and 1,400 new posts, such that the forum now contains over 100
members, nearly 600 topics and almost 2,800 posts.</p>
<p>The most popular posts from 2018 in our community forum included
<a href="https://pressbooks.community/t/pressbooks-5-developer-guide/335">a post Ned made about the developer’s guide to accompany the release of Pressbooks 5.0</a>
and inquiries from Pressbooks users on topics ranging from
<a href="https://pressbooks.community/t/importing-content-into-pressbooks/347">importing content into Pressbooks</a>,
<a href="https://pressbooks.community/t/troubleshooting-princexml/445">PrinceXML</a>,
<a href="https://pressbooks.community/t/import-xml-stripping-embedded-content/423">iFrames and oEmbed customization</a>,
<a href="https://pressbooks.community/t/theme-book-sugestions/391">book theming</a>,
<a href="https://pressbooks.community/t/automatic-line-numbering/369/6">automatic line numbering</a>,
and
<a href="https://pressbooks.community/t/watermarks-and-user-restrictions/467">watermarks and DocRaptor exports</a>.</p>
<p>Working on an open source software project means that questions come in all the time on
surprising topics and unexpected use cases. Observing and responding to these forum
interactions over the last year helped us better understand our own software and its
users, catch and fix bugs, and make more useful software. We’re grateful to everyone who
engaged with us in 2018, and look forward to another year filled with rich, positive
engagement with developers and other contributors.</p>
<p>Whether you’re an old hand or are new to Pressbooks and looking for
<a href="/get-involved/">a way to get involved</a> in contributing to the open source project, we
hope that you will feel welcomed and valued in our forum, and that you will treat others
with kindness and respect. If you have any feedback for us on how we can make
participating easier or more inclusive for you or others who might want to participate,
please let us know by sending Ned and/or Steel a private message on the forum or by
sending a Twitter DM to @pressbooksdev.</p>
<h4 id="git-hub-ideas-forum" tabindex="-1">GitHub Ideas Forum</h4>
<p>In March, our development team created a dedicated
<a href="https://github.com/pressbooks/ideas">Ideas forum</a> and connected
<a href="https://github.com/pressbooks/ideas/projects/1">Ideas board</a> on GitHub for users to
submit development ideas and suggestions for the Pressbooks team. Since then, we’ve
received more than 150 unique ideas from almost 20 contributors (including the author of
this post). We’ve already added several of these suggestions to our core product, with
plans to address many more in 2019.</p>
<p>If you’ve got an idea for something that you think would make Pressbooks better in 2019,
we encourage you to share it with us in this Ideas forum, which features a basic template
asking you to provide a feature description, use case, and any other notes that might help
us in evaluating or implementing your idea. If you’re new to GitHub, we recommend starting
with this
<a href="https://opensource.guide/how-to-contribute/#how-to-submit-a-contribution">guide to submitting contributions to open source software projects</a>
or this <a href="https://guides.github.com/features/issues/">guide to GitHub issues</a>.</p>
<h4 id="git-hub-snippets" tabindex="-1">GitHub Snippets</h4>
<p>A the same time we established the GitHub ideas forum, our dev team also created a
<a href="https://github.com/pressbooks/snippets/">GitHub repository to house useful code snippets</a>
for others working on/with Pressbooks. It’s currently a little-known and under-used
resource, but we hope that by highlighting it here, interested community members might add
useful snippets of their own more frequently in 2019.</p>
<p>At this point, I’m beginning to verge into product territory, so it’s probably a good
stopping point for now. Keep an eye out for part two of our Pressbooks 2018: Year in
Review, which will review highlights from our development work on Pressbooks software, in
the near future.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Q1 Roadmap Preview</title>
      <link href="https://pressbooks.org/blog/2019/01/04/q1-roadmap-preview/"/>
      <updated>2019-01-04T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2019/01/04/q1-roadmap-preview/</id>
      <content type="html"><![CDATA[
        <p>In December, the Pressbooks team spent some time planning our roadmap for Q1 2019. We've
got some exciting projects planned for the next few months. Here's some of what we'll be
working on:</p>
<ul>
<li>Rebuilding the Export page with progress indicators during exports, improved management
of export files, and full keyboard accessibility</li>
<li>Adding progress indicators to Clone and Import pages</li>
<li>Adding <a href="https://orcid.org/">ORCID</a> support for contributors</li>
<li>Improving support for books with editors or translators as primary contributors</li>
<li>Adding support for cloning <a href="https://h5p.org">H5P</a> content</li>
<li>Adding metadata to webbooks to make it easier to cite them with
<a href="https://www.zotero.org/">Zotero</a></li>
<li>Adding <a href="https://json-ld.org/">JSON-LD</a> metadata to webbooks</li>
<li>Adding a central database table of book metadata to Pressbooks networks to improve the
performance of our <code>/books</code> API endpoint and tools that use it</li>
<li>Improving the functionality of the network catalog</li>
<li>Improving usage statistics at the network level</li>
<li>Adding the ability for network managers to set some default theme options at the network
level</li>
<li>Exploring direct importing of Google Docs</li>
<li>Pursuing official certification for our LTI Provider plugin</li>
</ul>
<p>These are our big projects; as always, we'll continue to refine and improve Pressbooks in
smaller ways in each sprint. If you have any questions we're always happy to discuss! Our
first Open Source call of the year will be on Monday, January 7th at 2pm Eastern. An
agenda and Zoom link will be posted here and on our community forum by Monday morning.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Refactoring Slow Forms Using PHP Generators and Event Streams</title>
      <link href="https://pressbooks.org/blog/2018/11/12/refactoring-slow-forms-using-php-generators-and-event-streams/"/>
      <updated>2018-11-12T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/11/12/refactoring-slow-forms-using-php-generators-and-event-streams/</id>
      <content type="html"><![CDATA[
        <p>The form will still be slow but the user experience will be better. The user will see a
progress bar and see status updates in real time. The idea is to refactor something like
this:</p>
<pre class="language-php"><code class="language-php"><span class="token comment">/**
 * A task that takes way too loooooooooooooooooooooooong...
 */</span>
<span class="token keyword">function</span> <span class="token function-definition function">task</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">step1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">step2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">step3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//</span>
    <span class="token function">step100</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Into this:</p>
<pre class="language-php"><code class="language-php"><span class="token comment">/**
 * Yields a key/value pair
 * The key is between 1-100 and represents percentage completed
 * The value is a string of information for the user
 *
 * @return Generator
 */</span>
<span class="token keyword">function</span> <span class="token function-definition function">taskGenerator</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">step1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">yield</span> <span class="token number">1</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Completed step 1'</span><span class="token punctuation">;</span>
    <span class="token function">step2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">yield</span> <span class="token number">2</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Completed step 2'</span><span class="token punctuation">;</span>
    <span class="token function">step3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">yield</span> <span class="token number">3</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Completed step 3'</span><span class="token punctuation">;</span>
    <span class="token comment">//</span>
    <span class="token function">step100</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">yield</span> <span class="token number">100</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Completed step 100'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/**
 * A task that takes way too loooooooooooooooooooooooong...
 */</span>
<span class="token keyword">function</span> <span class="token function-definition function">task</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">foreach</span> <span class="token punctuation">(</span> <span class="token function">taskGenerator</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token variable">$percentage</span> <span class="token operator">=></span> <span class="token variable">$info</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// Do nothing, this is a compatibility wrapper</span>
        <span class="token comment">// that makes our generator work like a regular function</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>And this:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> evtSource <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">EventSource</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="before" tabindex="-1">Before</h2>
<p>Currently, cloning a book in Pressbooks looks like this:</p>
<!-- TODO: Restore video embed. -->
<p><em>Spinning beach ball of death.</em></p>
<p>The user clicks submit. They wait, and wait, and wait. The task completes and they receive
some feedback saying &quot;everything seems fine&quot;. It's not particularly pleasant but it does
the job. Typical open source WordPress installs, and by extension Pressbooks, don't have
the resources, infrastructure, or competence to setup job queues and delegate these kind
of tasks into the background. Everyone lives with it. The end.</p>
<p>Insert cliché &quot;What if I told you&quot; meme here.</p>
<h2 id="after" tabindex="-1">After</h2>
<p>It is possible to use
<a href="https://php.net/manual/en/language.generators.overview.php">PHP Generators</a> and
<a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource">Event Streams</a> to provide
real-time feedback to the web browser.</p>
<p><a href="/images/EventStreamConsole.png"><img src="/images/EventStreamConsole.png" alt="Screen shot of the EventStream console in Google Chrome."></a></p>
<p><em>The EventStream console in Chrome Browser.</em></p>
<p>With a bit of refactoring cloning a book in Pressbooks, instead, looks like this:</p>
<!-- TODO: Restore video embed. -->
<p><em>A status bar with real-time status updates.</em></p>
<p>The heavy lifting is done by an EventStreams class
(<a href="https://github.com/pressbooks/pressbooks/blob/c1a41cc95cd49780f39d0f9c1a7148a45b56a439/inc/class-eventstreams.php#L50">Source code)</a>.</p>
<p>On the front end, the main changes were from this:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span></code></pre>
<p>To:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pb-sse-progressbar<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pb-sse-info<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></code></pre>
<p>And some JavaScript:</p>
<pre class="language-js"><code class="language-js"><span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#pb-cloner-form"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"submit"</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#pb-cloner-button"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">attr</span><span class="token punctuation">(</span><span class="token string">"disabled"</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> form <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#pb-cloner-form"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> eventSourceUrl <span class="token operator">=</span>
    PB_ClonerToken<span class="token punctuation">.</span>ajaxUrl <span class="token operator">+</span>
    <span class="token punctuation">(</span>PB_ClonerToken<span class="token punctuation">.</span>ajaxUrl<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">"?"</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">"&amp;"</span> <span class="token operator">:</span> <span class="token string">"?"</span><span class="token punctuation">)</span> <span class="token operator">+</span>
    $<span class="token punctuation">.</span><span class="token function">param</span><span class="token punctuation">(</span>form<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token string">":input"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> evtSource <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">EventSource</span><span class="token punctuation">(</span>eventSourceUrl<span class="token punctuation">)</span><span class="token punctuation">;</span>
  evtSource<span class="token punctuation">.</span><span class="token function-variable function">onopen</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#pb-cloner-button"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">hide</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
  evtSource<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">message</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> bar <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#pb-sse-progressbar"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> info <span class="token operator">=</span> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#pb-sse-info"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">switch</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>action<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">case</span> <span class="token string">"updateStatusBar"</span><span class="token operator">:</span>
        bar<span class="token punctuation">.</span><span class="token function">progressbar</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>percentage<span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        info<span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>info<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
      <span class="token keyword">case</span> <span class="token string">"complete"</span><span class="token operator">:</span>
        evtSource<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          bar<span class="token punctuation">.</span><span class="token function">progressbar</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          info<span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          window<span class="token punctuation">.</span>location <span class="token operator">=</span> PB_ClonerToken<span class="token punctuation">.</span>redirectUrl<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
      <span class="token keyword">default</span><span class="token operator">:</span>
        <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
  evtSource<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    evtSource<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#pb-sse-progressbar"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">progressbar</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">"#pb-sse-info"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span><span class="token string">"EventStream Connection Error"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><a href="https://github.com/pressbooks/pressbooks/blob/c1a41cc95cd49780f39d0f9c1a7148a45b56a439/assets/src/scripts/cloner.js#L1">(Source code)</a></p>
<p>The JavaScript (and jQuery) snippet:</p>
<ul>
<li>Targets a form with id <code>pb-cloner-form</code></li>
<li>Stops the form from submitting and instead</li>
<li>Appends all the form data as <code>$_GET</code> parameters to an ajax URL then</li>
<li>Passes that ajax URL to a <code>new EventSource</code></li>
<li>Updates <code>pb-sse-progressbar</code> and <code>pb-sse-info</code> when it receives an event stream message</li>
<li>Redirects the user back to where they started when complete</li>
</ul>
<p>On the back end, the time consuming function was refactored into a generator that yields a
key/value pair. The key is between 1-100 and represents percentage completed. The value is
a string of information meant for the user. Once you have a generator that follows this
convention, pass it to the EventEmitter. The browser will start receiving an event stream.</p>
<pre class="language-php"><code class="language-php"><span class="token comment">/**
 * @return Generator
 */</span>
<span class="token keyword">function</span> <span class="token function-definition function">loooooooooooooooooooooooongGenerator</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// Pseudo code</span>
    <span class="token keyword">yield</span> <span class="token number">1</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Looking up the source book'</span><span class="token punctuation">;</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">yield</span> <span class="token number">10</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Creating the target book'</span><span class="token punctuation">;</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// ..</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">yield</span> <span class="token number">100</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Done'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token variable">$emitter</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Pressbooks<span class="token punctuation">\</span>EventStreams</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token variable">$emitter</span><span class="token operator">-></span><span class="token function">emit</span><span class="token punctuation">(</span> <span class="token function">loooooooooooooooooooooooongGenerator</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><a href="https://github.com/pressbooks/pressbooks/blob/c1a41cc95cd49780f39d0f9c1a7148a45b56a439/inc/class-cloner.php#L343">(Source code)</a>.</p>
<p>Key ideas:</p>
<ul>
<li>It's not necessary to wait until the request finishes, PHP can emit event-stream
responses (SSE) back to the web browser while it is working on something. - PHP
Generators are a relatively simple refactoring hack to get those responses back to the
browser. - <code>sleep()</code> is only meant as an example of a function call that takes a long
time to finish, don't put <code>sleep</code> in your production code, you already knew this, I
hope?</li>
</ul>
<blockquote>
<p><a href="https://kizu514.com/blog/refactor-your-slow-form-using-php-generators-and-event-streams/">Originally posted on my personal blog</a>
in a more generic format, with references to the movie Office Space, but it turns out
<a href="https://www.youtube.com/watch?v=_sYQeIO6Wyg">it was me, doing research for Pressbooks, the whole time.</a></p>
</blockquote>
<p>WIP: <a href="https://github.com/pressbooks/pressbooks/issues/1282">https://github.com/pressbooks/pressbooks/issues/1282</a></p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Pressbooks and Gutenberg</title>
      <link href="https://pressbooks.org/blog/2018/11/06/pressbooks-and-gutenberg/"/>
      <updated>2018-11-06T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/11/06/pressbooks-and-gutenberg/</id>
      <content type="html"><![CDATA[
        <p>We’ve been closely following the development of <a href="https://wordpress.org/gutenberg/">Gutenberg</a>, WordPress’ new block-based
editor, since its earliest technical prototypes. With the impending release of Gutenberg
in <a href="https://make.wordpress.org/core/5-0/">WordPress 5.0</a> (currently scheduled for November 19), we want to provide an update
to the Pressbooks community on our plans for Gutenberg integration.</p>
<p>In brief: we have deactivated Gutenberg for Pressbooks users, so upgrading to WordPress
5.0 will not change your editing experience. We’ve done this in Pressbooks itself, so
additional plugins like Classic Editor are not required. We’ve made this decision for
several reasons.</p>
<h2 id="1-gutenberg-has-continued-to-change-significantly-up-to-the-projected-release-date-without-a-sufficient-period-of-api-and-ui-stability" tabindex="-1">1. Gutenberg has continued to change significantly up to the projected release date, without a sufficient period of API and UI stability.</h2>
<p>At Pressbooks, our small development team accomplishes a lot with limited resources, but
ensuring compatibility with Gutenberg in time for its November 19th launch has proven to
be beyond our capacity. The <a href="https://make.wordpress.org/core/2018/10/05/gutenberg-phase-2-leads/#comment-34084">lack of clarity</a> in Gutenberg’s development process has
hindered us from integrating Gutenberg into our roadmap. We are now two weeks from its
production release, and Gutenberg’s <a href="https://github.com/WordPress/gutenberg/projects/18">API freeze</a> is not yet complete. We’ve been
tracking blocking issues over the last year and a half and have tried to contribute where
possible, but ongoing API and user interface changes have made it difficult for us to keep
on top of things without neglecting Pressbooks core development, and have made us hesitant
to invest our limited resources in building on a codebase that has not yet stabilized.
Once WordPress 5.0 is released, we will be able to evaluate a stable version of Gutenberg
and map out a plan for integration.</p>
<h2 id="2-gutenberg-lacks-functionality-that-pressbooks-relies-upon" tabindex="-1">2. Gutenberg lacks functionality that Pressbooks relies upon.</h2>
<p>Because Pressbooks is used to produce content for the web and for export, we leverage
WordPress <a href="https://developer.wordpress.org/reference/functions/register_post_status/">custom post statuses</a> to determine whether chapters and other content appear
on the web, in export files, or both. (Custom post statuses do not have a full-featured
public API in WordPress, but they were the best solution for our use case. This is not the
fault of the Gutenberg team—arguably, it’s our fault—but that’s where we are.) We also use
a custom post submission UI to more clearly reflect content status for our users. At this
point in time, Gutenberg <a href="https://github.com/WordPress/gutenberg/issues/3144">does not support</a> custom post statuses, which is a
fundamental issue for us (and <a href="https://github.com/AllediaWordPress/PublishPress/issues/296">others who leverage this functionality</a>). Furthermore,
the new post publish panel is <a href="https://github.com/danielbachhuber/gutenberg-migration-guide/blob/master/action-post-submitbox.md">not easily modified</a>, and we feel that it’s important to
maintain continuity of this interface for our users. Following the release of WordPress
5.0, we will engage on these specific issues with the WordPress and Gutenberg development
teams so that we can provide our users with a familiar experience in this area.</p>
<h2 id="3-gutenberg-does-not-meet-pressbooks-accessibility-standards" tabindex="-1">3. Gutenberg does not meet Pressbooks’ accessibility standards.</h2>
<p>WordPress Accessibility team lead Rian Rietveld’s <a href="https://rianrietveld.com/2018/10/09/i-have-resigned-the-wordpress-accessibility-team/">resignation</a> in early October and
the team’s recent <a href="https://make.wordpress.org/accessibility/2018/10/29/report-on-the-accessibility-status-of-gutenberg/">report</a> on Gutenberg have brought widespread attention to the
accessibility shortcomings of the Gutenberg project. These issues are not new, as some
have implied; Rietveld <a href="https://make.wordpress.org/accessibility/2018/03/28/accessibility-of-gutenberg-the-state-of-play/">documented many</a> in March of this year, and tests of Gutenberg
by <a href="https://make.wordpress.org/accessibility/2018/03/27/accessibility-team-meeting-march-26-2018/">Léonie Watson and Sina Bahram</a> highlighted significant problems around the same
time. Rietveld’s resignation, the team’s report, and the conversations surrounding them
have highlighted flaws in the Gutenberg development process and have underscored how hard
it is to retrofit an existing interface if it was not designed with accessibility and
inclusivity in mind. We're currently making accessibility improvement to elements of our
core UI that date back to the early days of our product—so we know this from firsthand
experience! More importantly, though, we’re continually seeking to expand our own shared
understanding of accessibility and inclusive design principles so that new features are
inclusive from day one. We’re grateful to <a href="https://twitter.com/jesshmitchell">Jess Mitchell</a>, Jonathan Hung, and the rest
of the team at OCAD’s <a href="https://idrc.ocadu.ca/">Inclusive Design Research Centre</a> for their guidance as we work
towards these goals.</p>
<p>We acknowledge the assessment of the WordPress Accessibility team, who <a href="https://make.wordpress.org/accessibility/2018/10/29/report-on-the-accessibility-status-of-gutenberg/">write</a> that
“based on [Gutenberg’s] current status, we cannot recommend that anybody who has a
need for assistive technology allow it to be in use on any sites they need to use at this
time.” We’re grateful to the many accessibility experts and advocates who have shone a
spotlight on accessibility in WordPress, particularly the volunteers who form the
WordPress Accessibility team. We’re also grateful to <a href="https://twitter.com/bamadesigner">Rachel Cherry</a> and the
<a href="https://wpcampus.org/">WPCampus</a> organization, who are funding a much-needed <a href="https://wpcampus.org/2018/10/gutenberg-a11y-audit-rfp/">accessibility audit</a> of
Gutenberg. As our focus is on continuously improving Pressbooks’ accessibility and all
signs suggest that Gutenberg would undermine this goal in its current state, we will be
awaiting the results of WPCampus’ audit following the release of WordPress 5.0, and we
will evaluate our next steps at that time.</p>
<h2 id="closing-thoughts" tabindex="-1">Closing Thoughts</h2>
<p>There are parts of the Gutenberg project that we’re pretty excited about. The ability to
add and edit complex elements visually could be extremely helpful for book production,
allowing educational textboxes and other specialized content to be edited visually while
ensuring clean, semantic output on the front end. We’d love to be able to allow shortcodes
to be edited visually, which Gutenberg supports. And we’re eager to see what comes of
Gutenberg’s <a href="https://github.com/WordPress/gutenberg/pull/7718/">Annotation API</a>, which could support expanded integrations with tools
like <a href="https://web.hypothes.is/">Hypothesis</a>. However, knowing what we know at this point and for the reasons
articulated above, we feel that a “wait and see” approach is most prudent for us and our
users. We are committed to tracking each of these issues and doing what we can to ensure
that authors using our software have the best available tools for the job at hand. We look
forward to a future where Gutenberg can be used for making books.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Q4 Roadmap Preview</title>
      <link href="https://pressbooks.org/blog/2018/10/10/q4-roadmap-preview/"/>
      <updated>2018-10-10T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/10/10/q4-roadmap-preview/</id>
      <content type="html"><![CDATA[
        <p>In Q3, we added a couple new and exciting features to Pressbooks:</p>
<ul>
<li>Image attributions (thanks to Brad and Alex at <a href="https://bccampus.ca">BCcampus</a>)</li>
<li>New
shortcodes to facilitate adding more complex content</li>
</ul>
<p>We also released a new Open Source plugin,
<a href="https://github.com/pressbooks/pressbooks-shibboleth-sso">Pressbooks Shibboleth SSO</a>,
which provides bilateral Shibboleth SSO integration for Pressbooks networks. And we
converted a few more themes to use Buckram, our theme component library, which gives us
added flexibility to add new theme options for all themes.</p>
<p>In Q4 we're wrapping up a few loose ends from our Q3 goals:</p>
<ul>
<li>UX improvements to the webbook Table of Contents</li>
<li>UX improvements to the Export page</li>
</ul>
<p>We're also working on:</p>
<ul>
<li>UI and UX improvements to the Theme Options page</li>
<li>Adding support for DOIs in Book
Info and metadata outputs</li>
<li>Testing integration with Gutenberg, WordPress' new editing
interface</li>
<li>Continuing to convert themes and improve Buckram</li>
</ul>
<p>As always, we'd love to hear your ideas for Pressbooks, so feel free to share them in the
<a href="https://pressbooks.community">Pressbooks Community Forum</a>!</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>The Pressbooks Community Forum</title>
      <link href="https://pressbooks.org/blog/2018/09/12/the-pressbooks-community-forum/"/>
      <updated>2018-09-12T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/09/12/the-pressbooks-community-forum/</id>
      <content type="html"><![CDATA[
        <p>As many of you know, we maintain a forum for Open Source users of Pressbooks at
<a href="https://pressbooks.community">https://pressbooks.community</a>. After some internal discussion, we've decided to close
down the #opensource channel on Pressbooks Slack and refocus our Open Source community
efforts on the forum. We've decided on this change because we believe that keeping
conversations among our Open Source users on the open web is the best way to serve the
broadest possible community of Pressbooks users. Many of you are already members of our
Discourse forum and are actively involved sharing tips &amp; tricks, suggesting features and
helping your fellow Open Source users. If you aren't yet a member, we encourage you to
<a href="https://pressbooks.community/signup">sign up</a>!</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Book Themes, Part 2: What’s Buckram?</title>
      <link href="https://pressbooks.org/blog/2018/07/03/book-themes-part-2-what-s-buckram/"/>
      <updated>2018-07-03T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/07/03/book-themes-part-2-what-s-buckram/</id>
      <content type="html"><![CDATA[
        <p>In the early days of Pressbooks, each book theme was pretty much built from scratch, using
trial and error (and adapting work that went into our first book theme,
<a href="https://github.com/pressbooks/pressbooks-luther">Luther</a>). We used vanilla CSS for all
book themes until
<a href="https://github.com/pressbooks/pressbooks/releases/tag/v3.0">Pressbooks 3.0</a> was released
in December 2015, which supported themes built using the SCSS variant of
<a href="https://sass-lang.com/">SASS</a>.</p>
<p>Our initial goal with adding SASS support to Pressbooks was limited in scope. We needed to
support non-Latin character sets (Ancient Greek, Biblical Hebrew, Chinese, Japanese,
Korean, and many more) but we wanted to keep book export sizes small by only bundling
these additional fonts when they were needed. So we added a new theme option (Global
Typography, now known as
<a href="https://guide.pressbooks.com/chapter/languages/">Language &amp; Script Support</a>) which
allowed users to select additional non-Latin languages for their book which would be
dynamically imported into their stylesheet during export.</p>
<p>After the release of Pressbooks 3.0, we realized the potential of SASS and SASS variables
for allowing users to customize various aspects of their book’s theme which until then we
had been forced to hard-code on a theme by theme basis (or insert by searching and
replacing placeholder strings in vanilla CSS).
<a href="https://github.com/pressbooks/pressbooks-clarke">Clarke</a> was the first theme we converted
to our new theme structure, now known as Buckram. When we released the rebuilt Clarke
theme alongside
<a href="https://github.com/pressbooks/pressbooks/releases/tag/v3.6.0">Pressbooks 3.6.0</a> in June
2016, users gained access to a host of new PDF theme options, allowing margins, running
content, and more to be customized via a settings page.</p>
<p>We wanted to bring this flexibility to our other themes, and since the release of Clarke
2.0 we’ve been slowly working towards that goal with
<a href="https://github.com/pressbooks/buckram">Buckram</a>. It’s been in the works for a couple of
years now, but only over the past six months have we been able to dedicate significant
time and developer resources to bringing it into a stable 1.0 release (coming early
July!).</p>
<p>So, what <em>is</em> Buckram? Last September at our team retreat in Montréal, I demoed it to our
friends at the <a href="https://rebus.foundation">Rebus Foundation</a>, and
<a href="https://rebus.foundation/team/">Boris</a> nicknamed it “Bookstrap”. That’s kind of what it
is; like <a href="https://getbootstrap.com">Bootstrap</a>, Buckram is a set of styled components for
book theming, with corresponding markup, that can be customized with SASS variables. It’s
raw material for our book themes, so we named it after
<a href="https://en.wikipedia.org/wiki/Buckram">buckram</a>, a material of physical bookbinding.</p>
<p>Here’s how Buckram works, in brief. A book theme imports Buckram’s component files and
default variables via SASS <a href="http://sass-lang.com/guide#topic-5">imports</a>, and then
overrides specific variables with custom values.</p>
<p>Let’s say you’d like to customize the way your theme displays blockquotes. They’re found
within the
<a href="https://github.com/pressbooks/buckram/blob/dev/assets/styles/components/elements/_blockquotes.scss"><code>blockquotes</code> partial</a>
and the corresponding
<a href="https://github.com/pressbooks/buckram/blob/dev/assets/styles/variables/_elements.scss#L584-L675">variables file</a>.
If you’ve started by scaffolding a book theme with our
<a href="https://cli.pressbooks.org">command line tool</a>, you’ll find the following file in
<code>/assets/styles/components/_elements.scss</code>:</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Elements</span>

<span class="token comment">// Override variables above this line, using the !default flag to allow further overrides.</span>
<span class="token keyword">@import</span> <span class="token string">"variables/elements"</span><span class="token punctuation">;</span>

<span class="token comment">// Add custom SCSS below these imports and includes.</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements"</span><span class="token punctuation">;</span></code></pre>
<p>Let’s say you want to add a left border and padding to your blockquotes. You can just do
this, with reference to the source variables file (or the
<a href="https://buckram.pressbooks.org">docs</a>):</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Elements</span>

<span class="token property"><span class="token variable">$blockquote-padding-left</span></span><span class="token punctuation">:</span> 1em <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$blockquote-border-left-width</span></span><span class="token punctuation">:</span> 2px <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$blockquote-border-left-style</span></span><span class="token punctuation">:</span> solid <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$blockquote-border-left-color</span></span><span class="token punctuation">:</span> #333 <span class="token statement keyword">!default</span><span class="token punctuation">;</span>

<span class="token comment">// Override variables above this line, using the !default flag to allow further overrides.</span>
<span class="token keyword">@import</span> <span class="token string">"variables/elements"</span><span class="token punctuation">;</span></code></pre>
<p>Now the values you’ve supplied will override the defaults from <code>variables/elements</code>, giving your blockquotes a <code>padding-left</code> value of <code>1em</code> and a <code>border-left</code> value of <code>solid 2px #333</code>. We take advantage of the SASS <code>!default flag</code>, which lets a variable that comes <em>before</em> another variable override it. In this example:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$color</span></span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color</span></span><span class="token punctuation">:</span> blue <span class="token statement keyword">!default</span><span class="token punctuation">;</span></code></pre>
<p>The <code>$color</code> variable will be set to <code>red</code>, as it precedes a variable flagged with <code>!default</code>.</p>
<p>Using <code>!default</code> flags for the custom values in a theme, as demonstrated above, means that we can add theme options to allow further overrides that users control. So a theme may have a default font for body text, but in the future we’ll be able to let users customize body text by selecting an alternative typeface from a dropdown, overriding all rules where that font is referenced by changing a single variable. Moving our themes to Buckram will make the theme customization experience for Pressbooks users flexible in ways that we’ve always dreamed it would be.</p>
<p>So far, we’ve got three open source themes built with Buckram (Clarke, Jacobs and McLuhan). The newest member of our dev team, <a href="https://github.com/dannylonglegs">Daniel Fernandes</a>, has been hard at work converting our backlog of premium themes to Buckram, and we’ll be releasing them over the coming months. We also will be expanding our documentation for Buckram, and improving the Pressbooks CLI tools for building new Buckram themes so that all Open Source users can benefit from the work that’s gone into our theme structure. We’re excited for what Buckram will let us do, and we welcome your feedback, bug reports and code contributions.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Q3 Roadmap Preview</title>
      <link href="https://pressbooks.org/blog/2018/06/30/q3-roadmap-preview/"/>
      <updated>2018-06-30T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/06/30/q3-roadmap-preview/</id>
      <content type="html"><![CDATA[
        <p>Q2 is drawing to a close, and we managed to get a couple of big-ticket items out the door:</p>
<ul>
<li><a href="https://github.com/pressbooks/pressbooks-cas-sso">Pressbooks CAS SSO Plugin</a> *
<a href="https://github.com/pressbooks/pressbooks-lti-provider">Pressbooks LTI Provider Plugin</a></li>
</ul>
<p>We didn't manage to finish as many roadmap items as we expected, but here's what we
crossed out:</p>
<ul>
<li>✔ Improve textbox and table styling across all formats</li>
<li>✔ Finalize new
theme structure and begin migrating themes</li>
<li>✔ Add support for Common Cartridge import
and export</li>
</ul>
<p>We'll be going forward with a simplified list for Q3, with only a couple of big items. We
want to focus Q3 on general housekeeping tasks such as UX improvements and backend
optimisations:</p>
<h2 id="big-projects" tabindex="-1">Big projects</h2>
<ul>
<li>Provide basic support for Shibboleth SSO</li>
<li>Add new shortcodes to facilitate
authoring</li>
<li>Begin researching analytics solutions</li>
</ul>
<h2 id="housekeeping-items" tabindex="-1">Housekeeping items</h2>
<ul>
<li>UX improvements to the webbook Table of Contents</li>
<li>UX improvements to the Export
page</li>
<li>Other backend and frontend UX improvements</li>
<li>Accessibility improvements</li>
<li>Ongoing theme conversions</li>
</ul>
<p>If you’re planning on working on any of these items or would like to collaborate, please
let us know in the forums or tweet <a href="https://twitter.com/pressbooksdev">@pressbooksdev</a>!</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Our Accessibility Policy and Forthcoming Accessibility Improvements</title>
      <link href="https://pressbooks.org/blog/2018/05/01/our-accessibility-policy-and-forthcoming-accessibility-improvements/"/>
      <updated>2018-05-01T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/05/01/our-accessibility-policy-and-forthcoming-accessibility-improvements/</id>
      <content type="html"><![CDATA[
        <p>We're pleased to share Pressbooks' new
<a href="/user-docs/accessibility/">policy on accessibility</a>:</p>
<blockquote>
<p>Pressbooks is committed to ensuring that our software is accessible to users and
readers. We understand accessibility and inclusive design to be holistic, proactive
processes that must be built into our product specification and development workflow. We
also recognize that as a publishing tool, we have an opportunity to facilitate the
production of accessible content. With this in mind, we are working with accessibility and
inclusive design experts at OCAD University’s
<a href="https://idrc.ocadu.ca">Inclusive Design Research Centre</a> and others to identify areas for
improvement.</p>
</blockquote>
<p>For full details, you can <a href="/user-docs/accessibility/">consult the policy</a>.</p>
<p>As noted in this morning's sprint preview, we are tackling
<a href="https://github.com/pressbooks/pressbooks-book/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+label%3Aa11y+milestone%3A2.3.0">a number of accessibility issues</a>
in our current sprint thanks to clear, actionable feedback from Jonathan Hung and the team
at the Inclusive Design Research centre. We're thrilled to be collaborating with the IDRC
to make our project more inclusive to all users, and we're grateful for their insight as
we develop our internal expertise on these vital issues.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Book Themes, Part 1: Frames and Pictures</title>
      <link href="https://pressbooks.org/blog/2018/04/09/book-themes-part-1-frames-and-pictures/"/>
      <updated>2018-04-09T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/04/09/book-themes-part-1-frames-and-pictures/</id>
      <content type="html"><![CDATA[
        <p>One of the most complex aspects of Pressbooks is the way our book themes work across
different formats. It even confuses us sometimes. In a series of posts this week, I hope
to clarify some of the concepts that underpin our book theming system, reflect on how it
has evolved over the years, and outline where we hope to take book themes in the future.</p>
<h2 id="a-framing-device" tabindex="-1">A Framing Device</h2>
<p>Conceptually, I find it helpful to think of our book themes as two things: a frame and a
picture.</p>
<figure>
<p><img src="/images/mcluhan-233x300.png" alt="A black and white photo of Marshall McLuhan leaning against a mantlepiece in a hand-drawn picture frame."></p>
<figcaption>Marshall McLuhan, framed. (Wikimedia Commons)</figcaption>
</figure>
<p>Take <a href="https://github.com/pressbooks/pressbooks-book/">McLuhan</a>, our default book theme.
It's really two elements in one. The first element is a (fairly conventional) WordPress
theme which provides the user interface for reading a Pressbooks book on the web. This is
the &quot;frame&quot; — the user interface (UI) for readers of a webbook. The other component is the
&quot;picture&quot; — styles which format the content of the book for display, either within the
webbook &quot;frame&quot; or in other formats such as PDF, EPUB, or MOBI.</p>
<p>McLuhan provides the UI for all Pressbooks webbooks, even those that use other styles for
their content. All other book themes are WordPress
<a href="https://codex.wordpress.org/Child_Themes">child themes</a>, which means that they inherit
the &quot;frame&quot; (the webbook UI) from McLuhan, the parent theme<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>.
So if you change your book's theme to
<a href="https://github.com/pressbooks/pressbooks-jacobs/">Jacobs</a>, you're putting a new &quot;picture&quot;
in the original frame:</p>
<figure>
<p><img src="/images/jacobs-233x300.png" alt="A black and white photo of Jane Jacobs in a hand-drawn picture frame."></p>
<figcaption>Jane Jacobs, framed. (Wikimedia Commons)</figcaption>
</figure>
<p>To demonstrate this more concretely, here's a webbook using McLuhan:</p>
<figure>
<p><img src="/images/mcluhan-webbook-1024x524.png" alt="A screenshot of the first chapter of Herman Melville's "></p>
<figcaption>Moby Dick in McLuhan.</figcaption>
</figure>
<p>And the same webbook using Jacobs:</p>
<figure>
<p><img src="/images/jacobs-webbook-1024x524.png" alt="A screenshot of "></p>
<figcaption>Moby Dick in Jacobs.</figcaption>
</figure>
<p>No difference except the typography of the book content.</p>
<h2 id="luthers-legacy" tabindex="-1">Luther's Legacy</h2>
<p>Our old default book theme was <a href="https://github.com/pressbooks/pressbooks-luther/">Luther</a>.
When we built Luther, we made a tactical error and mixed the content styles for web into
the UI styles. By failing to separate these concerns, we made the transition from Luther
to McLuhan more awkward than it could have been; when we rebuilt the webbook UI in
McLuhan, we had to
<a href="https://github.com/pressbooks/pressbooks-book/pull/163">supply some (now missing) content styles</a>
for old themes<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> that had been
relying on the Luther webbook stylesheet to properly display some of the webbook content.
We've learned from this mistake, and all of our work on webbook UI and web content styles
going forward will emphasize a proper separation of concerns.</p>
<h2 id="next-whats-buckram" tabindex="-1">Next: What's Buckram?</h2>
<p>The next part of this series will be a deep dive into
<a href="https://github.com/pressbooks/buckram/">Buckram</a>, the SCSS book component library that is
at the heart of our new batch of themes. Until next time!</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>That being said, child themes <em>can</em> override components of the parent themes, so one could make a child theme that changed any aspect of the webbook UI by <a href="https://codex.wordpress.org/Child_Themes#Template_Files">replacing or modifying template files</a>. <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Only old themes, though! More on that in part two. <a href="#fnref2" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Q2 Roadmap Preview</title>
      <link href="https://pressbooks.org/blog/2018/03/14/q2-roadmap-preview/"/>
      <updated>2018-03-14T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/03/14/q2-roadmap-preview/</id>
      <content type="html"><![CDATA[
        <p>We're drawing near the end of Q1 at Pressbooks! And we've crossed off a lot of the items
on our 2018 Roadmap:</p>
<ul>
<li>✔ Ensure support for <a href="https://h5p.org/wordpress">H5P</a> interactive elements with
graceful fallbacks across all formats</li>
<li>✔ Ensure support for video and audio with
graceful fallbacks across all formats</li>
<li>✔ Add support for multiple contributors (authors,
editors, translators, etc.)</li>
<li>✔ Add custom metadata support to the Pressbooks REST API
and clone tool</li>
<li>✔ Finish our new landing page theme</li>
<li>✔ Finish our new webbook theme</li>
<li>✔ Improve section heading outputs in EPUB and PDF</li>
<li>✔ Develop two new themes oriented
towards textbook and OER use cases</li>
<li>✔ Add support for chapter-level cloning</li>
<li>✔ Overhaul the Organize page, prioritizing accessibility, fully responsive design, and
inline and batch editing support of front matter/chapter/back matter properties</li>
</ul>
<p>Now's the time for us to share some of our plans for Q2. We've drawn from our overall
roadmap for this year and we'll be trying to address many of the top priorities and
feature requests we've been hearing about from our clients and Open Source users.</p>
<h3 id="editing-and-content" tabindex="-1">Editing and Content</h3>
<ul>
<li>We’ll be working to test and fully support the
<a href="https://wordpress.org/plugins/wp-quicklatex/">WP QuickLaTeX</a> plugin, which will improve
the quality of LaTeX formulas in PDF exports.</li>
<li>We'll be engaging in research and
development with an eye on further mathematics support improvements across all formats.</li>
<li>We'll be working to test and fully support the
<a href="https://wordpress.org/plugins/tablepress/">TablePress</a> plugin, which will allow more
advanced table display.</li>
<li>We'll be engaging in research and development with the goal of
improving to media management and image uploading, including user-facing guidance to
ensure high-quality image output across all formats.</li>
<li>We'll be refining our approach for
supporting the forthcoming WordPress <a href="https://wordpress.org/gutenberg/">Gutenberg</a> editor.</li>
</ul>
<h3 id="core-technology" tabindex="-1">Core Technology</h3>
<ul>
<li>We'll be engaging in research and development on various popular enterprise
integrations for Pressbooks, including LTI and various single sign-on (SSO) methods, with
the goal of ensuring that Pressbooks better supports these integrations.</li>
</ul>
<h3 id="themes-and-theme-design" tabindex="-1">Themes and Theme Design</h3>
<ul>
<li>Based on user feedback, we'll continue to refine the
<a href="https://github.com/pressbooks/pressbooks-book">McLuhan</a> (webbook) and
<a href="https://github.com/pressbooks/pressbooks-aldine">Aldine</a> (landing page) themes that we
released at the end of February.</li>
<li>We'll continue to refine Buckram, our book theme
component library, and we'll continue to convert legacy themes to use Buckram and fully
support the theme options that are currently available in
<a href="https://github.com/pressbooks/pressbooks-clarke">Clarke</a>,
<a href="https://github.com/pressbooks/pressbooks-jacobs">Jacobs</a>, and
<a href="https://github.com/pressbooks/pressbooks-book">McLuhan</a>. This work will include updates
to the open source Austen and <a href="https://github.com/pressbooks/pressbooks-donham">Donham</a>
themes.</li>
<li>We'll be continuing research and development towards implementing new markup for
books, based on <a href="https://oreillymedia.github.io/HTMLBook">HTMLBook</a>.</li>
</ul>
<h3 id="import-export-and-cloning" tabindex="-1">Import, Export, and Cloning</h3>
<ul>
<li>We'll be testing the BCcampus
<a href="https://github.com/BCcampus/pressbooks-openstax-import">OpenStax Importer for Pressbooks</a>
to see if can be added to our recommended plugins list.</li>
<li>We'll be reviewing various implementations of Common
Cartridge import and export to ensure first-class support for this format.</li>
<li>We'll be exploring ways of tracking the adoption of Open Textbooks.</li>
</ul>
<h3 id="user-interface" tabindex="-1">User Interface</h3>
<ul>
<li>We'll be engaging in research and development on methods of configuring default theme
options and other settings for books at the network level.</li>
<li>We'll be engaging in research
and development on methods for providing book-level analytics on networks where books are
in subdirectories as opposed to subdomains, and exploring other types of book- and
network-level analytics.</li>
</ul>
<h3 id="accessibility-and-inclusivity" tabindex="-1">Accessibility &amp; Inclusivity</h3>
<ul>
<li>We'll be working with the <a href="https://idrc.ocadu.ca/">Inclusive Design Research Centre</a>
(IDRC) to integrate their
<a href="https://docs.fluidproject.org/infusion/development/tutorial-userInterfaceOptions/UserInterfaceOptions.html">User Interface Options</a>
tool into <a href="https://github.com/pressbooks/pressbooks-book">McLuhan</a> and
<a href="https://github.com/pressbooks/pressbooks-aldine">Aldine</a>.</li>
<li>We'll be implementing other
accessibility and inclusivity improvements on the front-end and back-end based on feedback
from the IDRC.</li>
</ul>
<p>If you're planning on working on any of these items or would like to collaborate, please
let us know in the forums or tweet @pressbooksdev!</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Declaring your plugin&#39;s compatibility with Pressbooks</title>
      <link href="https://pressbooks.org/blog/2018/03/05/declaring-your-plugins-compatibility-with-pressbooks/"/>
      <updated>2018-03-05T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/03/05/declaring-your-plugins-compatibility-with-pressbooks/</id>
      <content type="html"><![CDATA[
        <p>Last summer, <a href="https://woocommerce.com">WooCommerce</a> introduced a
<a href="https://woocommerce.wordpress.com/2017/08/28/new-version-check-in-woocommerce-3-2/">new feature</a>
in version 3.2 of their core plugin: compatibility alerts for installed add-on plugins
when new versions of WooCommerce became available. By adding a line to the plugin headers
of a WooCommerce add-on, developers could let users know the most recent version of
WooCommerce with which they'd tested their plugin.</p>
<p>We really liked this idea, so <a href="https://github.com/connerbw">Dac</a> built a similar
<a href="https://github.com/pressbooks/pressbooks/pull/1115">feature</a> into Pressbooks 5. Now, when
future updates to Pressbooks show up on the plugins page of a Pressbooks, users will see
whether or not their Pressbooks-specific add-ons have been tested with the latest version:</p>
<p><img src="/images/Screen-Shot-2018-03-05-at-10.00.37-AM.png" alt="Plugin compatibility notice"></p>
<p>If you develop plugins that extend Pressbooks functionality (we check for <code>pressbooks</code> in
the plugin slug, name, and description), you can add <code>Pressbooks tested up to: 5.0.0</code> (or
whatever version string is relevant) to your plugin headers, and Pressbooks will reflect
your plugin's compatibility in the update notice. We hope this feature will give network
administrators a better understanding at a glance of whether they can safely update to the
latest version of Pressbooks. Of course, we still encourage thorough testing in a
development or staging environment before installing a major update.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Introducing pressbooks/ideas 💡</title>
      <link href="https://pressbooks.org/blog/2018/03/02/introducing-pressbooks-ideas/"/>
      <updated>2018-03-02T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/03/02/introducing-pressbooks-ideas/</id>
      <content type="html"><![CDATA[
        <p>I'm always looking for better ways to keep track of feature suggestions from members of
the Pressbooks Open Source community, which within our small and very active team can
often get lost in the shuffle. Messages in Slack can fly by before we make
note of them, and often threads in the <a href="https://pressbooks.community/">forum</a> include
a number of ideas which should be evaluated as standalone feature suggestions but get lost
in a broader discussion.</p>
<p>So, borrowing from the <a href="https://github.com/wp-cli/ideas">WP-CLI project</a> where I first saw
this implemented, I've created a <a href="https://github.com/pressbooks/ideas/">GitHub repo</a> for
ideas from Pressbooks users. If you have an idea for Pressbooks that you'd like to suggest
to our team, you can <a href="https://github.com/pressbooks/ideas/issues">open an issue</a>. We will
evaluate your ideas on a regular basis for inclusion in our sprints and longer-term
roadmap. You can check on the status of your idea by visiting the idea board.</p>
<p>I'm looking forward to seeing what emerges! As always we welcome feedback and discussion
in the <a href="https://pressbooks.community/">forum</a>.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Pressbooks 5: Developer Guide</title>
      <link href="https://pressbooks.org/blog/2018/01/17/pressbooks-5-developer-guide/"/>
      <updated>2018-01-17T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2018/01/17/pressbooks-5-developer-guide/</id>
      <content type="html"><![CDATA[
        <p>Pressbooks 5 will introduce some significant changes to the ways we store and retrieve
data within the book, a new export module, modifications to two existing export modules,
and some changes to the filesystem for user generated content. This post outlines these
key changes and the migration paths that we’ve built in to facilitate the upgrade to
Pressbooks 5.</p>
<h2 id="data-changes" tabindex="-1">Data Changes</h2>
<h3 id="content-visibility" tabindex="-1">Content Visibility</h3>
<p>In Pressbooks 4.x and earlier, the visibility of content across different media is
controlled by a combination of custom post metadata and core post status. For front
matter, back matter and chapters, the <code>pb_export</code> post meta value determines whether or
not they appear in exports, while their post status (<code>draft</code>, <code>pending</code>, <code>private</code>, or
<code>publish</code>) determines their visibility in the webbook.</p>
<p>In an effort to better conform to WordPress best practices and streamline the user
experience, we’re using the
<a href="https://developer.wordpress.org/reference/functions/get_post_status/">post status</a> as the
source of truth for whether front matter, chapters, and back matter appear in web,
exports, or both. We’ve added a new <code>web-only</code> post status, and content visibility will
now be determined as follows:</p>
<table>
<thead>
<tr>
<th>Post Status</th>
<th>Web + REST API</th>
<th>Exports</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>draft</code></td>
<td>hidden</td>
<td>hidden</td>
</tr>
<tr>
<td><code>web-only</code></td>
<td>visible</td>
<td>hidden</td>
</tr>
<tr>
<td><code>private</code></td>
<td>hidden</td>
<td>visible</td>
</tr>
<tr>
<td><code>publish</code></td>
<td>visible</td>
<td>visible</td>
</tr>
</tbody>
</table>
<p>In terms of the user interface, we're changing this:</p>
<p><img src="/images/export-publish.svg" alt="A mockup of the Export Settings &amp; Publish panels in Pressbooks 4.x."></p>
<p>To this:</p>
<figure>
<p><img src="/images/status-visibility-new.svg" alt="A mockup of the Status &amp; Visibility panel for a new chapter in Pressbooks 5."></p>
<figcaption>The panel for a new chapter.</figcaption>
</figure>
<figure>
<p><img src="/images/status-visibility.svg" alt="A mockup of the &quot;Status &amp; Visibility&quot; panel for an existing chapter in Pressbooks 5."></p>
<figcaption>The panel for an existing chapter.</figcaption>
</figure>
<p>Note that we're changing the primary action button from &quot;Publish&quot; for new content and
&quot;Update&quot; for existing content to &quot;Create&quot; and &quot;Save&quot;, respectively.</p>
<p>Your front matter, back matter and chapters will be automatically updated when you visit
your book after updating to Pressbooks 5.</p>
<h3 id="contributor-management" tabindex="-1">Contributor Management</h3>
<p>Pressbooks 4.x lets you add a single author and multiple contributing authors, editors,
and translators in your Book Information and lets you add a single author for each front
matter, back matter, or chapter. Pressbooks 5 imports all your existing authors (and
Pressbooks users who are assigned to your book) and creates entries in a new <code>contributor</code>
taxonomy. Then, it repopulates new relevant metadata fields with a list of contributors
that match your book’s existing contributors. For example, if you have an author named
Alice X and two editors named Bob Y and Eve Z, your Book Information will contain the
following in Pressbooks 4.x:</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>pb_author</code></td>
<td><code>'Alice X'</code></td>
</tr>
<tr>
<td><code>pb_editor</code></td>
<td><code>['Bob Y', 'Eve Z']</code></td>
</tr>
</tbody>
</table>
<p>In Pressbooks 5, your Book Information will contain the following:</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>pb_authors</code></td>
<td><code>'alice-x'</code></td>
</tr>
<tr>
<td><code>pb_editors</code></td>
<td><code>['bob-y', 'eve-z']</code></td>
</tr>
</tbody>
</table>
<p>The values saved in Book Information are the
<a href="https://codex.wordpress.org/Function_Reference/get_term#Return_Values">slugs</a> of entries
in the <code>contributor</code> taxonomy. Also, for backwards-compatibility, the new field names are
pluralized so that any third-party code that looks for the old fields will still be able
to retrieve them for the time being.</p>
<p>You’ll be able to edit the display names of these contributors in one place — the new
Contributors page, which is a standard WordPress taxonomy management page — and you’ll be
able to quickly and easily select from your list of contributors to add assign authors
throughout your book (if you have a book that consists of chapters with different authors,
and you also want to include credits for all the authors in your Book Information, this
will make maintaining that information much easier). In future releases of Pressbooks, we
will be able to add metadata to contributors, including profile pictures, author websites,
and more, for display on your webbook cover page or individual front matter, back matter,
and chapters.</p>
<p>We're also adding a
<a href="https://github.com/pressbooks/pressbooks/blob/dev/inc/class-contributors.php">new class</a>,
<code>\Pressbooks\Contributors</code>, and
<a href="https://github.com/pressbooks/pressbooks/blob/dev/inc/utility/namespace.php#L1263-L1284">some other related functions</a>
to retrieve arrays or formatted lists of contributors.</p>
<p>The migration of your book’s contributor data will happen automatically when you visit
your book after updating to Pressbooks 5.</p>
<h3 id="licenses" tabindex="-1"><strong>Licenses</strong></h3>
<p>In the same way that we’re moving contributor data to a <code>contributor</code> taxonomy, we’re
moving the available licenses into a new <code>license</code> taxonomy. That way, if you need to add
a custom license for your book, it will immediately be available in all chapters, front
matter, and back matter as well as your Book Information. This migration will happen
automatically when you visit your book after updating.</p>
<h2 id="export-changes" tabindex="-1">Export Changes</h2>
<h3 id="html-book-preview" tabindex="-1">HTMLBook Preview</h3>
<p>In Pressbooks 5, <a href="https://github.com/pressbooks/pressbooks/pull/1032">we’ve introduced</a> a
new <a href="https://oreillymedia.github.io/HTMLBook/">HTMLBook</a> export module as a proof of
concept. We’re excited about the potential of adopting and advancing this proposed
standard for the semantic representation of books on the web, and we will be actively
developing our export module in the months to come. We're also working with the creators
of HTMLBook to expand and improve the standard (to begin with, we're proposing the
addition of new front matter and back matter types and of new block elements, including
educational textboxes).</p>
<p>At this time, our HTMLBook exporter is not production-ready, but we will be using it as a
testbed to refine our best practices for coding export modules in Pressbooks.</p>
<h3 id="xhtml-and-epub-markup-changes" tabindex="-1">XHTML and EPUB Markup Changes</h3>
<p>We're making a change to the way we mark up our XHTML and EPUB exports, but only for
themes that use our SCSS component library,
<a href="https://github.com/pressbooks/buckram">Buckram</a>. In Pressbooks 4.x, chapter subtitle and
author elements are not wrapped in the same container as the chapter number and title:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter standard<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-title-wrap<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h3</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-number<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h3</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Loomings<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ugc chapter-ugc<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-author<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Herman Melville<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-subtitle<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>The First Chapter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Call me Ishmael.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>This makes it very difficult to reliably style the first page of front matter, back
matter, and chapters.</p>
<p>In Pressbooks 5, books that use Buckram-based themes will now have the following markup:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter standard<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-title-wrap<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-title<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Loomings<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-author<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Herman Melville<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>chapter-subtitle<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>The First Chapter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ugc chapter-ugc<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>Call me Ishmael.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>This change will only impact themes using Buckram, which include our open source <a href="https://github.com/pressbooks/pressbooks-clarke">Clarke</a> theme and the premium Asimov theme (the latter only available to Pressbooks EDU or <a href="https://pressbooks.com">Pressbooks.com</a> users). We are thoroughly testing these Buckram-based themes to ensure that this change does not affect existing books. If you have built a theme using Buckram, we suggest you test your theme as well once <a href="https://github.com/pressbooks/buckram/issues/36">this issue</a> has been closed.</p>
<h2 id="filesystem-changes" tabindex="-1">Filesystem Changes</h2>
<p>In Pressbooks 4.x, all export files, (S)CSS and other user-generated files are stored in
subfolders of your book’s uploads directory. We’re moving them all into a pressbooks
folder to prevent conflicts between our files and any other files that plugins may
generate. This will happen without the need for any intervention on your part.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Moving Half a Million Database Tables to AWS Aurora (Part 2)</title>
      <link href="https://pressbooks.org/blog/2017/11/07/moving-half-a-million-database-tables-to-aws-aurora-part-2/"/>
      <updated>2017-11-07T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2017/11/07/moving-half-a-million-database-tables-to-aws-aurora-part-2/</id>
      <content type="html"><![CDATA[
        <p><a href="/blog/2017/10/19/moving-half-a-million-database-tables-to-aws-aurora-part-1/">Quick recap</a>:
Migrate half a million database tables from a single bare metal server with 1 database to
101 database slices on AWS Aurora.</p>
<p>Wait, half a million database tables?! Answered in
<a href="/blog/2017/10/19/moving-half-a-million-database-tables-to-aws-aurora-part-1/">Part 1</a>.</p>
<h2 id="plan" tabindex="-1">Plan</h2>
<ol>
<li>Stop the server, take an LVM snapshot.</li>
<li>Use <a href="https://github.com/maxbube/mydumper">mydumper</a> to dump the snapshot to SQL files.</li>
<li>rysnc these to the new server.</li>
<li>Use myloader to load the SQL files into the new databases.</li>
</ol>
<figure>
<p><img src="/images/Migration-Kanban.png" alt=""></p>
<figcaption>A more detailed view of our plan as seen in our migration kanban</figcaption>
</figure>
<h2 id="captain-not-so-obvious" tabindex="-1">Captain Not So Obvious</h2>
<blockquote>
<p>Why not setup the Aurora as a replica and then switch over?</p>
</blockquote>
<p>Because our MariaDB server was a bare metal box outside of AWS. The
<a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Aurora.Migration.RDSMySQL.html">read Replica docs</a> imply
that MySQL has to already be in AWS for that to work. If that's not enough
<a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MySQL.Procedural.Importing.NonRDSRepl.html">this doc says use mysqldump to start, then sync after.</a>
<a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MySQL.Procedural.Importing.External.Repl.html">This doc also says use mysqldump.</a>
All signs point to nope.</p>
<blockquote>
<p>Why not DMS?</p>
</blockquote>
<p>Answered in
<a href="/blog/2017/10/19/moving-half-a-million-database-tables-to-aws-aurora-part-1/">Part 1</a>.</p>
<p>Mostly, at the end of the day, because our hosted networks are already on AWS it was simply more cost effective to shut down our freemium site and migrate in one swoop than to have our whole team keep at this for weeks, possibly months.</p>
<h2 id="epilogue-what-about-uploads" tabindex="-1">Epilogue: What About Uploads?</h2>
<p>Each book has media library files <em>(GIF, PNG, JPG, EPUB, PDF, etc)</em>. A few days before the
migration, we copied all files from the production server's <code>uploads/</code> directory using
<code>rsync</code>:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">rsync</span> <span class="token parameter variable">-avz</span> <span class="token parameter variable">-e</span> <span class="token string">"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"</span> someuser@oldpressbooksdotcom:/path/to/uploads/ /path/to/uploads/ <span class="token parameter variable">--progress</span></code></pre>
<p>This process took about 10 hours.</p>
<p>Then, on migration day, we ran the same command again with the <code>--delete</code> option to update
the new server with the latest files from the old server and remove any files that have
been deleted on the old server:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">rsync</span> <span class="token parameter variable">-avz</span> <span class="token parameter variable">--delete</span> <span class="token parameter variable">-e</span> <span class="token string">"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"</span> someuser@oldpressbooksdotcom:/path/to/uploads/ /path/to/uploads/ <span class="token parameter variable">--progress</span></code></pre>
<p>Much quicker! (around 7 minutes)</p>
<h2 id="launch-it" tabindex="-1">Launch it!</h2>
<blockquote>
<p>“If we get into the trees it could be rather disastrous, so we’ve got to hit the roses.”
– <a href="http://hnmag.ca/festivals/aiming-for-the-roses-with-devil-at-your-heels/">Ken Carter</a></p>
</blockquote>
<p>Scripts from
<a href="/blog/2017/10/19/moving-half-a-million-database-tables-to-aws-aurora-part-1/">Part 1 (read it already!)</a>
were modified to include Slack notifications:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function-name function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token builtin class-name">read</span> <span class="token parameter variable">-d</span> <span class="token string">''</span> payLoad <span class="token operator">&lt;&lt;</span> <span class="token string">EOF
  {
    "channel": "#operations",
    "username": "Pressbot",
    "icon_emoji": ":closed_book:",
    "text": "Slice \<span class="token variable"><span class="token variable">`</span>$<span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">\</span><span class="token variable">`</span></span> has been imported on AWS."
  }
EOF</span>

  <span class="token function">curl</span> <span class="token punctuation">\</span>
    --write-out %<span class="token punctuation">{</span>http_code<span class="token punctuation">}</span> <span class="token punctuation">\</span>
    <span class="token parameter variable">--silent</span> <span class="token punctuation">\</span>
    <span class="token parameter variable">--output</span> /dev/null <span class="token punctuation">\</span>
    <span class="token parameter variable">-X</span> POST <span class="token punctuation">\</span>
    <span class="token parameter variable">-H</span> <span class="token string">'Content-type: application/json'</span> <span class="token punctuation">\</span>
    <span class="token parameter variable">--data</span> <span class="token string">"<span class="token variable">${payLoad}</span>"</span> <span class="token string">"https://hooks.slack.com/services/&lt;SLACK_WEBHOOK_ID>"</span>
<span class="token punctuation">}</span>

<span class="token comment"># Usage</span>

notify <span class="token variable">$slice</span></code></pre>
<figure>
<p><img src="/images/pressbot-e1510002038580.png" alt=""></p>
<figcaption>Slack enhanced scripts.</figcaption>
</figure>
<p>In an effort to reduce downtime we imported slices as soon as they were transferred.
Dumping was faster than imports.</p>
<figure>
<p><img src="/images/pressbot2.png" alt="Pressbot"></p>
<figcaption>Still slacking!</figcaption>
</figure>
<p>Ned working hard:</p>
<figure>
<p><img src="/images/ned-again-225x300.jpg" alt="Ned"></p>
<figcaption>screen -r, control+a control+d,
repeat</figcaption>
</figure>
<p>All while coding sprint tasks in between.</p>
<h2 id="things-that-went-wrong" tabindex="-1">Things That Went Wrong</h2>
<p>We noticed an embarrassing typo in the first few database slices we imported. We had to
redo them because
<a href="https://stackoverflow.com/questions/67093/how-do-i-quickly-rename-a-mysql-database-change-schema-name">renaming a database with tens of thousands of tables in it is not obvious</a>.</p>
<p>I ordered takeout from the wrong <a href="https://www.comptoir21.com/">fish &amp; chips shop</a>. I had to
take a subway 30 minutes to downtown to get it. <em>(Psst <a href="https://www.foodora.ca">Foodora</a>,
your geolocation feature sucks!)</em></p>
<p>Otherwise, nothing. We landed in the roses.</p>
<h2 id="timeline" tabindex="-1">Timeline</h2>
<ul>
<li>8:00: Migration started.</li>
<li>10:40: Database migration started.</li>
<li>19:10: Database migration completed!</li>
<li>19:30: Migration completed.</li>
<li>Total time: 11 hours 30 minutes.</li>
</ul>
<p>DONE. Exciting to turn the page on this. Thanks for reading.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Moving Half a Million Database Tables to AWS Aurora (Part 1)</title>
      <link href="https://pressbooks.org/blog/2017/10/19/moving-half-a-million-database-tables-to-aws-aurora-part-1/"/>
      <updated>2017-10-19T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2017/10/19/moving-half-a-million-database-tables-to-aws-aurora-part-1/</id>
      <content type="html"><![CDATA[
        <p>This post is about migrating Pressbooks.com to AWS.</p>
<h2 id="does-it-scale" tabindex="-1">Does It Scale?</h2>
<p>At <a href="/">Pressbooks</a> we use
<a href="https://codex.wordpress.org/Create_A_Network">WordPress Multisite</a> as a development
platform. <a href="https://github.com/pressbooks/pressbooks">Pressbooks changes WordPress</a> and
makes every blog a book.</p>
<p>The prevailing wisdom of the day is that a relational database should have a manageable
set of tables with lots of rows of data in them ...and then there's WordPress.</p>
<p>WP Multisite creates
<a href="https://codex.wordpress.org/Database_Description#Site_Specific_Tables">10 database tables</a>
for every blog <em>(or in our case: for every book.)</em> Tables share IDs but they are not
enforced at the database level. There are no foreign key constraints, no triggers, nor
routines. It's simple no frills MySQL.</p>
<p>Pressbooks dot com is currently running on a single bare metal server. <em>(Our hosted
instances are already on AWS)</em> This server has a single MariaDB database with 60,000 books
in it. When we do the math that's over 600,000 tables in one database.
<a href="https://www.askbjoernhansen.com/2008/02/14/10000_tables_in_one_mysql_database.html">Are you nuts?!</a>
Unusual? Horrible? Yet
<a href="https://dev.mysql.com/doc/refman/5.7/en/database-count-limit.html">entirely possible</a>,
<a href="https://www.percona.com/blog/2017/10/01/one-million-tables-mysql-8-0/">even plausible</a>.</p>
<p>I've met people who worked at Automattic and
<a href="https://www.meetup.com/wp-mtl/events/240377606/">from the stories, I heard</a> WordPress dot
com uses the same WP Multisite technology but instead of half a million tables it's over a
billion tables <em>(probably not all in the same database though, more on that later)</em>.</p>
<p>I call this the Schrödinger's Cat of database design because so long as we don't look it's
alive?</p>
<h2 id="prerequisites" tabindex="-1">Prerequisites</h2>
<p>As I said, we already host hundreds of WP Multisite networks on AWS. We build, manage, and
deploy to our infrastructure using <a href="https://www.terraform.io/">Terraform</a>,
<a href="https://www.ansible.com/">Ansible</a>, <a href="https://wp-cli.org/">wp-cli</a> and
<a href="https://github.com/roots/trellis">all things competent</a>. We simply just, sort of, well,
neglected to move our freemium site over because we were too busy.</p>
<p>The time has come.</p>
<h2 id="research" tabindex="-1">Research</h2>
<p>We tried <code>mysqldump</code>. It was too slow. Our tests showed that a dump would take days.</p>
<p>Some colleagues recommended <a href="https://aws.amazon.com/dms/">AWS DMS</a>. It did not work. Some
reasons:</p>
<ul>
<li><a href="https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Source.MySQL.html#CHAP_Source.MySQL.Limitations">The <code>AUTO_INCREMENT</code> attribute is not migrated.</a></li>
<li>WP Multisite tables are prefixed <code>wp_1_, wp_2_, wp_3_, ...</code> MySQL considers the
underscore a
<a href="https://stackoverflow.com/questions/8236818/why-does-underscore-match-hyphen">one character wildcard</a>
when used in LIKE queries, DMS provided no way to escape it for table filters.</li>
<li>Unexplained crashing on anything less than a <code>c4.large</code> <em>(failed last Error The task
stopped abnormally Stop Reason RECOVERABLE_ERROR Error Level RECOVERABLE)</em></li>
<li>Mostly, the fastest migration we could get going, running 4 tasks in parallel, was an
ETA of 10 days</li>
</ul>
<p>We asked for help. Ned had a conference call with a reputable consulting firm and they gave us a quote: $34K USD + travel &amp; on-site
expenses.</p>
<p><img src="/images/coffee-spitting.gif" alt="Coffee spitting "></p>
<p>Next, our research led us to <a href="https://github.com/maxbube/mydumper">mydumper</a>. From the
README:</p>
<blockquote>
<p>== What is mydumper? Why? ==</p>
<ul>
<li>Parallelism (hence, speed) and performance (avoids expensive character set conversion
routines, efficient code overall)</li>
<li>Easier to manage output (separate files for tables, dump metadata, etc, easy to
view/parse data)</li>
<li>Consistency - maintains snapshot across all threads, provides accurate master and
slave log positions, etc</li>
<li>Manageability - supports PCRE for specifying database and tables inclusions and
exclusions</li>
</ul>
</blockquote>
<p>So far so good...</p>
<blockquote>
<p>== How to build it? ==</p>
</blockquote>
<p><img src="/images/jerry-seinfeld-leaving.gif" alt="Jerry Seinfeld leaving"></p>
<p>Just kidding. It turns out we don't have to build mydumper. On
Ubuntu <code>sudo apt install mydumper</code> works fine. Similar command using <code>yum</code> on CentOS.</p>
<p>Our tests conclude that mydumper finishes in hours instead of days.</p>
<h2 id="plan" tabindex="-1">Plan</h2>
<p>It is our opinion that this kind of problem is better suited for a
<a href="https://en.wikipedia.org/wiki/Document-oriented_database">document-oriented database</a>.
Given that this is the database design we inherited, there's not much we can do about it,
so we'll try our best with what we've got. ¯\<em>(ツ)</em>/¯</p>
<p>At a billion tables, Automattic has already established its own internal best practices
with plugins like <a href="https://github.com/Automattic/hyperdb">HypderDB</a>. Unfortunately HyperDB
doesn't have <a href="https://getcomposer.org/">Composer</a> support and doesn't look
maintained. <a href="https://github.com/stuttter/ludicrousdb">LudicrousDB</a>, a Composer compatible
drop-in that works with our <a href="https://github.com/roots/bedrock/">existing tech stack</a>, to
the rescue.</p>
<blockquote>
<p>LudicrousDB is an advanced database interface for WordPress that supports replication,
fail-over, load balancing, and partitioning, based on Automattic's HyperDB drop-in.</p>
</blockquote>
<p>With LudicrousDB tested and working, we are moving towards a 101 slice approach. 1 slice
for core tables and 100 slices for books.</p>
<p>The idea is to use the last <strong>two digits</strong> of a book ID to pick one of 100 slices. If this
becomes unmanageable in the future <em>(important to remember that we already have over half
a million</em> tables <em>in 1 database and
<a href="https://knowyourmeme.com/memes/this-is-fine">things are fine</a>)</em>, we can change the
splitting algorithm by adding a condition to use the last <strong>X digits</strong> on books with IDs
bigger than <strong>Y</strong>.</p>
<h2 id="code" tabindex="-1">Code</h2>
<p><em>For informational purposes only. Read the snippets and reason about them. Copy/paste at
your own peril.</em></p>
<h2 id="ludicrous-db-callback" tabindex="-1">LudicrousDB Callback</h2>
<pre class="language-php"><code class="language-php"><span class="token comment">/**
 * Slices
 *
 * We can predict what slice a blog is in by looking
 * at the last two digits of the id. Examples:
 *
 * + blog_id: 9, in db09
 * + blog_id: 74, in db74
 * + blog_id: 999989, in db89
 * + blog_id: 9200, in db00
 *
 * @param $query
 * @param \LudicrousDB $wpdb
 *
 * @return string
 */</span>
<span class="token keyword">function</span> <span class="token function-definition function">pb_db_callback</span><span class="token punctuation">(</span> <span class="token variable">$query</span><span class="token punctuation">,</span> <span class="token variable">$wpdb</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">preg_match</span><span class="token punctuation">(</span> <span class="token string double-quoted-string">"/^<span class="token interpolation"><span class="token punctuation">{</span><span class="token variable">$wpdb</span><span class="token operator">-></span><span class="token property">base_prefix</span><span class="token punctuation">}</span></span>\d+_/i"</span><span class="token punctuation">,</span> <span class="token variable">$wpdb</span><span class="token operator">-></span><span class="token property">table</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token variable">$last_two_digits</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword type-casting">int</span><span class="token punctuation">)</span> <span class="token function">substr</span><span class="token punctuation">(</span> <span class="token variable">$wpdb</span><span class="token operator">-></span><span class="token property">blogid</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">2</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token variable">$db</span> <span class="token operator">=</span> <span class="token function">sprintf</span><span class="token punctuation">(</span> <span class="token string single-quoted-string">'db%02d'</span><span class="token punctuation">,</span> <span class="token variable">$last_two_digits</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// db00, db01, db02, ..., db99</span>
    <span class="token keyword">return</span> <span class="token variable">$db</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string single-quoted-string">'global'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token variable">$wpdb</span><span class="token operator">-></span><span class="token function">add_callback</span><span class="token punctuation">(</span> <span class="token string single-quoted-string">'pb_db_callback'</span> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="export-db-into-101-slices" tabindex="-1">Export DB Into 101 Slices:</h3>
<pre class="language-bash"><code class="language-bash"><span class="token shebang important">#!/bin/bash</span>

<span class="token comment"># This script will CREATE 101 directories in current</span>
<span class="token comment"># working directory, you have been warned!</span>

<span class="token assign-left variable">db</span><span class="token operator">=</span><span class="token string">'old_database_name'</span>

<span class="token function">sudo</span> mydumper <span class="token parameter variable">--regex</span><span class="token operator">=</span><span class="token string">"^<span class="token variable">${db}</span>\.wp_[a-zA-Z]+.*"</span> <span class="token parameter variable">--database</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${db}</span>"</span> <span class="token parameter variable">--outputdir</span><span class="token operator">=</span><span class="token string">"core"</span> --build-empty-files
<span class="token keyword">for</span> <span class="token variable"><span class="token punctuation">((</span>i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&lt;=</span><span class="token number">99</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">))</span></span><span class="token punctuation">;</span> <span class="token keyword">do</span>
  <span class="token assign-left variable">ii</span><span class="token operator">=</span><span class="token variable"><span class="token variable">`</span><span class="token builtin class-name">printf</span> %02d $i<span class="token variable">`</span></span>
  <span class="token function">sudo</span> mydumper <span class="token parameter variable">--regex</span><span class="token operator">=</span><span class="token string">"^<span class="token variable">${db}</span>\.(wp_<span class="token variable">${i}</span>_|wp_\d+<span class="token variable">${ii}</span>_).*"</span> <span class="token parameter variable">--database</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${db}</span>"</span> <span class="token parameter variable">--outputdir</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${ii}</span>"</span> --build-empty-files
<span class="token keyword">done</span></code></pre>
<h3 id="import-101-slices" tabindex="-1">Import 101 Slices:</h3>
<pre class="language-bash"><code class="language-bash"><span class="token shebang important">#!/bin/bash</span>

<span class="token comment"># This script will READ 101 directories in current</span>
<span class="token comment"># working directory</span>

<span class="token assign-left variable">db</span><span class="token operator">=</span><span class="token string">'new_database_name'</span>

<span class="token function">sudo</span> myloader <span class="token parameter variable">--directory</span><span class="token operator">=</span><span class="token string">"core"</span> <span class="token parameter variable">--database</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${db}</span>"</span> --overwrite-tables
<span class="token keyword">for</span> <span class="token variable"><span class="token punctuation">((</span>i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&lt;=</span><span class="token number">99</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">))</span></span><span class="token punctuation">;</span> <span class="token keyword">do</span>
  <span class="token assign-left variable">ii</span><span class="token operator">=</span><span class="token variable"><span class="token variable">`</span><span class="token builtin class-name">printf</span> %02d $i<span class="token variable">`</span></span>
  <span class="token function">sudo</span> myloader <span class="token parameter variable">--directory</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${ii}</span>"</span> <span class="token parameter variable">--database</span><span class="token operator">=</span><span class="token string">"<span class="token variable">${db}</span>_<span class="token variable">${ii}</span>"</span> --overwrite-tables
<span class="token keyword">done</span></code></pre>
<h2 id="did-it-work" tabindex="-1">Did it work?</h2>
<p><a href="https://youtu.be/RA5WCpFY0PE">https://youtu.be/RA5WCpFY0PE</a></p>
<p>To be continued in Part 2...</p>
<h2 id="bonus-tips" tabindex="-1">Bonus tips:</h2>
<p>Because Pressbooks has so many MySQL tables, the Clients I use are always getting stuck or
freezing. Here are some tricks I use to keep sane:</p>
<ul>
<li>Don't let MySQL Workbench load the table schemas. Set up your GUI so that schemas are in
a separate tab, disable autoloading, autocomplete, etc. <em>(Edit ⇨ Preferences ⇨ SQL
Editor)</em></li>
<li>Disable MySQL CLI auto-completion
with <a href="https://dev.mysql.com/doc/refman/5.7/en/mysql-command-options.html#option_mysql_auto-rehash"><code>--disable-auto-rehash</code></a></li>
</ul>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Our new roadmap</title>
      <link href="https://pressbooks.org/blog/2017/09/27/our-new-roadmap/"/>
      <updated>2017-09-27T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2017/09/27/our-new-roadmap/</id>
      <content type="html"><![CDATA[
        <p>At the start of 2017, we established a
development roadmap for Pressbooks to
guide our work through the coming year. This past week we had the opportunity to review
and reflect on that roadmap during our retreat at Pressbooks HQ.</p>
<h2 id="2017-year-of-core" tabindex="-1">2017: Year of Core</h2>
<p>I want to highlight a few of our accomplishments from the past nine months (you'll see
them crossed out on the old roadmap). In retrospect, our clear focus over the past nine
months was improving Pressbooks’ core technology. When Dac came back, having a second
developer let us expand upon my efforts in recent years to standardize our development
processes under the hood. We now use consistent
<a href="/docs/coding-standards/">coding standards</a> across all of our open
source projects, and we have adopted a
<a href="https://laravel.com/docs/5.5/mix">standardized build process</a> for admin and front end
assets. We have expanded our <a href="https://codecov.io/gh/pressbooks/pressbooks">code coverage</a>
on the core Pressbooks plugin, and continue to do so with every release. These
improvements let us work more efficiently and give
<a href="/docs/contributors/">open source contributors</a> a clear framework
within which to contribute to the Pressbooks ecosystem.</p>
<p>Our most significant core enhancement is our new
<a href="/docs/api/">REST API</a>, built on the
<a href="https://developer.wordpress.org/rest-api/">WordPress Core REST API</a> infrastructure. This
is the engine that powers our new
<a href="https://pressbooks.com/blog/can-you-clone-a-pressbooks-book-you-can-now/">cloning tool</a>,
and we will be making use of it in other areas over the next year. We’re also extremely
excited to see what the Pressbooks Open Source community does with an API for books. If
you are building something with it,
<a href="https://pressbooks.community/c/apis">let us know</a>.</p>
<h2 id="2018-year-of-the-author" tabindex="-1">2018: Year of the Author</h2>
<p>The roadmap for our next year has a new focus: improving Pressbooks for authors. There are
a number of editing features that we included on our last roadmap that didn’t make the
cut, and our goal for the next year is to fill as many of these gaps in the Pressbooks
authoring toolset as we can. This includes:</p>
<ul>
<li>Broadening our support for math, interactive content, video and audio across all formats
(with graceful fallbacks in static formats like PDF)</li>
<li>Adding support for multiple contributors: authors, editors, translators and more</li>
<li>Adding indexing and glossary support</li>
</ul>
<p>And more! Take a look at our new roadmap to see our
comprehensive plans for improving Pressbooks’ authorship and editing tools, as well as all
other aspects of the project.</p>
<p>I’m very excited about our accomplishments since January 2017, and I’m looking forward to
building on them over the next year. Thanks to Apurva, Dac, Hugh, Liz, and Zoe for making
Pressbooks such a productive team!</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Can you “clone” a Pressbooks book? You can now*!</title>
      <link href="https://pressbooks.org/blog/2017/08/31/can-you-clone-a-pressbooks-book-you-can-now/"/>
      <updated>2017-08-31T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2017/08/31/can-you-clone-a-pressbooks-book-you-can-now/</id>
      <content type="html"><![CDATA[
        <p>Here at Pressbooks HQ we’ve been doing a whole lot more development work for the Open
Textbook world, in our opinion the most exciting space in the world of publishing. For the
uninitiated, an Open Textbook is an openly licensed (i.e. free) book that supports the
“5Rs,” <a href="https://www.opencontent.org/definition/">defined by David Wiley</a> as the rights to:
<strong>remix, revise, reuse, retain, and redistribute</strong>.</p>
<p>Open Textbooks are powerful not just because they are free for students, but also because
teachers and profs (or even students) can easily improve them and modify them for the
particular needs of their students.</p>
<h2 id="theory-vs-practice" tabindex="-1">Theory vs. Practice</h2>
<p>In theory, at least.</p>
<p>In practice, all that 5R-y stuff can be difficult: How do you revise a PDF? How do you
remix an EPUB? How do you redistribute a print book?</p>
<h2 id="clone-me-please" tabindex="-1">Clone me, please!</h2>
<p>The new answer—at least for Open Textbooks built on Pressbooks as of now is: You
<strong>clone</strong> them!</p>
<p>That is, you can now, with the click of a button, clone/copy a complete Pressbooks book
(including all metadata, image and media, and content) from one Pressbooks account or
instance to another, as long as the original book is:</p>
<ul>
<li>Openly licensed (i.e. licensed with a Creative Commons license)</li>
<li>Publicly available on the web</li>
</ul>
<p>And this means, once you’ve cloned that book, you can 5R it to your heart’s content!</p>
<h2 id="wait-does-this-mean-anyone-can-just-copy-my-book" tabindex="-1">Wait, does this mean anyone can just copy my book?</h2>
<p>No. No. No! … No, cloning is only possible in the case that:</p>
<ul>
<li>Your book is <strong>openly licensed</strong> (with a Creative Commons license)</li>
<li>You book privacy setting is: <strong>public on the web</strong></li>
</ul>
<p>So for any books that have standard copyright, or are not available on the web—this
doesn’t apply.</p>
<h2 id="why-would-you-clone-a-book" tabindex="-1">Why would you clone a book?</h2>
<p>This is, we think, a very exciting development for the Open Textbook ecosystem.</p>
<p>Here are just some of the ways we expect the new feature to be utilized:</p>
<ul>
<li>A community college wants to make changes to the level of subject matter in an open
textbook that was originally created for upper-division undergraduates.</li>
<li>A faculty member wants to adapt an open textbook to reflect the way they personally
teach the subject matter.</li>
<li>A university department wants to copy the books contained in a catalogue at a similar
department in another university.</li>
<li>An instructor wants to make a copy in order to have their class expand an existing open
textbook as part of a classroom project.</li>
</ul>
<p>Cloning ultimately allows books built in Pressbooks to become more modular and easily
adaptable for more courses.</p>
<h2 id="pressbooks-ryerson-university-and-e-campus-ontario" tabindex="-1">Pressbooks, Ryerson University &amp; eCampus Ontario</h2>
<p>Have you heard about the exciting Open Textbook work happening in Ontario?</p>
<p>This cloning feature was developed as part of a project
<a href="https://pressbooks.com/blog/pressbooks-working-with-ryerson-university-on-ecampus-ontario-grant-open-publishing-infrastructure/">Pressbooks is doing</a>
with Ryerson University, funded by a grant from
<a href="https://www.ecampusontario.ca/news/ecampusontario-ryerson-university-to-create-open-publishing-infrastructure-for-ontario-post-secondary-educators-learners">eCampusOntario,</a>
developing infrastructure for Open Resource Publishing in Ontario.</p>
<p>Also under this project, Pressbooks is getting a full design refresh, including redesigns
of the book home page, the webbook reading interface, and, for Pressbooks systems, updates
to the landing page and Pressbooks’ built-in catalog page.</p>
<h2 id="so-how-do-i-start-cloning" tabindex="-1">So, How Do I Start Cloning?</h2>
<p>The bad news is: This feature is not available on Pressbooks.com. Cloning is an
educational feature only available in standalone Pressbooks systems (Pressbooks EDU client
systems and Pressbooks open source). (<a href="mailto:sales@pressbooks.com">Contact us</a> if you're
interested in us hosting a Pressbooks EDU system for you.)</p>
<p>Pressbooks.com also supports replicating books. However, the process of copying a book is
more labour intensive, and requires users to reach out to original creators for the book’s
XML files. This new cloning feature omits these steps for enterprise users, making
duplication possible with only a few clicks of a button.</p>
<p>Learn more about
<a href="https://guide.pressbooks.com/chapter/clone-a-book/">how to use the new cloning feature</a>.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Pressbooks working with Ryerson University on eCampusOntario grant: &quot;Open Publishing Infrastructure&quot;</title>
      <link href="https://pressbooks.org/blog/2017/05/19/pressbooks-working-with-ryerson-university-on-ecampusontario-grant-open-publishing-infrastructure/"/>
      <updated>2017-05-19T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2017/05/19/pressbooks-working-with-ryerson-university-on-ecampusontario-grant-open-publishing-infrastructure/</id>
      <content type="html"><![CDATA[
        <p>We are very very excited to announce that we’re working with
<a href="https://www.ecampusontario.ca/news/ecampusontario-ryerson-university-to-create-open-publishing-infrastructure-for-ontario-post-secondary-educators-learners">eCampusOntario and Ryerson University</a>
to improve Pressbooks as an Open Textbook authoring tool, under the just-announced
eCampusOntario project: &quot;Open Publishing Infrastructure for Ontario Post-Secondary
Educators, Learners.&quot;</p>
<p>Most of the development work we undertake under this grant will be released as open source
improvements to the <a href="https://github.com/pressbooks/pressbooks">Pressbooks GPL codebase</a> —
so anyone using Pressbooks will benefit.</p>
<h2 id="pressbooks-as-we-ve-dreamed-since-well-2010" tabindex="-1">Pressbooks as we've dreamed since, well, 2010</h2>
<p>This project is going to allow us to develop some of the most exciting capabilities of
Pressbooks, something we have been dreaming of since, well, since I started working on
Pressbooks way back in 2011.</p>
<p>In particular, we will be making some very visible improvements, including a redesign of
the “webbook” interface (for reading
<a href="https://book.pressbooks.com/">Pressbooks books online</a>) and a refresh of the standard
catalog page for dedicated Pressbooks instances (such as this one, hosted by
<a href="https://opentextbc.ca/">BCcampus</a>).</p>
<h2 id="apis-and-cloning" tabindex="-1">APIs and Cloning</h2>
<p>But the more exciting work is going on under the hood, where we’ll be migrating the
Pressbooks API (built by Brad Payne from BCcampus) to the WordPress core REST API,
extending the metadata capabilities, and building “cloning” of Pressbooks books into
Pressbooks core (also leaning on work done by Brad).</p>
<p>This means that you’ll soon be able to point at any openly-licensed Pressbooks book in the
universe, and pull it into your own Pressbooks environment, to enable the famous
<a href="https://opencontent.org/definition/">5Rs of Open Educational Resources: Retain, Reuse, Revise, Remix, Redistribute</a>.</p>
<h2 id="an-api-for-books-finally" tabindex="-1">An API for Books (finally!)</h2>
<p>What does this mean? This means Pressbooks will, finally, be able to fulfill a promise
I’ve been thinking about since I started Pressbooks back in 2011: an API for books.</p>
<p>Indeed, looking through some archives, I am gratified to see that we’ve managed to build a
lot of what I laid out in my May 2010 (!!) article for O’Reilly:
<a href="https://toc.oreilly.com/2010/05/wordpress-as-book-publishing.html">“An Open, Webby, Book-Publishing Platform.”</a></p>
<p>More exciting is that we are now poised to move beyond that initial set of ideas, and
offer something I wrote about a year later, in September 2010 (!),
<a href="http://toc.oreilly.com/2010/09/beyond-ebooks-publisher-as-api.html">An API for Books</a>.</p>
<h2 id="it-s-taken-a-while-but-we-re-getting-there" tabindex="-1">It’s taken a while, but we’re getting there!</h2>
<p>The past number of years have been an exercise in patience: We have always had dedicated
and faithful users—from self-publishers to academic presses—who love Pressbooks because of
how easy it makes formatting books for print and ebook stores.</p>
<p>But the real power of Pressbooks, from my perspective, has always been hidden in the plain
sight of the web: all Pressbooks books are web-native from the start.</p>
<h2 id="open-textbooks-and-the-web" tabindex="-1">Open Textbooks and the Web</h2>
<p>The Open Textbook movement is really the first coherent usecase for Pressbooks that has
emerged to embrace the potential in Open, webby book publishing systems. So, it’s been
gratifying to see the Pressbooks open source software being adopted in the Open Textbook
world, by such leading projects as: Lumen Learning, BCcampus, and OpenSUNY.</p>
<p>At the same time, it’s been a challenge for a small company like ours to support the
exciting Open Textbook possibilities of Pressbooks with our limited resources. This new
project will enable us to move much faster towards an Open Textbook future we hope for.</p>
<h2 id="working-with-ryerson-and-e-campus-ontario" tabindex="-1">Working with Ryerson and eCampusOntario</h2>
<p>We’re thrilled to be working with some great people at Ryerson University on this project:
Wendy Freeman, Fangmin Wang, Ann Ludbrook, Sally Wilson, and the rest of their team. And
we're excited as well to be working on an eCampus Ontario project: David Porter and Lena
Patterson have a a great vision for the future of Open Textbooks in Ontario, and we’re
excited to be part of it.</p>
<p>If you’d like more information about Pressbooks and Open Textbooks, get in touch!</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Why We Removed Pressbooks from the WordPress Plugin Repository</title>
      <link href="https://pressbooks.org/blog/2016/10/15/why-we-removed-pressbooks-from-the-wordpress-plugin-repository/"/>
      <updated>2016-10-15T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2016/10/15/why-we-removed-pressbooks-from-the-wordpress-plugin-repository/</id>
      <content type="html"><![CDATA[
        <p>A couple weeks ago, we removed Pressbooks from the WordPress Plugin Repository. We want to
offer an explanation for this decision to our users, and give some insight into our plans
for the distribution of Pressbooks moving forward.</p>
<p>Pressbooks has never been a typical WordPress plugin. It is a
<a href="https://wordpress.org/support/topic/platform-not-plugin/">platform, not a plugin</a>, and as
such it completely transforms the WordPress interface into a content management system for
book authoring and formatting. Furthermore, it requires
<a href="https://codex.wordpress.org/Create_A_Network">WordPress Multisite</a> and it also requires a
number of third-party libraries to support its export routines
(<a href="https://github.com/idpf/epubcheck">epubcheck</a>,
<a href="https://www.amazon.com/gp/feature.html?docId%3D1000765211">KindleGen</a>,
<a href="http://www.princexml.com">PrinceXML</a> and xmllint to
name a few) which cannot be installed on shared hosting environments. As such, Pressbooks
is not a WordPress plugin that is particularly useful without:</p>
<ol>
<li>A virtual private server (VPS) environment;</li>
<li>An advanced knowledge of WordPress configuration, especially multisite;</li>
<li>Some devops experience.</li>
</ol>
<p>Over the years, we have encountered many WordPress users who installed Pressbooks from the
WordPress Plugin Repository on their existing blogs[1. Don't do this!] and were frustrated
by the experience. After much consideration, we have decided that the best way to support
all users of the Pressbooks plugin is to remove it from the WordPress Plugin Repository
and distribute it via <a href="https://github.com/pressbooks/pressbooks/releases/">GitHub</a>.</p>
<p>For those who don't want to run their own Pressbooks infrastructure, we offer the
following options:</p>
<ul>
<li><a href="https://pressbooks.com/">Pressbooks.com</a>, for authors and small publishers creating a
single book or a handful of books per year</li>
<li><a href="https://pressbooks.com/for-academia/">Pressbooks EDU</a>, our premium hosted service for
educational institutions</li>
<li><a href="https://pressbooks.com/for-publishers/">Pressbooks Publisher</a>, our premium hosted
service for publishers</li>
</ul>
<p>For those who are interested in running their own networks, we are working to improve the
installation documentation and provide
<a href="https://github.com/pressbooks/pressbooks/issues/502">several</a> <a href="https://github.com/pressbooks/pressbooks/issues/502">methods</a> to
keep Pressbooks updated.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Notes from the Pressbooks Accessibility Group</title>
      <link href="https://pressbooks.org/blog/2016/09/28/notes-from-the-pressbooks-accessibility-group/"/>
      <updated>2016-09-28T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2016/09/28/notes-from-the-pressbooks-accessibility-group/</id>
      <content type="html"><![CDATA[
        <p>Pressbooks’ first meeting on accessibility with our Open Source partners took place today.
Hugh and I were joined by Jess Mitchell and Jonathan Hung from the
<a href="https://idrc.ocadu.ca">Inclusive Design Research Centre</a> at OCAD and Brad Payne and Josie
Gray from <a href="https://bccampus.ca">BCcampus</a>. We identified and discussed four initial tasks
to begin work on making Pressbooks more accessible and inclusive for authors and readers
alike:</p>
<ol>
<li>Conducting an audit of the Pressbooks administration interface for accessibility and
inclusivity (see
<a href="https://github.com/pressbooks/pressbooks/issues/487" title="Conduct accessibility &amp; inclusivity audit of administration interface">pressbooks/pressbooks#487</a>);</li>
<li>Conducting an audit of the Pressbooks web book theme and root theme interfaces for
accessibility and inclusivity (see
<a href="https://github.com/pressbooks/pressbooks/issues/488" title="Conduct accessibility &amp; inclusivity audit of web book interface">pressbooks/pressbooks#488</a>);</li>
<li>Integrating the IDRC Fluid Project’s display preferences tool into the Pressbooks web
book theme and root theme interfaces (see
<a href="https://github.com/pressbooks/pressbooks/issues/489" title="Add @fluid-project user interface options to web books and root theme">pressbooks/pressbooks#489</a>);</li>
<li>Assessing potential tools to help authors review their books’ content for accessibility
and inclusivity (see
<a href="https://github.com/pressbooks/pressbooks/issues/490" title="Accessibility &amp; inclusivity review tool for book content">pressbooks/pressbooks#490</a>).</li>
</ol>
<p>In our discussion of the fourth point, we heard from Josie, who in her work at BCcampus
has been using a combination of tools (including
<a href="https://www.totalvalidator.com/downloads/index.html">Total Validator</a> and
AChecker and manual review against to the W3C’s
<a href="https://www.w3.org/WAI/WCAG20/quickref/">Web Content Accessibility Guidelines</a> to assess
the accessibility and inclusivity of their OERs. Jess and Jonathan also recommended
<a href="https://wave.webaim.org/">WAVE</a> for this.</p>
<p>We plan to have a second meeting of the accessibility group within one month (tentatively
on Wednesday, October 26, 2016) and in the meantime, I will be working with Jess and
Jonathan to get a development instance of Pressbooks running at the IDRC for auditing
purposes, working on the integration of the Fluid display preferences module, and
continuing discussions with Jess and Jonathan on the IDRC’s metadata tools. Brad and Josie
will work on compiling a matrix of problem patterns that Josie has identified in her
content review work, and Jess and Jonathan will walk through their audit process and
results with the accessibility group at our next meeting so that we can all get a sense of
best practices. Thanks to everyone who could join us today! It was an exciting first
meeting, and we’re looking forward to continued collaboration on this important component
of the Pressbooks project.</p>

      ]]></content>
    </entry>
	
    
    <entry>
      <title>Rethinking Book Themes</title>
      <link href="https://pressbooks.org/blog/2016/05/16/rethinking-book-themes/"/>
      <updated>2016-05-16T12:00:00Z</updated>
      <id>https://pressbooks.org/blog/2016/05/16/rethinking-book-themes/</id>
      <content type="html"><![CDATA[
        <p>Pressbooks has built book themes the same way for quite a while, with the only significant
change being the switch from CSS to SCSS in Pressbooks 3.0. Shown below is the structure
for one of our open-source themes, <a href="https://github.com/pressbooks/pressbooks-clarke">Clarke</a> (with a
couple of omissions that aren’t relevant to this post).</p>
<pre class="language-treeview"><code class="language-treeview"><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name">export</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">epub</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">images</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-png">asterisk.png</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-png">em-dash.png</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">style.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">prince</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">images</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-png">em-dash.png</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-js">script.js</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">style.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_fonts-epub.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_fonts-prince.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_fonts-web.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_mixins.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-php">functions.php</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-css">style.css</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">style.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-php">theme-information.php</span><br /></span></code></pre>
<p>We’re in the midst of a significant re-think of how we build themes, and here’s what it
looks like so far.</p>
<pre class="language-treeview"><code class="language-treeview"><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name">assets</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">images</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-png">em-dash.png</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">epub</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-png">asterisk.png</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">scripts</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">prince</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-js">script.js</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">styles</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">epub</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_fonts.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">style.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">prince</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_fonts.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">style.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">web</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_fonts.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">style.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name">components</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_accessibility.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_alignment.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_colors.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_elements.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_elements-special.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_media.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_structure.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_titles.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-v">│   </span><span class="token entry-line line-h">├── </span><span class="token entry-name ext-scss">_toc.scss</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-php">functions.php</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-css">style.css</span><br /></span><span class="token treeview-part"><span class="token entry-line line-h">├── </span><span class="token entry-name ext-php">theme-information.php</span><br /></span></code></pre>
<p>All three core outputs now keep their assets in the <code>assets</code> folder, with shared assets
going in the directory roots of <code>assets/fonts</code> (when
needed), <code>assets/images</code>, <code>assets/scripts</code> and <code>assets/styles</code>. We used to keep the
uncompiled web stylesheet in the theme root along with a compiled version, but this caused
some <a href="https://github.com/pressbooks/pressbooks/issues/396">confusion</a>.
The <code>style.css</code> file in the theme root was never loaded in the web view; since Pressbooks
3.0, we’ve always used a freshly compiled version which is generated when the user changes
themes or changes their theme options. But WordPress requires that theme information be
stored in
the <a href="https://codex.wordpress.org/File_Header#Theme_File_Header_Example">file header</a> of <code>style.css</code>.
Our practice moving forward will be to use the <code>style.css</code> file in the root for theme
information only, and keep a <code>style.scss</code> file for the web book in <code>assets/styles/web/</code>.</p>
<p>Each of the files in <code>assets/styles/components</code> imports a global components file or
file(s) and a variables file for the relevant item(s) from the Pressbooks
plugin’s <code>assets/book/styles/</code> directory (which is loaded by our SCSS compiler). For
example, <code>assets/styles/components/_elements.scss</code> might contain the following:</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Elements</span>

<span class="token property"><span class="token variable">$orphans</span></span><span class="token punctuation">:</span> 3 <span class="token statement keyword">!default</span><span class="token punctuation">;</span>

<span class="token comment">// Change variables above this line, using the !default flag to allow overrides.</span>
<span class="token keyword">@import</span> <span class="token string">"variables/elements"</span><span class="token punctuation">;</span>

<span class="token comment">// Add custom SCSS below these imports and includes.</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements/links"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements/blockquotes"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements/body"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements/headings"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements/lists"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements/miscellaneous"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements/paragraphs"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"components/elements/tables"</span><span class="token punctuation">;</span>
<span class="token keyword">@include</span> <span class="token function">tables</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>In this hypothetical theme, all of the default element styles have been imported but the
theme developer has changed the orphan property from <code>1</code> to <code>3</code>. (Using the
SCSS <code>!default</code> flag allows a variable like this to be overridden by the book user once we
overhaul our <a href="https://github.com/pressbooks/pressbooks/issues/106">theme options</a>.)</p>
<p>All of these component files are imported into the EPUB, PDF and web <code>style.scss</code> files,
like so:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$type</span></span><span class="token punctuation">:</span> <span class="token string">"prince"</span><span class="token punctuation">;</span>

<span class="token keyword">@import</span> <span class="token string">"fonts"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"../components/alignment"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"../components/colors"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"../components/elements"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"../components/specials"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"../components/media"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"../components/titles"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"../components/structure"</span><span class="token punctuation">;</span>
<span class="token keyword">@import</span> <span class="token string">"../components/toc"</span><span class="token punctuation">;</span></code></pre>
<p>So now we have a book theme with a more coherent structure, comprehensive default
variables and an easy method to override them, and lots of possibilities.</p>
<p>We have lots to do to move forward with the implementation of this new theme structure
(including backwards compatibility). You can follow along on
the <a href="https://github.com/pressbooks/pressbooks/tree/theme-structure/">theme-structure</a> branch
to observe or participate in the implementation process. If you want to get involved in
the discussion of these changes, feel free to join in on the
relevant <a href="https://github.com/pressbooks/pressbooks/issues/383">GitHub issue</a>!</p>

      ]]></content>
    </entry>
	
</feed>
