Added Metadata Plugin and documentation.
This commit is contained in:
parent
96512011a0
commit
4303be09ac
3 changed files with 125 additions and 4 deletions
|
@ -39,6 +39,34 @@
|
||||||
|
|
||||||
**Example**: `(gh-pages :cname t)`
|
**Example**: `(gh-pages :cname t)`
|
||||||
|
|
||||||
|
## SEO and Social Metadata
|
||||||
|
|
||||||
|
**Description**: Adds description and keywords metadata for SEO purposes.
|
||||||
|
Adds both Open Graph and Twitter Cards metadata for sharing posts as well.
|
||||||
|
`:twitter` keyword argument sets "site" property of Twitter.
|
||||||
|
Twitter Card specific metadata will be omitted if this property is not set.
|
||||||
|
`:card` keyword argument sets the type of Twitter card created.
|
||||||
|
Possible types are `:summary` and `:image`. Defaults to `:summary`.
|
||||||
|
|
||||||
|
Five *optional* tags for post file header are added.
|
||||||
|
|
||||||
|
`keywords:` comma, seperated, seo, keywords.
|
||||||
|
They will be generated from tags if empty.
|
||||||
|
|
||||||
|
`description:` Description to be used in SEO and
|
||||||
|
Open Graph description tags. If empty, Open Graph description will be generated
|
||||||
|
from content while SEO description metadata will be omitted.
|
||||||
|
|
||||||
|
`image:` either an absolute (`http://www.example.com/image.png`)
|
||||||
|
or a root-relative (`/static/image.png`) image URL.
|
||||||
|
|
||||||
|
`card:` Overrides Twitter Card type defined in plugin activation.
|
||||||
|
Possible values are either `image` or `summary`.
|
||||||
|
|
||||||
|
`creator:` Twitter username of the content creator.
|
||||||
|
|
||||||
|
**Example**: `(metadata :twitter "twitter_account" :card :summary)`
|
||||||
|
|
||||||
## Incremental Builds
|
## Incremental Builds
|
||||||
|
|
||||||
**Description**: Primarily a performance enhancement. Caches the
|
**Description**: Primarily a performance enhancement. Caches the
|
||||||
|
|
81
plugins/metadata.lisp
Normal file
81
plugins/metadata.lisp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
(eval-when (:compile-toplevel :load-toplevel)
|
||||||
|
(ql:quickload 's-xml))
|
||||||
|
|
||||||
|
(defpackage :coleslaw-metadata
|
||||||
|
(:use :cl :coleslaw)
|
||||||
|
(:import-from :coleslaw
|
||||||
|
#:title
|
||||||
|
#:domain
|
||||||
|
#:tag-name
|
||||||
|
#:page-url
|
||||||
|
#:content-tags
|
||||||
|
#:content-text
|
||||||
|
#:keywords-of
|
||||||
|
#:description-of
|
||||||
|
#:image-of
|
||||||
|
#:card-format
|
||||||
|
#:creator-of)
|
||||||
|
(:import-from :s-xml
|
||||||
|
#:xml-parser-state
|
||||||
|
#:start-parse-xml)
|
||||||
|
(:export #:enable))
|
||||||
|
|
||||||
|
(in-package :coleslaw-metadata)
|
||||||
|
|
||||||
|
(defparameter *description-length* 200)
|
||||||
|
|
||||||
|
(defvar *metadata-header*
|
||||||
|
"
|
||||||
|
<meta name=\"keywords\" content=\"~A\" />~@[
|
||||||
|
<meta name=\"description\" content=\"~A\" />~]~:[~*~*~;~:*
|
||||||
|
<meta name=\"twitter:site\" content=\"@~A\" />
|
||||||
|
<meta name=\"twitter:card\" content=\"~:[summary~;summary_large_image~]\" />~@[
|
||||||
|
<meta name=\"twitter:creator\" content=\"@~A\" />~]~]
|
||||||
|
<meta property=\"og:title\" content=\"~A\" />
|
||||||
|
<meta property=\"og:site_name\" content=\"~A\" />
|
||||||
|
<meta property=\"og:url\" content=\"~A\" />
|
||||||
|
<meta property=\"og:description\" content=\"~A\" />~@[
|
||||||
|
<meta property=\"og:image\" content=\"~A\" />~]
|
||||||
|
")
|
||||||
|
|
||||||
|
(defun remove-markup (text)
|
||||||
|
(with-input-from-string (in text)
|
||||||
|
(let* ((state (make-instance 'xml-parser-state
|
||||||
|
:text-hook #'(lambda (string seed) (cons string seed))))
|
||||||
|
(result (start-parse-xml in state)))
|
||||||
|
(apply #'concatenate 'string (nreverse result)))))
|
||||||
|
|
||||||
|
(defun shorten-text (text)
|
||||||
|
(if (< *description-length* (length text))
|
||||||
|
(subseq text 0 (- *description-length* 1)) text))
|
||||||
|
|
||||||
|
(defun compile-description (text)
|
||||||
|
(shorten-text (remove #\" (remove-markup text))))
|
||||||
|
|
||||||
|
(defun root-relative-url-p (url)
|
||||||
|
(eq (elt url 0) #\/))
|
||||||
|
|
||||||
|
(defun compile-url (url)
|
||||||
|
(if (root-relative-url-p url)
|
||||||
|
(concatenate 'string (domain *config*) url)
|
||||||
|
url))
|
||||||
|
|
||||||
|
(defun compile-metadata (post twitter card)
|
||||||
|
(format nil *metadata-header*
|
||||||
|
(or (keywords-of post)
|
||||||
|
(format nil "~{~A~^, ~}" (mapcar #'tag-name (content-tags post))))
|
||||||
|
(description-of post)
|
||||||
|
twitter
|
||||||
|
(eq (or (card-format post) card) :image)
|
||||||
|
(creator-of post)
|
||||||
|
(title-of post)
|
||||||
|
(title *config*)
|
||||||
|
(concatenate 'string (domain *config*) "/" (namestring (page-url post)))
|
||||||
|
(or (description-of post)
|
||||||
|
(compile-description (content-text post)))
|
||||||
|
(when (image-of post) (compile-url (image-of post)))))
|
||||||
|
|
||||||
|
(defun enable (&key twitter card)
|
||||||
|
(flet ((inject-p (x)
|
||||||
|
(when (typep x 'post) (compile-metadata x twitter card))))
|
||||||
|
(add-injection #'inject-p :head)))
|
|
@ -3,15 +3,27 @@
|
||||||
(defclass post (content)
|
(defclass post (content)
|
||||||
((title :initarg :title :reader title-of)
|
((title :initarg :title :reader title-of)
|
||||||
(author :initarg :author :reader author-of)
|
(author :initarg :author :reader author-of)
|
||||||
(format :initarg :format :reader post-format))
|
(format :initarg :format :reader post-format)
|
||||||
(:default-initargs :author nil))
|
(keywords :initarg :keywords :reader keywords-of)
|
||||||
|
(description :initarg :description :reader description-of)
|
||||||
|
(image :initarg :image :reader image-of)
|
||||||
|
(card :initarg :card :reader card-format)
|
||||||
|
(creator :initarg :creator :reader creator-of))
|
||||||
|
(:default-initargs
|
||||||
|
:author nil
|
||||||
|
:keywords nil
|
||||||
|
:description nil
|
||||||
|
:image nil
|
||||||
|
:card nil
|
||||||
|
:creator nil))
|
||||||
|
|
||||||
(defmethod initialize-instance :after ((object post) &key)
|
(defmethod initialize-instance :after ((object post) &key)
|
||||||
(with-slots (url title author format text) object
|
(with-slots (url title author format card text) object
|
||||||
(setf url (compute-url object (slugify title))
|
(setf url (compute-url object (slugify title))
|
||||||
format (make-keyword (string-upcase format))
|
format (make-keyword (string-upcase format))
|
||||||
text (render-text text format)
|
text (render-text text format)
|
||||||
author (or author (author *config*)))))
|
author (or author (author *config*))
|
||||||
|
card (if card (make-keyword (string-upcase card))))))
|
||||||
|
|
||||||
(defmethod render ((object post) &key prev next)
|
(defmethod render ((object post) &key prev next)
|
||||||
(funcall (theme-fn 'post) (list :config *config*
|
(funcall (theme-fn 'post) (list :config *config*
|
||||||
|
|
Loading…
Add table
Reference in a new issue