Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
986 lines (896 sloc) 39.5 KB
;;; org2blog.el --- blog from Org mode to wordpress
;; Copyright (C) 2010 Benjamin Beckwith <bnbeckwith@gmail.com>
;; Copyright (C) 2010 Marcel van der Boom <marcel@hsdev.com>
;; Copyright (C) 2010,2011 Puneeth Chaganti <punchagan+org2blog@gmail.com>
;; Copyright (C) 2010 Sacha Chua <sacha@sachachua.com>
;; Copyright (C) 2010 Giovanni Moretti <Giovanni@reflections.co.nz>
;; Copyright (C) 2011 Mykola Nikishov <mn@mn.com.ua>
;; Copyright (C) 2010 Matt Price <matt@roke.mercey.dyndns.org>
;; Author: Puneeth Chaganti <punchagan+org2blog@gmail.com>
;; Version: 0.5
;; Keywords: orgmode, wordpress, blog
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;; A portion of the code in this file is based on blog.el posted to
;; http://www.mail-archive.com/gnu-emacs-sources@gnu.org/msg01576.html
;; copyrighted by Ashish Shukla. The Copyright notice from that file is
;; given below.
;; blog.el -- a wordpress posting client
;; Copyright (C) 2008 Ashish Shukla
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version 2
;; of the License, or (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
(require 'org)
(require 'xml-rpc)
(require 'metaweblog)
(defgroup org2blog/wp nil
"Post to weblogs from Emacs"
:group 'org2blog/wp)
(defcustom org2blog/wp-blog-alist nil
"Association list to set information for each blog.
Each element of the alist is a blog name. The CAR of each
element is a string, uniquely identifying the project. The CDR
of each element is a well-formed property list with an even
number of elements, alternating keys and values, specifying
parameters for the blog.
(:property value :property value ... )
When a property is given a value in org2blog/wp-blog-alist, its
setting overrides the value of the corresponding user
variable (if any) during publishing.
Most properties are optional, but some should always be set:
:url xmlrpc url of the blog.
:username username to be used.
All the other properties are optional. They over-ride the global variables.
:password password to be used
:default-title `org2blog/wp-default-title'
:default-categories `org2blog/wp-default-categories'
Use a list of categories.
(\"category1\" \"category2\" ...)
:tags-as-categories `org2blog/wp-use-tags-as-categories'
:confirm `org2blog/wp-confirm-post'
:show `org2blog/wp-show-post-in-browser'
:keep-new-lines `org2blog/wp-keep-new-lines'
:wp-latex `org2blog/wp-use-wp-latex'
:wp-code `org2blog/wp-use-sourcecode-shortcode'
:track-posts `org2blog/wp-track-posts'
"
:group 'org2blog/wp
:type '(alist :value-type plist))
(defcustom org2blog/wp-default-categories '("Uncategorized" "Hello")
"Default list of categories"
:group 'org2blog/wp
:type '(repeat string))
(defcustom org2blog/wp-buffer-template
"#+DATE: %s
#+OPTIONS: toc:nil num:nil todo:nil pri:nil tags:nil ^:nil TeX:nil
#+CATEGORY: %s
#+TAGS:
#+DESCRIPTION:
#+TITLE: %s
\n"
"The default template to be inserted in a new post buffer."
:group 'org2blog/wp
:type 'string)
(defcustom org2blog/wp-buffer-template-prefix nil
"A prefix to the default template used for a new post buffer."
:group 'org2blog/wp
:type 'string)
(defcustom org2blog/wp-default-title "Hello, World"
"Title of the new post"
:group 'org2blog/wp
:type 'string)
(defcustom org2blog/wp-use-tags-as-categories nil
"Non-nil means assign :tags: to Wordpress categories instead."
:group 'org2blog/wp
:type 'boolean)
(defcustom org2blog/wp-confirm-post nil
"Non-nil means confirm before Publishing a post."
:group 'org2blog/wp
:type 'boolean)
(defcustom org2blog/wp-show-post-in-browser 'ask
"A variable to configure if you want to view your post/draft in
the browser. Setting it to 'ask will prompt you before opening
it in the browser. Setting it to 'show will show it without
prompting. Set it to nil, to turn off viewing posts in the
browser."
:group 'org2blog/wp
:type 'boolean)
(defcustom org2blog/wp-keep-new-lines nil
"Non-nil means do not strip newlines."
:group 'org2blog/wp
:type 'boolean)
(defcustom org2blog/wp-use-sourcecode-shortcode nil
"Non-nil means convert <pre> tags to WP sourcecode blocks."
:group 'org2blog/wp
:type 'boolean)
(defcustom org2blog/wp-use-wp-latex t
"Non-nil means convert LaTeX to WP latex blocks."
:group 'org2blog/wp
:type 'boolean)
(defcustom org2blog/wp-sourcecode-default-params "light=\"true\""
"Default arguments to pass to WP syntaxhighlighter."
:group 'org2blog/wp
:type 'string)
(defcustom org2blog/wp-sourcecode-langs
(list "actionscript3" "bash" "coldfusion" "cpp" "csharp" "css" "delphi"
"erlang" "fsharp" "diff" "groovy" "javascript" "java" "javafx" "matlab"
"objc" "perl" "php" "text" "powershell" "python" "ruby" "scala" "sql"
"vb" "xml")
"List of languages supported by sourcecode shortcode of WP."
:group 'org2blog/wp
:type 'list)
(defcustom org2blog/wp-track-posts
(list ".org2blog.org" "Posts")
"File where to save logs about posts.
Set to nil if you don't wish to track posts."
:group 'org2blog/wp
:type 'list)
(defvar org2blog/wp-blog nil
"Parameters of the currently selected blog.")
(defvar org2blog/wp-blog-name nil
"Name of the blog, to pick from `org2blog/wp-blog-alist'")
(defvar org2blog/wp-categories-list nil
"List of weblog categories")
(defvar org2blog/wp-tags-list nil
"List of weblog tags")
(defvar org2blog/wp-pages-list nil
"List of WP pages.")
(defvar org2blog/wp-server-xmlrpc-url nil
"Weblog server XML-RPC URL")
(defvar org2blog/wp-server-userid nil
"Weblog server user id")
(defvar org2blog/wp-server-blogid nil
"Weblog ID")
(defvar org2blog/wp-entry-mode-map nil
"Keymap for blog entry buffer")
(defvar org2blog/wp-logged-in nil
"Flag whether user is logged-in or not")
(defvar org2blog/wp-buffer-name "*org2blog/wp-%s*"
"Name of the blog buffer")
(defvar org2blog/wp-buffer-kill-prompt t
"Ask before killing buffer")
(make-variable-buffer-local 'org2blog/wp-buffer-kill-prompt)
(defconst org2blog/wp-version "0.5"
"Current version of blog.el")
(defvar org2blog/wp-mode-hook nil
"Hook to run upon entry into mode.")
(defun org2blog/wp-kill-buffer-hook ()
"Prompt before killing buffer."
(if (and org2blog/wp-buffer-kill-prompt
(not (buffer-file-name)))
(if (y-or-n-p "Save entry?")
(progn
(save-buffer)
(org2blog/wp-save-details (org2blog/wp-parse-entry) nil
(y-or-n-p "Published?"))))))
(unless org2blog/wp-entry-mode-map
(setq org2blog/wp-entry-mode-map
(let ((org2blog/wp-map (make-sparse-keymap)))
(set-keymap-parent org2blog/wp-map org-mode-map)
(define-key org2blog/wp-map (kbd "C-c p") 'org2blog/wp-post-buffer-and-publish)
(define-key org2blog/wp-map (kbd "C-c P") 'org2blog/wp-post-buffer-as-page-and-publish)
(define-key org2blog/wp-map (kbd "C-c d") 'org2blog/wp-post-buffer)
(define-key org2blog/wp-map (kbd "C-c D") 'org2blog/wp-post-buffer-as-page)
(define-key org2blog/wp-map (kbd "C-c t") 'org2blog/wp-complete-category)
org2blog/wp-map)))
;;;###autoload
(define-minor-mode org2blog/wp-mode
"Toggle org2blog/wp mode.
With no argument, the mode is toggled on/off.
Non-nil argument turns mode on.
Nil argument turns mode off.
Commands:
\\{org2blog/wp-entry-mode-map}
Entry to this mode calls the value of `org2blog/wp-mode-hook'."
:init-value nil
:lighter " o2b"
:group 'org2blog/wp
:keymap org2blog/wp-entry-mode-map
(if org2blog/wp-mode
(run-mode-hooks 'org2blog/wp-mode-hook)))
(defun org2blog/wp-create-categories (categories)
"Create unknown categories."
(mapcar
(lambda (cat)
(if (and (not (member cat org2blog/wp-categories-list))
(y-or-n-p (format "Create '%s' category? " cat)))
(wp-new-category org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid
cat))
(add-to-list 'org2blog/wp-categories-list cat))
categories))
(defun org2blog/wp-password ()
"Set password."
(interactive)
(setq org2blog/wp-server-pass (read-passwd "Weblog password? ")))
;;;###autoload
(defun org2blog/wp-login()
"Logs into the blog. Initializes the internal data structures."
(interactive)
(if (not org2blog/wp-blog-alist)
(error "Set `org2blog/wp-blog-alist' to be able to use org2blog."))
(let ()
(setq org2blog/wp-blog-name (completing-read
"Blog to login into? ([Tab] to see list): "
(mapcar 'car
org2blog/wp-blog-alist))
org2blog/wp-blog (assoc org2blog/wp-blog-name org2blog/wp-blog-alist)
org2blog/wp-server-xmlrpc-url (plist-get (cdr org2blog/wp-blog) :url)
org2blog/wp-server-userid (eval (plist-get (cdr org2blog/wp-blog) :username))
org2blog/wp-server-blogid (or (plist-get (cdr org2blog/wp-blog) :id) "1")
org2blog/wp-server-pass (or
(eval (plist-get (cdr org2blog/wp-blog) :password))
(read-passwd "Weblog password? "))
org2blog/wp-categories-list
(mapcar (lambda (category) (cdr (assoc "categoryName" category)))
(metaweblog-get-categories org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid))
org2blog/wp-tags-list
(mapcar (lambda (tag) (cdr (assoc "slug" tag)))
(wp-get-tags org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid))
org2blog/wp-pages-list
(mapcar (lambda (pg)
(cons (cdr (assoc "page_title" pg))
(cdr (assoc "page_id" pg))))
(wp-get-pagelist org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid)))
(setq org2blog/wp-logged-in t)
(message "Logged in")))
(defun org2blog/wp-logout()
"Logs out from the blog and clears. Clears the internal data structures."
(interactive)
(setq org2blog/wp-server-xmlrpc-url nil
org2blog/wp-server-userid nil
org2blog/wp-server-blogid nil
org2blog/wp-server-pass nil
org2blog/wp-categories-list nil
org2blog/wp-tags-list nil
org2blog/wp-pages-list nil
org2blog/wp-logged-in nil)
(message "Logged out"))
;;;###autoload
(defun org2blog/wp-new-entry()
"Creates a new blog entry."
(interactive)
(if (and (not org2blog/wp-logged-in)
(y-or-n-p "You are not logged in. Login?"))
(org2blog/wp-login))
(let ((org2blog/wp-buffer (generate-new-buffer
(format org2blog/wp-buffer-name org2blog/wp-blog-name))))
(switch-to-buffer org2blog/wp-buffer)
(add-hook 'kill-buffer-hook 'org2blog/wp-kill-buffer-hook nil 'local)
(org-mode)
(insert
(or org2blog/wp-buffer-template-prefix "")
(format org2blog/wp-buffer-template
(format-time-string "[%Y-%m-%d %a %H:%M]" (current-time))
(mapconcat
(lambda (cat) cat)
(or (plist-get (cdr org2blog/wp-blog) :default-categories)
org2blog/wp-default-categories)
", ")
(or (plist-get (cdr org2blog/wp-blog) :default-title)
org2blog/wp-default-title)))
(org2blog/wp-mode t)))
(defun org2blog/wp-upload-files-replace-urls (text)
"Uploads files, if any in the html, and changes their links"
(let ((file-all-urls nil)
file-name file-web-url beg
(file-regexp "<a href=\"\\(.?*\\)\"\\|<img src=\"\\(.*?\\)\""))
(save-excursion
(while (string-match file-regexp text beg)
(setq file-name
(if (match-beginning 1)
(substring text (match-beginning 1) (match-end 1))
(substring text (match-beginning 2) (match-end 2))))
(setq file-name (save-match-data (if (string-match "^file:" file-name)
(substring file-name 7)
file-name)))
(setq beg (match-end 0))
(if (save-match-data (not (or
(string-match org-plain-link-re file-name)
(string-match "^#" file-name)
(string-equal (file-name-nondirectory file-name) ""))))
(progn
(goto-char (point-min))
(if (re-search-forward (concat "^#\\+"
(regexp-quote file-name)
" ") nil t 1)
(setq file-web-url (buffer-substring-no-properties
(point)
(or (end-of-line) (point))))
(setq file-web-url
(cdr (assoc "url"
(metaweblog-upload-file
org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid
(get-file-properties file-name)))))
(goto-char (point-max))
(newline)
(insert (concat "#+" file-name " " file-web-url)))
(setq file-all-urls
(append file-all-urls (list (cons
file-name file-web-url)))))))
(dolist (file file-all-urls)
(setq text (replace-regexp-in-string
(concat "\\(file://\\)*" (regexp-quote (car file)))
(cdr file) text))))
text))
(defun org2blog/wp-get-option (opt)
"Gets an the value of the option OP from a buffer."
(let* ((r (org-make-options-regexp (list (upcase opt) (downcase opt)))))
(save-excursion
(goto-char (point-min))
(if (re-search-forward r nil t 1)
(match-string-no-properties 2)))))
(defun org2blog/wp-get-post-parent (post-par)
"Gets the post's parent from a buffer."
(if post-par
(or (cdr (assoc
(car (split-string post-par "\\( *, *\\)" t))
org2blog/wp-pages-list))
"0")
"0"))
(defun org2blog/wp-strip-new-lines (html)
"Strip the new lines from the html, except in pre and blockquote tags."
(save-excursion
(with-temp-buffer
(let* (start-pos end-pos)
(insert html)
(setq start-pos (point-min))
(goto-char start-pos)
(while (re-search-forward
"\\(<\\(pre\\|blockquote\\).*?>\\(.\\|[[:space:]]\\)*?</\\2.*?>\\)"
nil t 1)
(setq end-pos (match-beginning 0))
(replace-regexp "\\\n" " " nil start-pos end-pos)
(setq start-pos (match-end 0))
(goto-char start-pos))
(setq end-pos (point-max))
(replace-regexp "\\\n" " " nil start-pos end-pos)
(buffer-substring-no-properties (point-min) (point-max))))))
(defun org2blog/wp-point-in-wp-sc ()
"Return True when point in sourcecode block."
(save-excursion
(let* ((pos (point))
(s-count 0)
(e-count 0))
(save-match-data
(while (re-search-backward "\\[sourcecode.*\\]" nil t)
(setq s-count (1+ s-count)))
(goto-char pos)
(while (re-search-backward "\\[/sourcecode\\]" nil t)
(setq e-count (1+ e-count))))
(> (- s-count e-count) 0))))
(defun org2blog/wp-latex-to-wp (html)
"Change inline LaTeX to wp latex blocks."
(save-excursion
(with-temp-buffer
(insert html)
(let* ((matchers (plist-get org-format-latex-options :matchers))
(re-list org-latex-regexps)
beg end re e m n block off)
(while (setq e (pop re-list))
(setq m (car e) re (nth 1 e) n (nth 2 e)
block (if (nth 3 e) "\n\n" ""))
(when (member m matchers)
(goto-char (point-min))
(save-match-data
(while (and
(re-search-forward re nil t)
(not (org2blog/wp-point-in-wp-sc)))
(cond
((equal m "$")
(unless (string-match "^latex" (match-string 4))
(replace-match (concat (match-string 1) "$latex "
(match-string 4) "$"
(match-string 6))
nil t)))
((equal m "$1")
(replace-match (concat (match-string 1) "$latex "
(substring (match-string 2) 1 -1)
"$" (match-string 3))
nil t))
((equal m "\\(")
(replace-match (concat "$latex "
(substring (match-string 0) 2 -2)
"$") nil t))
((equal m "\\[")
(replace-match (concat "<p style=\"text-align:center\"> $latex \\displaystyle "
(substring (match-string 0) 2 -2)
"$ </p>") nil t))
((equal m "$$")
(replace-match (concat "<p style=\"text-align:center\"> $latex \\displaystyle "
(substring (match-string 0) 2 -2)
"$ </p>") nil t))
((equal m "begin")
(if (equal (match-string 2) "equation")
(replace-match (concat "<p style=\"text-align:center\"> $latex \\displaystyle "
(substring (match-string 1) 16 -14)
"$ </p>") nil t)))))))))
(buffer-substring-no-properties (point-min) (point-max)))))
(defun org2blog/wp-replace-pre (html)
"Replace pre blocks with sourcecode shortcode blocks."
(save-excursion
(let (pos code lang info params src-re code-re)
(with-temp-buffer
(insert html)
(goto-char (point-min))
(save-match-data
(while (re-search-forward
"<pre\\(.*?\\)>\\(\\(.\\|[[:space:]]\\|\\\n\\)*?\\)</pre.*?>"
nil t 1)
(setq code (match-string-no-properties 2))
;; When the codeblock is a src_block
(unless (save-match-data
(string-match "example" (match-string-no-properties 1)))
;; Stripping out all the code highlighting done by htmlize
(save-match-data
(setq code (replace-regexp-in-string "<.*?>" "" code)))
(replace-match
(concat "\n[sourcecode]\n"
code
"\n[/sourcecode]\n")
nil t))))
(setq html (buffer-substring-no-properties (point-min) (point-max))))
(goto-char (point-min))
(setq pos 1)
(while (re-search-forward org-babel-src-block-regexp nil t 1)
(backward-word)
(setq info (org-babel-get-src-block-info))
(setq params (nth 2 info))
(setq code (nth 1 info))
(setq lang (nth 0 info))
(unless (member lang org2blog/wp-sourcecode-langs)
(setq lang "text"))
(setq code-re (regexp-quote (org-html-protect code)))
(setq src-re (concat "\\[sourcecode\\]\n"
code-re "\\(\n\\)*\\[/sourcecode\\]"))
(save-excursion
(with-temp-buffer
(insert html)
(goto-char pos)
(save-match-data
(re-search-forward src-re nil t 1)
(setq pos (point))
(replace-match
(concat "\n[sourcecode language=\"" lang "\" "
(if (assoc :syntaxhl params)
(cdr (assoc :syntaxhl params))
org2blog/wp-sourcecode-default-params)
"]\n" code "[/sourcecode]\n")
nil t))
(setq html (buffer-substring-no-properties (point-min) (point-max))))))))
html)
(defun org2blog/wp-parse-entry (&optional publish)
"Parse an org2blog/wp buffer."
(interactive "P")
(let* ((keep-new-lines (if (plist-member (cdr org2blog/wp-blog) :keep-new-lines)
(plist-get (cdr org2blog/wp-blog) :keep-new-lines)
org2blog/wp-keep-new-lines))
(wp-latex (if (plist-member (cdr org2blog/wp-blog) :wp-latex)
(plist-get (cdr org2blog/wp-blog) :wp-latex)
org2blog/wp-use-wp-latex))
(sourcecode-shortcode (if (plist-member (cdr org2blog/wp-blog) :wp-code)
(plist-get (cdr org2blog/wp-blog) :wp-code)
org2blog/wp-use-sourcecode-shortcode))
html-text post-title post-id post-date tags categories narrow-p
cur-time post-par)
(save-restriction
(save-excursion
(if (not org2blog/wp-mode)
(org-save-outline-visibility 'use-markers (org-mode-restart))
(org-save-outline-visibility 'use-markers (org-mode-restart))
(org2blog/wp-mode t))
(setq narrow-p (not (equal (- (point-max) (point-min)) (buffer-size))))
(if narrow-p
(progn
(setq post-title (or (org-entry-get (point) "TITLE")
(nth 4 (org-heading-components))))
(setq excerpt (org-entry-get (point) "DESCRIPTION"))
(setq permalink (org-entry-get (point) "PERMALINK"))
(setq post-id (or (org-entry-get (point) "POSTID")
(org-entry-get (point) "POST_ID")))
(setq post-par (org2blog/wp-get-post-parent
(org-entry-get (point) "PARENT")))
;; Set post-date to the Post Date property or look for timestamp
(setq post-date (or (org-entry-get (point) "POST_DATE")
(org-entry-get (point) "SCHEDULED")
(org-entry-get (point) "DEADLINE")
(org-entry-get (point) "TIMESTAMP_IA")
(org-entry-get (point) "TIMESTAMP")))
(setq tags (mapcar 'org-no-properties (org-get-tags-at (point) nil)))
(setq categories (org-entry-get (point) "CATEGORY"))
(setq categories (if categories
(split-string categories "\\( *, *\\)" t)
"")))
(setq post-title (or (plist-get (org-infile-export-plist) :title)
"No Title"))
(setq excerpt (plist-get (org-infile-export-plist) :description))
(setq permalink (org2blog/wp-get-option "PERMALINK"))
(setq post-id (org2blog/wp-get-option "POSTID"))
(setq post-par (org2blog/wp-get-post-parent
(org2blog/wp-get-option "PARENT")))
(setq post-date (plist-get (org-infile-export-plist) :date))
(setq tags (org2blog/wp-get-option "TAGS"))
(setq tags (if tags (split-string tags "\\( *, *\\)" t) ""))
(setq categories (org2blog/wp-get-option "CATEGORY"))
(setq categories (if categories
(split-string categories "\\( *, *\\)" t)
"")))
;; Convert post date to ISO timestamp
;;add the date of posting to the post. otherwise edits will change it
(setq cur-time (format-time-string (org-time-stamp-format t t) (org-current-time)))
(setq post-date
(format-time-string "%Y%m%dT%T%z"
(if post-date
(apply 'encode-time (org-parse-time-string post-date))
(current-time)
(if narrow-p
(org-entry-put (point) "POST_DATE" cur-time)
(save-excursion
(goto-char (point-min))
(insert (concat "#+DATE: " cur-time "\n")))))
t))
(if
(if (plist-member (cdr org2blog/wp-blog) :tags-as-categories)
(plist-get (cdr org2blog/wp-blog) :tags-as-categories)
org2blog/wp-use-tags-as-categories)
(setq categories tags
tags nil))
(save-excursion
(if (not narrow-p)
(setq html-text (org-export-as-html nil nil nil 'string t nil))
(setq html-text
(org-export-region-as-html
(1+ (and (org-back-to-heading) (line-end-position)))
(org-end-of-subtree)
t 'string)))
(setq html-text (org-no-properties html-text)))
(setq html-text (org2blog/wp-upload-files-replace-urls html-text))
(unless keep-new-lines
(setq html-text (org2blog/wp-strip-new-lines html-text)))
(when sourcecode-shortcode
(setq html-text (org2blog/wp-replace-pre html-text)))
(when wp-latex
(setq html-text (org2blog/wp-latex-to-wp html-text)))))
(list
(cons "point" (point))
(cons "subtree" narrow-p)
(cons "date" post-date)
(cons "title" (org-html-do-expand post-title))
(cons "tags" tags)
(cons "categories" categories)
(cons "post-id" post-id)
(cons "parent" post-par)
(cons "excerpt" (org-html-do-expand (or excerpt "")))
(cons "permalink" (or permalink ""))
(cons "description" html-text))))
(defun org2blog/wp-post-buffer-and-publish ()
"Post buffer and mark it as published"
(interactive)
(org2blog/wp-post-buffer t))
(defun org2blog/wp-post-buffer (&optional publish)
"Posts new blog entry to the blog or edits an existing entry."
(interactive "P")
(org2blog/wp-mode t) ;; turn on org2blog-wp-mode
(unless org2blog/wp-logged-in
(org2blog/wp-login))
(save-excursion
(save-restriction
(let ((post (org2blog/wp-parse-entry))
(confirm (and
(if (plist-member (cdr org2blog/wp-blog) :confirm)
(plist-member (cdr org2blog/wp-blog) :confirm)
org2blog/wp-confirm-post)
publish))
(show (or (plist-member (cdr org2blog/wp-blog) :show)
org2blog/wp-show-post-in-browser))
post-id)
(org2blog/wp-create-categories (cdr (assoc "categories" post)))
(setq post-id (cdr (assoc "post-id" post)))
(when confirm
(if (not (y-or-n-p (format "Publish %s ?"
(cdr (assoc "title" post)))))
(error "Post cancelled.")))
(if post-id
(metaweblog-edit-post org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
post-id
post
publish)
(setq post-id (metaweblog-new-post org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid
post
publish))
(if (cdr (assoc "subtree" post))
(org-entry-put (point) "POSTID" post-id)
(goto-char (point-min))
(insert (concat "#+POSTID: " post-id "\n"))))
(org2blog/wp-save-details post post-id publish)
(message (if publish
"Published (%s): %s"
"Draft (%s): %s")
post-id
(cdr (assoc "title" post)))
(when (or (equal show 'show)
(and
(equal show 'ask)
(y-or-n-p
"[For drafts, ensure you login] View in browser? y/n")))
(if (cdr (assoc "subtree" post))
(org2blog/wp-preview-subtree-post)
(org2blog/wp-preview-buffer-post)))))))
(defun org2blog/wp-post-buffer-as-page-and-publish ()
"Alias to post buffer and mark it as published"
(interactive)
(org2blog/wp-post-buffer-as-page t))
(defun org2blog/wp-post-buffer-as-page (&optional publish)
"Posts new page to the blog or edits an existing page."
(interactive "P")
(unless org2blog/wp-logged-in
(org2blog/wp-login))
(save-excursion
(save-restriction
(widen)
(let ((post (org2blog/wp-parse-entry))
(confirm (and
(if (plist-member (cdr org2blog/wp-blog) :confirm)
(plist-member (cdr org2blog/wp-blog) :confirm)
org2blog/wp-confirm-post)
publish))
(show (or (plist-member (cdr org2blog/wp-blog) :show)
org2blog/wp-show-post-in-browser))
post-id)
(org2blog/wp-create-categories (cdr (assoc "categories" post)))
(setq post-id (cdr (assoc "post-id" post)))
(when confirm
(if (not (y-or-n-p (format "Publish %s ?"
(cdr (assoc "title" post)))))
(error "Post cancelled.")))
(if post-id
(wp-edit-page org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid
post-id
post
publish)
(setq post-id (wp-new-page org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid
post
publish))
(setq org2blog/wp-pages-list
(mapcar (lambda (pg)
(cons (cdr (assoc "title" pg))
(cdr (assoc "page_id" pg))))
(wp-get-pagelist org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
org2blog/wp-server-blogid)))
(if (cdr (assoc "subtree" post))
(org-entry-put (point) "POSTID" post-id)
(goto-char (point-min))
(insert (concat "#+POSTID: " post-id "\n"))))
(org2blog/wp-save-details post post-id publish)
(message (if publish
"Published (%s): %s"
"Draft (%s): %s")
post-id
(cdr (assoc "title" post)))
(when (or (equal show 'show)
(and
(equal show 'ask)
(y-or-n-p
"[For drafts, ensure you login] View in browser? y/n")))
(if (cdr (assoc "subtree" post))
(org2blog/wp-preview-subtree-post)
(org2blog/wp-preview-buffer-post)))))))
(defun org2blog/wp-delete-entry (&optional post-id)
(interactive "P")
(unless org2blog/wp-logged-in
(org2blog/wp-login))
(if (null post-id)
(setq post-id (org2blog/wp-get-option "POSTID")))
(metaweblog-delete-post org2blog/wp-server-xmlrpc-url
org2blog/wp-server-userid
org2blog/wp-server-pass
post-id)
(message "Post Deleted"))
(defun org2blog/wp-delete-page (&optional page-id)
(interactive "P")
(unless org2blog/wp-logged-in
(org2blog/wp-login))
(if (null page-id)
(setq page-id (org2blog/wp-get-option "POSTID")))
(wp-delete-page org2blog/wp-server-xmlrpc-url
org2blog/wp-server-blogid
org2blog/wp-server-userid
org2blog/wp-server-pass
page-id)
(message "Page Deleted"))
(defun org2blog/wp-save-details (post pid pub)
"Save the details of posting, to a file."
(save-excursion
(when (if (plist-member (cdr org2blog/wp-blog) :track-posts)
(car (plist-get (cdr org2blog/wp-blog) :track-posts))
(car org2blog/wp-track-posts))
(let* ((o2b-id (if (cdr (assoc "subtree" post))
(concat "id:" (org-id-get nil t))
(buffer-file-name)))
(log-file (if (plist-member (cdr org2blog/wp-blog) :track-posts)
(car (plist-get (cdr org2blog/wp-blog) :track-posts))
(car org2blog/wp-track-posts)))
(log-file (if (file-name-absolute-p log-file)
log-file
(if org-directory
(expand-file-name log-file org-directory)
(message "org-track-posts: filename is ambiguous
use absolute path or set org-directory")
log-file)))
(headline (if (plist-member (cdr org2blog/wp-blog) :track-posts)
(cadr (plist-get (cdr org2blog/wp-blog) :track-posts))
(cadr org2blog/wp-track-posts)))
p)
(when o2b-id
(with-current-buffer (or (find-buffer-visiting log-file)
(find-file-noselect log-file))
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(show-all)
(setq p (org-find-exact-headline-in-buffer headline))
(if p
(progn (goto-char p) (org-narrow-to-subtree) (end-of-line))
(goto-char (point-max))
(if (y-or-n-p (format "Heading '%s' not in '%s'; Create?"
headline log-file))
(progn (org-insert-heading t) (insert headline)
(org-narrow-to-subtree))))
(if (search-forward o2b-id nil t 1)
(progn
(org-back-to-heading)
(forward-thing 'whitespace)
(kill-line))
(org-insert-subheading t)))
(org2blog/wp-update-details post o2b-id pid pub))
(save-buffer)))))))
(defun org2blog/wp-update-details (post o2b-id pid pub)
"Inserts details of a new post or updates details."
(insert (format "[[%s][%s]]"
(if (cdr (assoc "subtree" post))
o2b-id
(concat "file:" o2b-id))
(cdr (assoc "title" post))))
(org-entry-put (point) "POSTID" (or pid ""))
(org-entry-put (point) "POST_DATE" (cdr (assoc "date" post)))
(org-entry-put (point) "Published" (if pub "Yes" "No")))
(defun org2blog/wp-complete-category()
"Provides completion for categories and tags."
(interactive)
(let* (current-pos tag-or-category-list)
(setq current-pos (point))
(forward-line 0)
(forward-char 2)
(if (or (looking-at "CATEGORY: ") (looking-at "TAGS: ")
(looking-at "PARENT: "))
(progn
(cond
((looking-at "TAGS: ")
(setq tag-or-cat-list org2blog/wp-tags-list)
(setq tag-or-cat-prompt "Tag ?"))
((looking-at "CATEGORY: ")
(setq tag-or-cat-list org2blog/wp-categories-list)
(setq tag-or-cat-prompt "Category ?"))
((looking-at "PARENT: ")
(setq tag-or-cat-list org2blog/wp-pages-list)
(setq tag-or-cat-prompt "Parent ?")))
(goto-char current-pos)
(let ((word-match (or (current-word t) ""))
(completion-match nil))
(when word-match
(setq completion-match (completing-read tag-or-cat-prompt tag-or-cat-list nil nil word-match))
(when (stringp completion-match)
(search-backward word-match nil t)
(replace-match (concat completion-match ", ") nil t)))))
(progn
(goto-char current-pos)
(command-execute (lookup-key org-mode-map (kbd "C-c t")))))))
;;;###autoload
(defun org2blog/wp-post-subtree (&optional publish)
"Post the current entry as a draft. Publish if PUBLISH is non-nil."
(interactive "P")
(save-restriction
(save-excursion
(org-insert-heading-after-current)
(org-backward-same-level 1)
(org-narrow-to-subtree)
(org-id-get nil t "o2b")
(goto-char (point-min))
(setq level (1- (org-reduced-level (org-outline-level))))
(dotimes (n level nil) (org-promote-subtree))
(org2blog/wp-post-buffer publish)
(dotimes (n level nil) (org-demote-subtree))
(widen)
(org-forward-same-level 1)
(delete-region (or (beginning-of-line) (point))
(1+ (or (end-of-line) (point))))
(save-buffer))))
;;;###autoload
(defun org2blog/wp-track-buffer ()
"Save details of current buffer in the tracking file."
(interactive)
(save-restriction
(save-excursion
(widen)
(org2blog/wp-save-details (org2blog/wp-parse-entry) "" nil))))
;;;###autoload
(defun org2blog/wp-track-subtree ()
"Save details of current subtree in the tracking file."
(interactive)
(save-restriction
(save-excursion
(org-narrow-to-subtree)
(org2blog/wp-save-details (org2blog/wp-parse-entry) "" nil)
(widen))))
;;;###autoload
(defun org2blog/wp-preview-buffer-post ()
"Preview the present buffer in browser, if posted."
(interactive)
(unless org2blog/wp-logged-in
(org2blog/wp-login))
(let* ((postid (org2blog/wp-get-option "POSTID"))
(url org2blog/wp-server-xmlrpc-url))
(if (not postid)
(message "This buffer hasn't been posted, yet.")
(setq url (substring url 0 -10))
(setq url (concat url "?p=" postid "&preview=true"))
(browse-url url))))
;;;###autoload
(defun org2blog/wp-preview-subtree-post ()
"Preview the present subtree in browser, if posted."
(interactive)
(unless org2blog/wp-logged-in
(org2blog/wp-login))
(let* ((postid (or (org-entry-get (point) "POSTID")
(org-entry-get (point) "POST_ID")))
(url org2blog/wp-server-xmlrpc-url))
(if (not postid)
(message "This subtree hasn't been posted, yet.")
(setq url (substring url 0 -10))
(setq url (concat url "?p=" postid "&preview=true"))
(browse-url url))))
(provide 'org2blog)
Jump to Line
Something went wrong with that request. Please try again.