Skip to content

Latest commit

 

History

History
538 lines (413 loc) · 24.6 KB

DEVELOPMENT.org

File metadata and controls

538 lines (413 loc) · 24.6 KB

Development

About

Org2Blog Developer Documentation.

Table Of Contents

Loading Up The Source Code By Hand

Here is where to start:

The constant org2blog-def--package helps manage Org2Blog’s dependencies. Here are helper functions to quickly get you started:

  • org2blog-def-checkout-statement creates Git commands to get the code from GitHub into the directory you want it stored. Call it and input the directory name. Finally copy and paste the commands from *Messages* into your Terminal to run them.
  • org2blog-def-load-statement creates Elisp code to load the libraries. Call it and input the directory name. Copy and paste the commands from *Messages* into your init file. Finally run them. Now they will get loaded each time you start Emacs.

For example, you should see something like this:

cd ~/tmp
git clone https://github.com/hniksic/emacs-htmlize.git ~/tmp/htmlize
cd htmlize
git checkout release/1.56
cd ..

And this

(add-to-list 'load-path "/Users/gcr/mysrc/htmlize")

Note: the correct tag of the project is loaded automatically.

Now you’ve got everything you need to run Org2Blog against its source code.

With this set up you can start playing around with things and even making changes. When you scratch an itch: create your branch and submit a pull request. It’s fun, easy, and makes Org2Blog better for all its users.

Software Packages Used

Org2Blog uses these libraries:

/docs/o2b-external-libraries.png

(Source code for this image follows)

@startmindmap
!theme plain
caption Read Left To Right
title Referenced Libraries
header
  Org2Blog Docs
endheader
center footer Org2Blog DEVELOPMENT

* org2blog
left side
** Internal
*** org
*** ox-wp
*** subr-x
** External
*** htmlize
*** hydra
*** xml-rpc
*** metaweblog
@endmindmap

Getting Started With Development

  • You may have already set up your codebase to run Org2Blog, but if you haven’t, then find out how up in the Installation section.
  • Readme
    • If you made any changes in the README then rebuild the Table of Contents just to be sure it’s correct. Follow the directions here.
  • Contributing
    • Read the contributing guidelines.
    • Before your commit make sure that byte-compile-file, checkdoc, and package-lint-current-buffer don’t report any errors. The first two are included with Emacs. package-lint you can either install using MELPA or you can also install it by hand like you did the other packages, like this:
      cd ~/src
      git clone https://github.com/purcell/package-lint.git
              

      Use this code to load it:

      (add-to-list 'load-path "~/src/package-lint")
      (require 'package-lint)
              
    • Note: Org2Blog uses non-standard separators in its naming. The naming will address it in a future release.
      error: `org2blog/wp-version' contains a non-standard separator `/', use hyphens instead (see Elisp Coding Conventions).
              
  • Testing
    • Programmatic Interactive System Testing
      • Working with posts and pages is the most critical 80% of this package. This core functionality should always work well and be easy to test. And it’s easy to test. It only takes 3 steps to get the system tests running.
        • Define three system variables for the blog you will test against like this:
          O2BXMLRPC="https://yourblog.com/xmlrpc.php"
          O2BUSER="user"
          O2BPASSWORD="password"
                          
        • Load and evaluate System Test Program.
          • Start Emacs in an empty environment before loading Org2Blog and performing the testing by starting Emacs like this: emacs --no-init-file
          • Load (or open and evalute it) it because it’s not a package.
        • Now you’ve got everything you need to start automatically going through the entire blogging process. The test functions will log you in, create and display posts, modify them, publish them, and finally trash them. At each step, there is a pause so you can observe what is happening on the blog. Testing is a great way to see how the workflow works, too, if you’ve never blogged before. These four functions cover everything.
          • defun org2blog--test-buffer-post
          • defun org2blog--test-buffer-page
          • defun org2blog--test-subtree-post
          • defun org2blog--test-subtree-page
      • If you need a test WordPress system to use you can set up a free WordPress blog here.
    • Manual System Testing
      • Here is a detailed Test Plan for manually testing every feature of this system. It’s a great way to see everything that can be done with Org2Blog.
  • Release Process.
  • Rules

Package Questions And Answers

In some ways Org2Blog can be surprising. Since it bridges that gap between Org mode documents and WordPress blog posts sometimes there can be a little friction. That is where most of the questions come from in the form of something like “Why does Org2Blog …fill in the blank…? Because it’s really weird!”. Be at ease though, this section should clear up some the weirdness ASAP.

Why Does Org2blog Talk About Save, View, Publish, And Trash So Much?

Most software out there has some version of Create, read, update and delete (CRUD). In our case it has to do with WordPress Entries and Pages. In techie language you would talk about CRUD’ing them. In WordPress language you talk about Saving, Viewing, Publishing, and Trashing. Org2Blog chose to use the WordPress language: it’s less surprising and makes it easier to keep the idea that Org2Blog fits into your WordPress workflow in your mind.

Take time to learn that workflow outside of Org2Blog. It will save you from uncomfortable situations where your Entry enters a weird state. At least it can feel weird. For example when you make changes to an Entry and save it, it will enter the Status of Draft. From here you only have two options to move it back to a Published state: Save the changes you made, or Save it without any changes. If you’ve never encountered this before it can be upsetting when the URL for your Entry always says preview=true. Whenever you get into a confusing situation be sure to access your blog inside of the WordPress UI to find out more about what is happening. Usually it’s something really simple. Then step back and see what Org2Blog is doing within the WordPress workflow.

Those words are also used because they reflect the natural workflow of working with WordPress that looks like this:

⮎Save → View → Publish⮌ Trash⁉

Blogging with WordPress is an iterative workflow, going through the cycle as many times as desired. Org2Blog supports and facilitates this workflow very well. This workflow is so important in fact that the entire right side of the main menu is dedicated to realizing it.

Why Does Org2blog Talk About Buffers, Subtrees, Posts, And Pages So Much?

WordPress doesn’t see much difference between a Post and a Page, so Org2Blog doesn’t either. Here are some terms to help clarify things:

  • Blog is shorthand for Web Log
  • Every post you make on your blog is called an Entry
  • Org2Blog stores Entries in either a Buffer or a Subtree
  • Every Entry can be either a Post or a Page

Here is how to visualize it remembering this is supposed to make it easier to make sense of how Org2Blog works behind the scenes:

/docs/o2b-entry-source-dest-flow.png

(Source code for this image follows)

@startmindmap
!theme plain
caption Read Left To Right
title Data Flow From Org2Blog Entries To WordPress
header
  Org2Blog Docs
endheader
center footer Org2Blog README

* Org2Blog
** 🠊 WordPress Post
** 🠊 WordPress Page
left side
** Buffer Entry 🠊
** Subtree Entry 🠊
@endmindmap

This simplicity can actually lead to some less comfortable situations where you accidentally publish one thing as another (it’s pretty easy to fix anyway though).

Although Org2Blog is implemented how WordPress works, it can surprising to see these words used. However you’ll get used to it pretty quickly.

Why Isn’t The Package Name Org2wordpress?

When Org2Blog was created its technical name, its package name, was org2blog. Unbeknownst to us there was another package out there named Org2BlogAtom with the same package name!

These unforeseen naming conflicts do happen more than you might thing and it had to be resolved. Since they both had the same package name they needed some way to differentiate themselves from each other and the slash/suffix approach was chosen resulting in org2blog/atom and org2blog/wp. So why doesn’t this package say ‘Org2Blog/WP’ all over the place today?

That is another historical accident. This package became known simply as Org2Blog without the /WP, and the name stuck. Part of the reason might be that Org2BlogAtom seems unavailable and no longer maintained. Its wiki page hasn’t had any updates on the topic either. Having made this decision it made sense to change the artifact naming scheme to org2blog instead of org2blog/wp. It’s easier to understand and adheres to artifact naming best practices. Over time existing /wp names are slowly being migrated. That still doesn’t answer the original question yet!

Org2Blog is blogging software. You write everything in Org mode and publish it to a blog. It’s pretty simple. Currently it publishes to WordPress. Could it publish to any other blog? With some work definitely. Its impossible to rule out using Org2Blog to blog to other blogs in addition to WordPress.

In that historical context and considering goals today the name remains Org2Blog instead of Org2WordPress.

How Does Org2blog Manage Autoloads?

Preemptive TL;DR: It doesn’t—Packages are not supposed to manage autoloads.

The autoload facility delays loading Elisp files until their contents are actually used improving Emacs startup times. To state it even more simply: it’s how to lazy-load packages. Anytime you see code prefixed with the default magic autoload comment ;;;###autoload you can use it (for example call a function) before the its package is loaded. Org2Blog has lots of autoload‘ed functions. Emacs learns about them by reading the autoloads file. There are three entities that can manage the autoloads file along with their decision of whether or not they will:

  • Org2Blog: Won’t do it
  • You: Should not do it
  • A Package Manager: Will do it by design—And Easily

Org2Blog does not manage an autoloads file because packages are not supposed to manage it. Usage and management of an autoloads file is a personal decision made by the user or their choice package manager. By design packages never assume the responsibility. For reference at the moment there are 5,258 packages in MELPA and only one of them includes an autoloads file. Like anything there are exceptions to the rule but Org2Blog isn’t one of them. Another entity who can manage the autoloads file is you.

With an inordinate amount of effort you can create the autoloads file and load it yourself. However it’s likely not worth the effort. Disk drives today are fast. Disk drives of 20 years ago are almost as fast (this applies to whatever the current year is). Drive speed improvements take care of the load time issue. That leaves the time required to manage the autoloads file. If you want to manage the autoloads file yourself you need to create, load it, and update it whenever autoloaded values are changed. It’s even more work better left to a program. If you insist then have at it. Otherwise make your life easy and let the package manager do it for you.

Package Managers by design are responsible for creating the autoloads file for you. It requires no effort and likely zero customization on your part. It’s that simpler. Even better though would be something simpler.

The simplest way to handle autoloads is simply never to use them at all. There is essentially never a good justification for using autoloads. There is almost always another way to achieve your goal. The worst part is that once people start relying on that features autoload behavior you can never remove it later on without creating pain for the user.

The best code is the code that doesn’t exist: that includes autoloads. Bit by bit Org2Blog will keep moving towards a future without them.

MetaWeblog

What Is MetaWeblog?

Via Wikipedia:

The MetaWeblog API is an application programming interface created by software developer Dave Winerin 2002 that enables weblog entries to be written, edited, and deleted using web services.

The API is implemented as an XML-RPC web service with three methods whose names describe their function: metaweblog.newPost(), metaweblog.getPost() and metaweblog.editPost(). These methods take arguments that specify the blog author’s username and password along with information related to an individual weblog entry.

What Blogs Use MetaWeblog?

What Is The Official MetaWeblog API?

The official definition only contains three methods:

  • metaweblog.editPost()
  • metaweblog.getPost()
  • metaweblog.newPost()

That doesn’t seem like enough. A cursory glance at various implementations reveals there are likely more. The problem is that neither the specification homepage―nor Web.Archive.Org’s snapshot of it―is available to confirm that. This leaves us in the situation of having to deduce the current MetaWeblog API specification by studying what is implemented by the servers and the client software. Since WordPress definitely supports MetaWeblog, Org2Blog starts here.

MetaWeblog’s API Support

This library provides the following for what is believed to be the current MetaWeblog API standard:

Method URLSupported
metaWeblog.deletePostYes
metaWeblog.editPostYes
metaWeblog.getCategoriesYes
metaWeblog.getPostYes
metaWeblog.getRecentPostsYes
metaWeblog.getTemplateNo
metaWeblog.getUsersBlogsYes
metaWeblog.newMediaObjectYes
metaWeblog.newPostYes
metaWeblog.setTemplateNo
  • Note
    • This reflects the subset supported by WordPress.
    • This definition reflects what other implementations support.
    • Looking at other implementations the support for getTemplate and setTemplate is about fifty-percent. The reason why is unknown. It will be helpful to understand why.

WordPress’s API Support

In addition to MetaWeblog this library provides the following XML-RPC WordPress API methods:

  • wp.deletePage
  • wp.editPage
  • wp.getPageList
  • wp.getPages
  • wp.getTags
  • wp.newCategory
  • wp.newPage

Why is MetaWeblog In This Project?

  1. Org2Blog maintains MetaWeblog as an independent library for common usage
  2. MetaWeblog provides critical functionality for Org2Blog

Data Model & Functional Design

Org2Blog’s data model addresses only two ideas:

  • You write an Entry (SOURCE) that gets published to either a WordPress Post or Page (DEST)
  • An Entry is defined in either a Buffer or a Subtree

All of the functions revolve around these two ideas.

Object-Orientation is not used with either the data or implementation. With only two data types the effort isn’t justified. With that in mind functions must manually manually address this implementation scenario:

o2b-entry-source-dest-flow.png

Consequently key functions all either include (or deduce) the variables:

SOURCE
Either ~’buffer~ or ~’subtree~
DEST
Either ~’post~ ~’page~

From the user’s perspective the source data is virtually identical: you write an Entry that gets published out to WordPress. It’s really that simple.

From WordPress’s perspective a Post and Page are almost identical too. Therefore many of the functions can be reused with slight differences.

Since WordPress follows the CRUD model Org2Blog will only need four implementations for each operation type documented here addressing SOURCE 🠆 DEST:

  • Buffer 🠆 Post
  • Buffer 🠆 Page
  • Subtree 🠆 Post
  • Subtree 🠆 Page

Resulting in 4x4 combination. Here is how the each work.

In the interest of brevity the org2blog- prefix is removed from the function names.

The node document format below is:

  • Function name: newline
  • Argument names: newline
  • Values passed to next function in round parens: (🠆 args…)

Create

org2blog--new creates the content but doesn’t publish it yet. See Save.

It works like this:

  • Confirm the destination type is valid or error out
  • Maybe login
  • Prepare a buffer to population with Entry content
  • Insert Entry specific content
  • Maybe track it’s creation

/docs/o2b-entry-new-flow.png]]

(Source code for this image follows)

@startmindmap
!theme plain
caption Read Left To Right
title Creation Function Flow
header
  Org2Blog Docs
endheader
center footer Org2Blog DEVELOPMENT

* -new\nsource
left side
** buffer-new\n('buffer 🠆)
** subtree-new\n('subtree 🠆)
@endmindmap

Read Aka View

org2blog-entry-view works like this:

  • Subtree processing is almost identical to a Buffer. Therefore make a note right away this for a subtree
  • Get the Post ID. If there isn’t one then error out.
  • Prepare the preview URL
  • Open in web browser

/docs/o2b-entry-view-flow.png]]

(Source code for this image follows)

@startmindmap
!theme plain
caption Read Left To Right
title View Function Flow
header
  Org2Blog Docs
endheader
center footer Org2Blog DEVELOPMENT

* entry-view\nsource dest
left side
** buffer-post-view\n('buffer 'post 🠆)
** buffer-page-view\n('buffer 'page 🠆)
** subtree-view\ndest\n('subtree dest 🠆)
*** subtree-post-view\n('post 🠆)
*** subtree-page-view\n('page 🠆)
@endmindmap

Update Aka Create Or Save

From a WordPress perspective both Create and Save are the same thing. The only difference is whether or not they’re a Draft, and private, or published and pubic.

org2blog-entry-save works like this:

  • Maybe login
  • Subtree processing is almost identical to a Buffer. Therefore make a note right away this for a subtree
  • Maybe auto-save and auto-post it
  • Either create or save the post
  • Update the Entry with the new ID

/docs/o2b-entry-create-save-flow.png]]

(Source code for this image follows)

@startmindmap
!theme plain
caption Read Left To Right
title Create & Save Function Flow
header
  Org2Blog Docs
endheader
center footer Org2Blog DEVELOPMENT

* entry-save\nsource type &publish
left side
** buffer-post-save\n&publish\n('buffer 'post publish)
*** buffer-post-publish\n(t)
** subtree-post-save\n&publish\n('subtree 'post publish)
*** subtree-post-publish\n(t)
** buffer-page-save\n&publish\n('buffer 'page publish)
*** buffer-page-publish\n(t)
** subtree-page-save\n&publish\n('subtree 'page publish)
*** subtree-page-publish\n(t)
@endmindmap

Delete

org2blog-entry-trash works like this:

  • Get the Post ID
  • Maybe confirm the trashing
  • Trash it

/docs/o2b-entry-trash-flow.png

@startmindmap
!theme plain
caption Read Left To Right
title Delete Flow
header
  Org2Blog Docs
endheader
center footer Org2Blog DEVELOPMENT

* entry-trash\n&post-id
left side
** buffer-post-trash\n&post-id\n('post post-id)
** subtree-post-trash\n&post-id\n('post post-id)
** buffer-page-trash\n&page-id\n('page page-id)
** subtree-page-trash\n&page-id\n('page post-id)
@endmindmap