php.ini에서 최대 업로드 허용량을 늘려줬는데도 1메가 이상의 이미지 업로드시 HTTP Error가 계속되었는데 알고보니 nginx의 업로드 허용량이 1메가라서 이부분을 수정해줘야 한다.

/etc/nginx/nginx.conf

http괄호 안에 넣어주었다. client_max_body_size 10m;

user  www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
  #tcp_nopush     on;

  keepalive_timeout  65;

  #gzip  on;
  client_max_body_size 10m;
  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
}
Tags : #nginx #wordpress

osx에 nginx를 세팅하고 virtual host로 로컬 도메인을 세팅해 주고 워드프레스를 사용할때 아래와 같은 식으로 virtual host를 세팅해주었다.

server {
  listen 80;
  server_name echo.dev;
  root  /Users/ray/Sites/USER/echo/public_html;
  index  index.php index.html index.htm;
  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
  }
    location / {
    index index.php index.html index.htm;
    try_files $uri $uri/ /index.php?$args;
    }
  location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
    access_log off; log_not_found off; expires max;
  }
}

이 때 워드프레스를 http://hostname/wordpress 에 설치하고 Site Address를 http://hostname/ WordPress Address를 http://hostname/wordpress 로 이용할 수 있다. (index.php를 / 에 옮기는 작업이 필요) 이렇게 하면 Permalink Settings에서 Post name을 쓰는 것도 문제가 없다.

문제는 WordPress Address를 / 로 바꾸지 않고 그대로 /wordpress 로 사용할 때 문제가 된다. 이 때 아래와 같이 location을 더해주면 문제가 해결된다.

    location /wordpress/ {
    try_files $uri $uri/ /wordpress/index.php?$args;
    }

최종적인 config 모습.

server {
  listen 80;
  server_name echo.dev;
  root  /Users/ray/Sites/USER/echo/public_html;
  index  index.php index.html index.htm;
  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
  }
    location / {
    index index.php index.html index.htm;
    try_files $uri $uri/ /index.php?$args;
    }
    location /wordpress/ {
    try_files $uri $uri/ /wordpress/index.php?$args;
    }
  location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
    access_log off; log_not_found off; expires max;
  }
}
Tags : #wordpress

이런 복잡한 주제에 이런 간단한 해결방법이 있을 줄은 몰랐다. 처음에 Mysql sync remote local로 찾았는데, 수많은 복잡한 방법과 복잡한 이야기들. 혹시나 하고 wordpress local remote로 찾았더니 글쎄. 나왔다.

바로바기 : https://github.com/wp-sync-db/wp-sync-db

설치방법

  1. github에서 zip을 받아 양쪽 wordpress에 플러그인으로 설치한다.
  2. 설명에 github-updater를 설치하라고 나오는데, 이 플러그인을 github에서 자동으로 업데이트 시켜주는 기능이라 필요없으면 굳이 설치할 필요 없어 보인다.

사용방법

  1. Remote에서 push선택하면 나오는 코드를 복사
  2. Local에서 pull을 선택하고 아까의 코드를 입력한다.
  3. migrate버튼을 누르면 끝

영상에 잘 나와 있다.

장점

  1. db를 온라인을 통해 옮기는 과정이 쉽고 간단하다.
  2. 자동으로 url주소도 변경해 준다.
  3. 자매품 wp-sync-db-media-files을 쓰면 미디어 파일도 같이 옮겨지는 것 같다.
  4. 공짜다.
Tags : #wordpress

or wordpress의 markdown에서 shortcode 쓰기

현재 mytory markdown플러그인를 이용하고 있다. 이를 통해 글을 올리는 프로세스는 다음과 같다.

  1. sublime text로 markdown파일을 dropbox의 public 폴더 내에 저장한다.
  2. dropbox의 public link를 복사한다.
  3. wordpress에 새 글 쓰기를 눌러 mytory markdown이 만든 링크를 넣을 수 있는 곳에 링크 주소를 넣는다.
  4. makrdown이 html로 변환되어 에디터 창에 들어간 것을 확인할 수 있다.

내 글을 내가 직접 관리할 수 있다는 점. 글의 수정시 워드프레스에 반영이 용이하다는 점이 맘에 들어 이 방법으로 계속 포스팅을 하려고 한다.

문제점

이 방법의 몇가지의 문제점이 발생했는데 이는 다음과 같다.

  1. github 스타일의 코드를 넣으면 에러가 난다.
    : markdown변환하는 과정에서 파서가 github favored code 스타일을 인식하지 못해 일어난 에러인데
    http://kmyh.kr/add-prism-js-for-glsl-language/에 해결 방법을 기록했다.
  2. gist를 등록하는 과정에서 script나 shortcode가 인식이 안되는 문제가 생긴다.

해결

어떤 식으로 해결이 가능할지 생각해 보았다. 일단 markdown에 gist가 삽입이 되어야 하는데 script방식은 되지 않고, native gist를 삽입하는 방식은 특정 line을 지정할 수도 없어 소용이 없다. 이를 해결한 Gistpress를 설치해서 gist를 성공적으로 wordpress내에 임베딩하는것은 물론 특정 line까지 지정할 수 있었다. 단지 문제는 이제 시작이었는데, markdown에서는 어떤 shortcode도 문자열을 변환시킨다는 것이다.

markdown에서 shortcode를 소화하는 방법을 아무리 찾아보았지만 관련 질문조차 찾을 수 없었다. 단지 github에서는 {% gist … %} 이런 식으로 지정해서 gist를 임베딩하는 방식을 제공한다는 것 밖에. 한참 고민한 끝에 나도 역시 저런 식으로 마크다운 문법을 만든 다음 markdown을 파싱하는 과정에서 숏코드로 변환하자는 생각을 했다.

결국 이 기능은 mytory shortcode플러그인 안에서 markdown을 파싱하는 과정 직후에 preg_replace를 이용해 만들었다.

입력 예)

{% gist daa33988ada6dafa773d prism-glsl.js 851-873 %}

변환 예)

[gist id="daa33988ada6dafa773d" file="prism-glsl.js" lines="851-873"]

plugins/mytory-markdown/main.php에서 아래 라인을 찾는다.

$post['post_content'] = preg_replace('/<h1>(.*)<\/h1>/', '', $content);

이 부분을 아래와 같이 바꾼다.

$content = preg_replace('/<h1>(.*)<\/h1>/', '', $content);
$post['post_content'] = preg_replace('/<p>{%\sgist\s([\w\d]+)\s([\w\d-.]+)\s(([\d-]+)\s)?(?:%}<\/p>)/', 'https://gist.github.com/$1', $content);

이처럼 markdown에다 넣어주면 숏코드 형태로 변환되어 html로 입력이 된다.

{% gist daa33988ada6dafa773d prism-glsl.js 851-873 %}

Tags : #gist #markdown #wordpress

워드프레스에 많은 syntexhighligher 플러그인들이 있는데, glsl shading 언어를 지원하는 건 그리 많지 않다. crayon syntax hightlighter가 이를 지원해서 써 왔는데, 썩 맘에 들지 않는 디자인과 시스템 전체에 부하가 걸리는 느낌이 싫어 prism.js를 쓰게 되었다.

Prism

Prism.js는 요즘 많이 사용되는 javascript syntexhighligher인데 깔끔한 디자인과 crayon에 비해 비교적 빠른 로딩속도로 인해 사용하고 싶은 마음은 있었는데, 지난번에도 역시 glsl을 지원하지 않아서 쓰지 못했던 기억이 났다. 이참에 방법을 알아보려고 이리저리 애를 쓰다 기존에 있던 구문강조 들 중 가장 glsl과 비슷한 것이 c-like 인 것을 알아내서, 이를 이용해서 glsl 랭귀지를 만들기로 했다. 워드프레스 플러그인을 설치하고 c문법에서 몇가지 구문을 추가하기로 했다. 방법은 다음과 같다.

문제

  • prism.js에서 “language-glsl” class를 인식하지 못한다.

해결방법

  • 가장 비슷한 language-clike 를 복사하여, glsl의 구문 몇가지를 추가하고 language-glsl을 추가한다.

순서

  1. prism.js를 지원하는 워드프레스 플러그인을 설치한다.
  2. 플러그인에서 참고하는 prism.js를 수정해서 c-like랭귀지 부분을 찾는다.
  3. c-like부분이 없는 경우 prismjs.com에 들어가서 c-like를 추가해서 js와 css를 download받는다.
  4. c-like부분 다음에 아래 소스를 추가해서 ‘language-glsl’구문을 입력받을 수 있게 만든다.

일단 워드프레스 플러그인은 몇가지가 있는데 그중에서도 WordPress › WP Prism Syntax Highlighter « WordPress Plugins 을 사용했는데, 마음에 드는 것을 사용하면 될 것 같다.

플러그인 디렉토리 안에 있는 prism.js파일을 열고 c-like부분을 찾아서 아래 구문을 추가한다.

/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+php+coffeescript+scss+bash+c+markdown&plugins=show-invisibles+show-language */
self = (typeof window !== 'undefined')
? window // if in browser
: (
(typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
? self // if in worker
: {} // if in node js
);
/**
* Prism: Lightweight, robust, elegant syntax highlighting
* MIT license http://www.opensource.org/licenses/mit-license.php/
* @author Lea Verou http://lea.verou.me
*/
var Prism = (function(){
// Private helper vars
var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i;
var _ = self.Prism = {
util: {
encode: function (tokens) {
if (tokens instanceof Token) {
return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias);
} else if (_.util.type(tokens) === 'Array') {
return tokens.map(_.util.encode);
} else {
return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
}
},
type: function (o) {
return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1];
},
// Deep clone a language definition (e.g. to extend it)
clone: function (o) {
var type = _.util.type(o);
switch (type) {
case 'Object':
var clone = {};
for (var key in o) {
if (o.hasOwnProperty(key)) {
clone[key] = _.util.clone(o[key]);
}
}
return clone;
case 'Array':
return o.map(function(v) { return _.util.clone(v); });
}
return o;
}
},
languages: {
extend: function (id, redef) {
var lang = _.util.clone(_.languages[id]);
for (var key in redef) {
lang[key] = redef[key];
}
return lang;
},
/**
* Insert a token before another token in a language literal
* As this needs to recreate the object (we cannot actually insert before keys in object literals),
* we cannot just provide an object, we need anobject and a key.
* @param inside The key (or language id) of the parent
* @param before The key to insert before. If not provided, the function appends instead.
* @param insert Object with the key/value pairs to insert
* @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted.
*/
insertBefore: function (inside, before, insert, root) {
root = root || _.languages;
var grammar = root[inside];
if (arguments.length == 2) {
insert = arguments[1];
for (var newToken in insert) {
if (insert.hasOwnProperty(newToken)) {
grammar[newToken] = insert[newToken];
}
}
return grammar;
}
var ret = {};
for (var token in grammar) {
if (grammar.hasOwnProperty(token)) {
if (token == before) {
for (var newToken in insert) {
if (insert.hasOwnProperty(newToken)) {
ret[newToken] = insert[newToken];
}
}
}
ret[token] = grammar[token];
}
}
// Update references in other language definitions
_.languages.DFS(_.languages, function(key, value) {
if (value === root[inside] && key != inside) {
this[key] = ret;
}
});
return root[inside] = ret;
},
// Traverse a language definition with Depth First Search
DFS: function(o, callback, type) {
for (var i in o) {
if (o.hasOwnProperty(i)) {
callback.call(o, i, o[i], type || i);
if (_.util.type(o[i]) === 'Object') {
_.languages.DFS(o[i], callback);
}
else if (_.util.type(o[i]) === 'Array') {
_.languages.DFS(o[i], callback, i);
}
}
}
}
},
highlightAll: function(async, callback) {
var elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');
for (var i=0, element; element = elements[i++];) {
_.highlightElement(element, async === true, callback);
}
},
highlightElement: function(element, async, callback) {
// Find language
var language, grammar, parent = element;
while (parent && !lang.test(parent.className)) {
parent = parent.parentNode;
}
if (parent) {
language = (parent.className.match(lang) || [,''])[1];
grammar = _.languages[language];
}
if (!grammar) {
return;
}
// Set language on the element, if not present
element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
// Set language on the parent, for styling
parent = element.parentNode;
if (/pre/i.test(parent.nodeName)) {
parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
}
var code = element.textContent;
if(!code) {
return;
}
code = code.replace(/^(?:\r?\n|\r)/,'');
var env = {
element: element,
language: language,
grammar: grammar,
code: code
};
_.hooks.run('before-highlight', env);
if (async && self.Worker) {
var worker = new Worker(_.filename);
worker.onmessage = function(evt) {
env.highlightedCode = Token.stringify(JSON.parse(evt.data), language);
_.hooks.run('before-insert', env);
env.element.innerHTML = env.highlightedCode;
callback && callback.call(env.element);
_.hooks.run('after-highlight', env);
};
worker.postMessage(JSON.stringify({
language: env.language,
code: env.code
}));
}
else {
env.highlightedCode = _.highlight(env.code, env.grammar, env.language);
_.hooks.run('before-insert', env);
env.element.innerHTML = env.highlightedCode;
callback && callback.call(element);
_.hooks.run('after-highlight', env);
}
},
highlight: function (text, grammar, language) {
var tokens = _.tokenize(text, grammar);
return Token.stringify(_.util.encode(tokens), language);
},
tokenize: function(text, grammar, language) {
var Token = _.Token;
var strarr = [text];
var rest = grammar.rest;
if (rest) {
for (var token in rest) {
grammar[token] = rest[token];
}
delete grammar.rest;
}
tokenloop: for (var token in grammar) {
if(!grammar.hasOwnProperty(token) || !grammar[token]) {
continue;
}
var patterns = grammar[token];
patterns = (_.util.type(patterns) === "Array") ? patterns : [patterns];
for (var j = 0; j < patterns.length; ++j) {
var pattern = patterns[j],
inside = pattern.inside,
lookbehind = !!pattern.lookbehind,
lookbehindLength = 0,
alias = pattern.alias;
pattern = pattern.pattern || pattern;
for (var i=0; i<strarr.length; i++) { // Don’t cache length as it changes during the loop
var str = strarr[i];
if (strarr.length > text.length) {
// Something went terribly wrong, ABORT, ABORT!
break tokenloop;
}
if (str instanceof Token) {
continue;
}
pattern.lastIndex = 0;
var match = pattern.exec(str);
if (match) {
if(lookbehind) {
lookbehindLength = match[1].length;
}
var from = match.index - 1 + lookbehindLength,
match = match[0].slice(lookbehindLength),
len = match.length,
to = from + len,
before = str.slice(0, from + 1),
after = str.slice(to + 1);
var args = [i, 1];
if (before) {
args.push(before);
}
var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias);
args.push(wrapped);
if (after) {
args.push(after);
}
Array.prototype.splice.apply(strarr, args);
}
}
}
}
return strarr;
},
hooks: {
all: {},
add: function (name, callback) {
var hooks = _.hooks.all;
hooks[name] = hooks[name] || [];
hooks[name].push(callback);
},
run: function (name, env) {
var callbacks = _.hooks.all[name];
if (!callbacks || !callbacks.length) {
return;
}
for (var i=0, callback; callback = callbacks[i++];) {
callback(env);
}
}
}
};
var Token = _.Token = function(type, content, alias) {
this.type = type;
this.content = content;
this.alias = alias;
};
Token.stringify = function(o, language, parent) {
if (typeof o == 'string') {
return o;
}
if (Object.prototype.toString.call(o) == '[object Array]') {
return o.map(function(element) {
return Token.stringify(element, language, o);
}).join('');
}
var env = {
type: o.type,
content: Token.stringify(o.content, language, parent),
tag: 'span',
classes: ['token', o.type],
attributes: {},
language: language,
parent: parent
};
if (env.type == 'comment') {
env.attributes['spellcheck'] = 'true';
}
if (o.alias) {
var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias];
Array.prototype.push.apply(env.classes, aliases);
}
_.hooks.run('wrap', env);
var attributes = '';
for (var name in env.attributes) {
attributes += name + '="' + (env.attributes[name] || '') + '"';
}
return '<' + env.tag + ' class="' + env.classes.join(' ') + '" ' + attributes + '>' + env.content + '</' + env.tag + '>';
};
if (!self.document) {
if (!self.addEventListener) {
// in Node.js
return self.Prism;
}
// In worker
self.addEventListener('message', function(evt) {
var message = JSON.parse(evt.data),
lang = message.language,
code = message.code;
self.postMessage(JSON.stringify(_.util.encode(_.tokenize(code, _.languages[lang]))));
self.close();
}, false);
return self.Prism;
}
// Get current script and highlight
var script = document.getElementsByTagName('script');
script = script[script.length - 1];
if (script) {
_.filename = script.src;
if (document.addEventListener && !script.hasAttribute('data-manual')) {
document.addEventListener('DOMContentLoaded', _.highlightAll);
}
}
return self.Prism;
})();
if (typeof module !== 'undefined' && module.exports) {
module.exports = Prism;
}
;
Prism.languages.markup = {
'comment': /<!--[\w\W]*?-->/g,
'prolog': /<\?.+?\?>/,
'doctype': /<!DOCTYPE.+?>/,
'cdata': /<!\[CDATA\[[\w\W]*?]]>/i,
'tag': {
pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,
inside: {
'tag': {
pattern: /^<\/?[\w:-]+/i,
inside: {
'punctuation': /^<\/?/,
'namespace': /^[\w-]+?:/
}
},
'attr-value': {
pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,
inside: {
'punctuation': /=|>|"/g
}
},
'punctuation': /\/?>/g,
'attr-name': {
pattern: /[\w:-]+/g,
inside: {
'namespace': /^[\w-]+?:/
}
}
}
},
'entity': /&#?[\da-z]{1,8};/gi
};
// Plugin to make entity title show the real entity, idea by Roman Komarov
Prism.hooks.add('wrap', function(env) {
if (env.type === 'entity') {
env.attributes['title'] = env.content.replace(/&amp;/, '&');
}
});
;
Prism.languages.css = {
'comment': /\/\*[\w\W]*?\*\//g,
'atrule': {
pattern: /@[\w-]+?.*?(;|(?=\s*\{))/gi,
inside: {
'punctuation': /[;:]/g
}
},
'url': /url\((?:(["'])(\\\n|\\?.)*?\1|.*?)\)/gi,
'selector': /[^\{\}\s][^\{\};]*(?=\s*\{)/g,
'string': /("|')(\\\n|\\?.)*?\1/g,
'property': /(\b|\B)[\w-]+(?=\s*:)/ig,
'important': /\B!important\b/gi,
'punctuation': /[\{\};:]/g,
'function': /[-a-z0-9]+(?=\()/ig
};
if (Prism.languages.markup) {
Prism.languages.insertBefore('markup', 'tag', {
'style': {
pattern: /<style[\w\W]*?>[\w\W]*?<\/style>/ig,
inside: {
'tag': {
pattern: /<style[\w\W]*?>|<\/style>/ig,
inside: Prism.languages.markup.tag.inside
},
rest: Prism.languages.css
},
alias: 'language-css'
}
});
Prism.languages.insertBefore('inside', 'attr-value', {
'style-attr': {
pattern: /\s*style=("|').+?\1/ig,
inside: {
'attr-name': {
pattern: /^\s*style/ig,
inside: Prism.languages.markup.tag.inside
},
'punctuation': /^\s*=\s*['"]|['"]\s*$/,
'attr-value': {
pattern: /.+/gi,
inside: Prism.languages.css
}
},
alias: 'language-css'
}
}, Prism.languages.markup.tag);
};
Prism.languages.clike = {
'comment': [
{
pattern: /(^|[^\\])\/\*[\w\W]*?\*\//g,
lookbehind: true
},
{
pattern: /(^|[^\\:])\/\/.*?(\r?\n|$)/g,
lookbehind: true
}
],
'string': /("|')(\\\n|\\?.)*?\1/g,
'class-name': {
pattern: /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,
lookbehind: true,
inside: {
punctuation: /(\.|\\)/
}
},
'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,
'boolean': /\b(true|false)\b/g,
'function': {
pattern: /[a-z0-9_]+\(/ig,
inside: {
punctuation: /\(/
}
},
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,
'operator': /[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/g,
'ignore': /&(lt|gt|amp);/gi,
'punctuation': /[{}[\];(),.:]/g
};
;
Prism.languages.javascript = Prism.languages.extend('clike', {
'keyword': /\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/g,
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|-?Infinity)\b/g,
'function': /(?!\d)[a-z0-9_$]+(?=\()/ig
});
Prism.languages.insertBefore('javascript', 'keyword', {
'regex': {
pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,
lookbehind: true
}
});
if (Prism.languages.markup) {
Prism.languages.insertBefore('markup', 'tag', {
'script': {
pattern: /<script[\w\W]*?>[\w\W]*?<\/script>/ig,
inside: {
'tag': {
pattern: /<script[\w\W]*?>|<\/script>/ig,
inside: Prism.languages.markup.tag.inside
},
rest: Prism.languages.javascript
},
alias: 'language-javascript'
}
});
}
;
/**
* Original by Aaron Harun: http://aahacreative.com/2012/07/31/php-syntax-highlighting-prism/
* Modified by Miles Johnson: http://milesj.me
*
* Supports the following:
* - Extends clike syntax
* - Support for PHP 5.3+ (namespaces, traits, generators, etc)
* - Smarter constant and function matching
*
* Adds the following new token classes:
* constant, delimiter, variable, function, package
*/
Prism.languages.php = Prism.languages.extend('clike', {
'keyword': /\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/ig,
'constant': /\b[A-Z0-9_]{2,}\b/g,
'comment': {
pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])(\/\/|#).*?(\r?\n|$))/g,
lookbehind: true
}
});
Prism.languages.insertBefore('php', 'keyword', {
'delimiter': /(\?>|<\?php|<\?)/ig,
'variable': /(\$\w+)\b/ig,
'package': {
pattern: /(\\|namespace\s+|use\s+)[\w\\]+/g,
lookbehind: true,
inside: {
punctuation: /\\/
}
}
});
// Must be defined after the function pattern
Prism.languages.insertBefore('php', 'operator', {
'property': {
pattern: /(->)[\w]+/g,
lookbehind: true
}
});
// Add HTML support of the markup language exists
if (Prism.languages.markup) {
// Tokenize all inline PHP blocks that are wrapped in <?php ?>
// This allows for easy PHP + markup highlighting
Prism.hooks.add('before-highlight', function(env) {
if (env.language !== 'php') {
return;
}
env.tokenStack = [];
env.backupCode = env.code;
env.code = env.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/ig, function(match) {
env.tokenStack.push(match);
return '{{{PHP' + env.tokenStack.length + '}}}';
});
});
// Restore env.code for other plugins (e.g. line-numbers)
Prism.hooks.add('before-insert', function(env) {
if (env.language === 'php') {
env.code = env.backupCode;
delete env.backupCode;
}
});
// Re-insert the tokens after highlighting
Prism.hooks.add('after-highlight', function(env) {
if (env.language !== 'php') {
return;
}
for (var i = 0, t; t = env.tokenStack[i]; i++) {
env.highlightedCode = env.highlightedCode.replace('{{{PHP' + (i + 1) + '}}}', Prism.highlight(t, env.grammar, 'php'));
}
env.element.innerHTML = env.highlightedCode;
});
// Wrap tokens in classes that are missing them
Prism.hooks.add('wrap', function(env) {
if (env.language === 'php' && env.type === 'markup') {
env.content = env.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g, "<span class=\"token php\">$1</span>");
}
});
// Add the rules before all others
Prism.languages.insertBefore('php', 'comment', {
'markup': {
pattern: /<[^?]\/?(.*?)>/g,
inside: Prism.languages.markup
},
'php': /\{\{\{PHP[0-9]+\}\}\}/g
});
}
;
(function(Prism) {
// Ignore comments starting with { to privilege string interpolation highlighting
var comment = /#(?!\{).+/g,
interpolation = {
pattern: /#\{[^}]+\}/g,
alias: 'variable'
};
Prism.languages.coffeescript = Prism.languages.extend('javascript', {
'comment': comment,
'string': [
// Strings are multiline
/'(?:\\?[\s\S])*?'/g,
{
// Strings are multiline
pattern: /"(?:\\?[\s\S])*?"/g,
inside: {
'interpolation': interpolation
}
}
],
'keyword': /\b(and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/g,
'class-member': {
pattern: /@(?!\d)\w+/,
alias: 'variable'
}
});
Prism.languages.insertBefore('coffeescript', 'comment', {
'multiline-comment': {
pattern: /###[\s\S]+?###/g,
alias: 'comment'
},
// Block regexp can contain comments and interpolation
'block-regex': {
pattern: /\/{3}[\s\S]*?\/{3}/,
alias: 'regex',
inside: {
'comment': comment,
'interpolation': interpolation
}
}
});
Prism.languages.insertBefore('coffeescript', 'string', {
'inline-javascript': {
pattern: /`(?:\\?[\s\S])*?`/g,
inside: {
'delimiter': {
pattern: /^`|`$/g,
alias: 'punctuation'
},
rest: Prism.languages.javascript
}
},
// Block strings
'multiline-string': [
{
pattern: /'''[\s\S]*?'''/,
alias: 'string'
},
{
pattern: /"""[\s\S]*?"""/,
alias: 'string',
inside: {
interpolation: interpolation
}
}
]
});
Prism.languages.insertBefore('coffeescript', 'keyword', {
// Object property
'property': /(?!\d)\w+(?=\s*:(?!:))/g
});
}(Prism));;
Prism.languages.scss = Prism.languages.extend('css', {
'comment': {
pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g,
lookbehind: true
},
// aturle is just the @***, not the entire rule (to highlight var & stuffs)
// + add ability to highlight number & unit for media queries
'atrule': /@[\w-]+(?=\s+(\(|\{|;))/gi,
// url, compassified
'url': /([-a-z]+-)*url(?=\()/gi,
// CSS selector regex is not appropriate for Sass
// since there can be lot more things (var, @ directive, nesting..)
// a selector must start at the end of a property or after a brace (end of other rules or nesting)
// it can contain some caracters that aren't used for defining rules or end of selector, & (parent selector), or interpolated variable
// the end of a selector is found when there is no rules in it ( {} or {\s}) or if there is a property (because an interpolated var
// can "pass" as a selector- e.g: proper#{$erty})
// this one was ard to do, so please be careful if you edit this one :)
'selector': /([^@;\{\}\(\)]?([^@;\{\}\(\)]|&|#\{\$[-_\w]+\})+)(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/gm
});
Prism.languages.insertBefore('scss', 'atrule', {
'keyword': /@(if|else if|else|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)|(?=@for\s+\$[-_\w]+\s)+from/i
});
Prism.languages.insertBefore('scss', 'property', {
// var and interpolated vars
'variable': /((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i
});
Prism.languages.insertBefore('scss', 'function', {
'placeholder': /%[-_\w]+/i,
'statement': /\B!(default|optional)\b/gi,
'boolean': /\b(true|false)\b/g,
'null': /\b(null)\b/g,
'operator': /\s+([-+]{1,2}|={1,2}|!=|\|?\||\?|\*|\/|%)\s+/g
});
;
Prism.languages.bash = Prism.languages.extend('clike', {
'comment': {
pattern: /(^|[^"{\\])(#.*?(\r?\n|$))/g,
lookbehind: true
},
'string': {
//allow multiline string
pattern: /("|')(\\?[\s\S])*?\1/g,
inside: {
//'property' class reused for bash variables
'property': /\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^\}]+\})/g
}
},
'keyword': /\b(if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/g
});
Prism.languages.insertBefore('bash', 'keyword', {
//'property' class reused for bash variables
'property': /\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^}]+\})/g
});
Prism.languages.insertBefore('bash', 'comment', {
//shebang must be before comment, 'important' class from css reused
'important': /(^#!\s*\/bin\/bash)|(^#!\s*\/bin\/sh)/g
});
Prism.languages.c = Prism.languages.extend('clike', {
// allow for c multiline strings
'string': /("|')([^\n\\\1]|\\.|\\\r*\n)*?\1/g,
'keyword': /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/g,
'operator': /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\//g
});
Prism.languages.insertBefore('c', 'string', {
// property class reused for macro statements
'property': {
// allow for multiline macro definitions
// spaces after the # character compile fine with gcc
pattern: /((^|\n)\s*)#\s*[a-z]+([^\n\\]|\\.|\\\r*\n)*/gi,
lookbehind: true,
inside: {
// highlight the path of the include statement as a string
'string': {
pattern: /(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/g,
lookbehind: true
}
}
}
});
// prism-glsl : start
Prism.languages.glsl = Prism.languages.extend('clike', {
'string': /("|')([^\n\\\1]|\\.|\\\r*\n)*?\1/g,
'keyword': /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while|vec2|vec3|vec4)\b/g,
'operator': /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\//g
});
Prism.languages.insertBefore('glsl', 'string', {
// property class reused for macro statements
'property': {
// allow for multiline macro definitions
// spaces after the # character compile fine with gcc
pattern: /((^|\n)\s*)#\s*[a-z]+([^\n\\]|\\.|\\\r*\n)*/gi,
lookbehind: true,
inside: {
// highlight the path of the include statement as a string
'string': {
pattern: /(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/g,
lookbehind: true
}
}
}
});
// prism-glsl : end
delete Prism.languages.c['class-name'];
delete Prism.languages.c['boolean'];;
Prism.languages.markdown = Prism.languages.extend('markup', {});
Prism.languages.insertBefore('markdown', 'prolog', {
'blockquote': {
// > ...
pattern: /(^|\n)>(?:[\t ]*>)*/,
lookbehind: true,
alias: 'punctuation'
},
'code': [
{
// Prefixed by 4 spaces or 1 tab
pattern: /(^|\n)(?: {4}|\t).+/,
lookbehind: true,
alias: 'keyword'
},
{
// `code`
// ``code``
pattern: /``.+?``|`[^`\n]+`/,
alias: 'keyword'
}
],
'title': [
{
// title 1
// =======
// title 2
// -------
pattern: /\w+.*\n(?:==+|--+)/,
alias: 'important',
inside: {
punctuation: /==+$|--+$/
}
},
{
// # title 1
// ###### title 6
pattern: /((?:^|\n)\s*)#+.+/,
lookbehind: true,
alias: 'important',
inside: {
punctuation: /^#+|#+$/
}
}
],
'hr': {
// ***
// ---
// * * *
// -----------
pattern: /((?:^|\n)\s*)([*-])([\t ]*\2){2,}(?=\s*(?:\n|$))/,
lookbehind: true,
alias: 'punctuation'
},
'list': {
// * item
// + item
// - item
// 1. item
pattern: /((?:^|\n)\s*)(?:[*+-]|\d+\.)(?=[\t ].)/,
lookbehind: true,
alias: 'punctuation'
},
'url-reference': {
// [id]: http://example.com "Optional title"
// [id]: http://example.com 'Optional title'
// [id]: http://example.com (Optional title)
// [id]: <http://example.com> "Optional title"
pattern: /!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:[^>]|\\>)+>)(?:[\t ]+(?:"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\((?:[^)]|\\\))*\)))?/,
inside: {
'variable': {
pattern: /^(!?\[)[^\]]+/,
lookbehind: true
},
'string': /(?:"(?:[^"]|\\")*"|'(?:[^']|\\')*'|\((?:[^)]|\\\))*\))$/,
'punctuation': /[[\]\(\)<>:]/
},
alias: 'url'
},
'bold': {
// **strong**
// __strong__
// Allow only one line break
pattern: /(^|[^\\])(\*\*|__)(?:\n(?!\n)|.)+?\2/,
lookbehind: true,
inside: {
'punctuation': /^\*\*|^__|\*\*\s*$|__\s*$/
}
},
'italic': {
// *em*
// _em_
// Allow only one line break
pattern: /(^|[^\\])(?:\*(?:\n(?!\n)|.)+?\*|_(?:\n(?!\n)|.)+?_)/,
lookbehind: true,
inside: {
'punctuation': /^[*_]|[*_]$/
}
},
'url': {
// [example](http://example.com "Optional title")
// [example] [id]
pattern: /!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:[^"]|\\")*")?\)| ?\[[^\]\n]*\])/,
inside: {
'variable': {
pattern: /(!?\[)[^\]]+(?=\]$)/,
lookbehind: true
},
'string': {
pattern: /"(?:[^"]|\\")*"(?=\)$)/
}
}
}
});
Prism.languages.markdown['bold'].inside['url'] = Prism.util.clone(Prism.languages.markdown['url']);
Prism.languages.markdown['italic'].inside['url'] = Prism.util.clone(Prism.languages.markdown['url']);
Prism.languages.markdown['bold'].inside['italic'] = Prism.util.clone(Prism.languages.markdown['italic']);
Prism.languages.markdown['italic'].inside['bold'] = Prism.util.clone(Prism.languages.markdown['bold']);;
(function(){
if(!window.Prism) {
return;
}
for (var language in Prism.languages) {
var tokens = Prism.languages[language];
tokens.tab = /\t/g;
tokens.crlf = /\r\n/g;
tokens.lf = /\n/g;
tokens.cr = /\r/g;
}
})();
;
(function(){
if (!self.Prism) {
return;
}
var Languages = {
'csharp': 'C#',
'cpp': 'C++'
};
Prism.hooks.add('before-highlight', function(env) {
var language = Languages[env.language] || env.language;
env.element.setAttribute('data-language', language);
});
})();
;
view raw prism-glsl.js hosted with ❤ by GitHub
  <pre><code class="language-glsl">
    code..
  </code></pre>

구문이 잘 동작하는지 확인한다.

Tags : #javascript #wordpress

개요

위와 같은 동적 페이지를 만들기 위한 방법을 기록해보겠습니다.

방법 자체는 Isotope플러그인의 filter기능으로 구현했습니다. Isotope – Filtering을 보시는게 더 쉽고 간단할 수 있습니다.

위의 페이지는 Types플러그인 이용하여 아래의 기능으로 이루어졌습니다.

custom post 생성 : ‘link’

taxonomy 생성 : ‘linktag

‘link’ custom post를 ‘linktag’ taxonomy와 연결

아래 소스는 http://blogurl.com/link 로 접속했을 때 출력되는 페이지를 overdrive하기 위해 만든 archive-link.php이고, 이 파일의 loop안에서 content-linkthumb.php를 불러오게 됩니다.

archive-link.php

    <?php
    /**
     * The template for displaying Archive pages.
     *
     */

    get_header(); ?>
    <?php
    //custom post name : link
    //tag(taxonomy) : linktag
    //
    //archive-link.php는 link 라는 custom post를 출력하는 페이지.
    //이 파일이 없을 경우 archive.php가 출력되는데, 테마 폴더 안에 이 파일을 만들면 http://blogurl.com/link로 접근할 때
    //archive.php대신 출력된다.

    $args = array(
        'post_type' => 'link',
        'posts_per_page' => -1
        );
    $the_query = new WP_Query( $args ); // 포스트 갯수는 설정에서 지정해 둔 숫자로 출력되는데 전체 포스트를 출력하기 위해 wp_query를 새로 지정해줌.
    ?>

    <section id="primary" class="content-area">

        <h2>A.some.link</h2>

        <div id="filters" class="button-group">
            <button data-filter="*">show all</button>
            <?php
            // 페이지 상단 버튼 태그 버튼 그룹.
            // taxonomy 'linktag'의 terms들을 출력한다.
            $args = array(
                'orderby' => 'name',
                'taxonomy' => 'linktag',
                'hide_empty' => 1,
                'order' => 'ASC'
                );
            $categories = get_categories($args);
            foreach($categories as $category) {
                echo '<button data-filter="'.$category->slug.'">'.$category->name.'</button>';
            }
            ?>
        </div>
        <div class="linkthumbs">
            <?php
            if ( $the_query->have_posts() ) :
                while ( $the_query->have_posts() ) : $the_query->the_post();
            get_template_part( 'content', 'linkthumb'); // content-linkthumb.php를 인클루드한다.
            endwhile;
            endif;
            wp_reset_postdata();
            ?>

        </div>
    </section>
    <script src="http://dev.0-q.me/js/isotope.pkgd.min.js"></script>
    <script>

    jQuery( document ).ready( function( $ ) {
        var $container = $('.linkthumbs');
        var currentFilter = '*';
        $container.isotope({
          itemSelector: '.linkthumbs article',
          layoutMode: 'fitRows'
        });
        $('#filters').on( 'click', 'button', function() {
            //#filters아래의 button을 클릭했을 때 이벤트.

            var filterValue = $(this).attr('data-filter') ; // 클릭한 버튼의 data-filter을 확인
            if(currentFilter != filterValue ){ // 현재의 filterValue와 클릭한 filterValue를 확인하여 다를때 실행.
                currentFilter = filterValue;
                $(this).siblings().removeClass('selected');
                $(this).toggleClass('selected'); // 클릭한 버튼에 selected 클래스를 지정하고 나머지 버튼에서 해당 클래스를 제거
                filterValue = $(this).attr('data-filter') == '*' ? '*' : '.tag-'+$(this).attr('data-filter') // filterValue확인
                $container.isotope({ filter: filterValue }); // isotope에서 해당 데이터만 보이게 함.
            }
        });
        $('.tags').on( 'click', 'a', function() {
            // .tags아래의 버튼을 클릭할때 data-filter속성을 확인하여 jquery의 trigger을 이용. 상단의 태그들에서 같은 버튼을 클릭한 효과를 낸다.
            var thisValue = $(this).attr('data-filter') == '*' ? '*' : $(this).attr('data-filter') ;
            $('#filters').find("[data-filter='" + thisValue + "']").trigger('click');
            //console.log(thisValue); // 디버깅 용도
        });

    });
    </script>

    <?php get_sidebar('sidebar-1'); ?>
    <?php get_footer(); ?>
    `</pre>

content-linkthumb.php

<?php
    /**
     */
    $linkurl = types_render_field("links", array("raw"=>"true")); //types에서 지정한 links 항목을 $linkurl에 불러온다.
    if($linkurl){
        $linkurl = addhttp($linkurl); // http://가 없을 시 붙여주는 펑션(functions.php에서 만들어 줌.)
    }
    ?>
    <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
        <header class="entry-header">
            <div class="entry-meta">
                <span class="entry-in-time" style="display:none;"> <?php the_time('Y.m.d'); ?> </span>
                <span class="tags"><?php

                $linktags = wp_get_object_terms($post->ID, 'linktag');
                // taxonomy : 'linktag'의 terms들을 출력한다.
                foreach($linktags as $category) {
                    echo '<a data-filter="'.$category->slug.'" href="#">'.$category->name.'</a>';
                }

                ?></span>
            </div>
            <h3 class="entry-title">
                <a href="<?php echo $linkurl ?>" title="<?php echo 'go to '.$linkurl ?>" rel="bookmark" target="_blank" class="newwindow">
                    <?php the_title(); ?>
                </a>
            </h3>

        </header>

        <div class="entry-summary">

            <?php if ( has_post_thumbnail() && ! post_password_required() ) : ?>
            <div class="post-thumbnail">
                <a href="<?php echo $linkurl ?>" title="<?php echo 'go to '.$linkurl ?>" rel="bookmark" target="_blank" class="newwindow"><?php the_post_thumbnail();?></a>
            </div>

            <?php elseif($linkurl != ''): ?>
            <a href="<?php echo $linkurl ?>" title="<?php echo 'go to '.$linkurl ?>" rel="bookmark" target="_blank" class="newwindow">
            <?php echo do_shortcode('[stwthumb]'.$linkurl.'[/stwthumb]' ); //shrinktheweb 플러그인을 이용해 썸네일을 생성?>
            </a>
            <?php endif; ?>

        </div>

    </article>
Tags : #wordpress

facebook처럼 링크를 던져넣었을때 스크린샷이 생성되는건 워드프레스 유저들이 보기에 참으로 부러운 기능인것 같다. 찾아보면 이를 원하는 질문들이 많은데, 그동안 비슷한 방법은 wordpress.com에서 제공하는 기능이다.

1. mshot 방식

http://s.wordpress.com/mshots/v1/http%3A%2F%2Fprothemedesign.com%2F?w=250

이런식으로 스크립트를 써주면 이미지가 생성된다. 이를 이용해 워드프레스 상에서 입력한 url을 저 url부분에 넣어서 스크린샷을 동적으로 보여줄 수 있고, 이를 이용한 플러그인이 많은데 나는 bm-shot이라는 플러그인을 썻다.

코드를 보면 이미지가 저 워드프레스 서버에 저장이 되고 이를 불러오는 방식인데, 한번 생성되면 느리진 않지만 나중에 다시 페이지를 읽으면 서버에서 지워졌는지 다시 지워지는 단점이 있다.

2. Shrink The Web

http://www.shrinktheweb.com/

더 좋은 방법이 없나 계속 찾다보니 이런 서비스가 있었다. 저 서비스에 가입을 하고 제공하는 코드로 url을 전송하면 이미지가 생성된다. 이 서비스에서 제공하는 Shrink The Web 플러그인을 이용했더니 좋은점은 생성된 이미지가 내 서버에 저장된다는 것이다.

무료와 유료 계정의 차이가 있지만 무료 계정으로도 한달에 5000개의 쿼리를 처리할 수 있다니 나쁘지 않다. 현재 왼쪽의 a some link부분을 이 기능으로 사용 중.

2-1. 생성된 썸네일을 thumbnail로 등록하기

2번의 방법을 계속 써 왔는데 이 방식은 매번 stw의 숏코드를 불러오는데 이 코드에서는 해당 파일이 생성되어 있는지 확인하고 그것 보여주거나, 캐시 기간이 지났을 경우 다시 서비스에 접속해서 썸네일을 생성한다. 이 방식이 필요한 사람도 있겠지만 내 경우에는 속도 문제도 있고 굳이 그렇께까지 할 필요를 못느껴서 차라리 post에 썸네일로 등록하고 싶었는데, 한참을 헤멘 끝에 간단히 해결하였다.

먼저 테마의 functions.php에 아래 코드를 추가한다.

function save_thumbnail($imageurl){
    global $post;
    $post_id = $post->ID;  
    $image_url = $imageurl;
    $upload_dir = wp_upload_dir();
    $image_data = file_get_contents($image_url);
    $filename = basename($image_url);
    if(wp_mkdir_p($upload_dir['path']))
    $file = $upload_dir['path'] . '/' . $filename;
    else
    $file = $upload_dir['basedir'] . '/' . $filename;
    file_put_contents($file, $image_data);

    $wp_filetype = wp_check_filetype($filename, null );
    $attachment = array(
        'post_mime_type' => $wp_filetype['type'],
        'post_title' => sanitize_file_name($filename),
        'post_content' => '',
        'post_status' => 'inherit'
    );
    $attach_id = wp_insert_attachment( $attachment, $file, $post_id );
    require_once(ABSPATH . 'wp-admin/includes/image.php');
    $attach_data = wp_generate_attachment_metadata( $attach_id, $file );
    wp_update_attachment_metadata( $attach_id, $attach_data );

    set_post_thumbnail( $post_id, $attach_id );
}

그리고 ‘/wp-content/plugins/shrinktheweb-website-preview-plugin/stw-wp-thumbnails.php’ 파일을 열어 line:437에 아래와 같은 부분이 있는데,

if ($useCachedThumb) {
return STWWT_plugin_getCacheURL($cacheFilename, $errorThumb);
} else {
    // File is not in cache, or we need a live version, so return it.
    return STWWT_fetch_requestThumbnailCapture($args);
}

save_thumbnail을 추가하여 아래처럼 바꾼다.

if ($useCachedThumb) {
save_thumbnail($cachePath);
return STWWT_plugin_getCacheURL($cacheFilename, $errorThumb);
} else {
    // File is not in cache, or we need a live version, so return it.
    return STWWT_fetch_requestThumbnailCapture($args);
}

참고 : wp insert post – How do I set a featured image (thumbnail) by image URL when using wp_insert_post()? – WordPress Development Stack Exchange

Tags : #wordpress

How To Track & Display Post Views Count in WordPress Without a Plugin

ID;    
    }
    wpb_set_post_views($post_id);
}
add_action( 'wp_head', 'wpb_track_post_views');

/*********************************CODE-3********************************************
* @Author: Boutros AbiChedid 
* @Date:   January 16, 2012
* @Websites: http://bacsoftwareconsulting.com/ ; http://blueoliveonline.com/
* @Description: Adds a Non-Sortable 'Views' Columnn to the Post Tab in WP dashboard.
* This code requires CODE-1(and CODE-2) as a prerequesite.
* Code is browser and JavaScript independent.
* @Tested on: WordPress version 3.2.1
***********************************************************************************/

//Gets the  number of Post Views to be used later.
function get_PostViews($post_ID){
    $count_key = 'wpb_post_views_count';
    //Returns values of the custom field with the specified key from the specified post.
    $count = get_post_meta($post_ID, $count_key, true);

    return $count;
}

//Function that Adds a 'Views' Column to your Posts tab in WordPress Dashboard.
function post_column_views($newcolumn){
    //Retrieves the translated string, if translation exists, and assign it to the 'default' array.
    $newcolumn['post_views'] = __('Views');
    return $newcolumn;
}

//Function that Populates the 'Views' Column with the number of views count.
function post_custom_column_views($column_name, $id){

    if($column_name === 'post_views'){
        // Display the Post View Count of the current post.
        // get_the_ID() - Returns the numeric ID of the current post.
        echo get_PostViews(get_the_ID());
    }
}
//Hooks a function to a specific filter action.
//applied to the list of columns to print on the manage posts screen.
add_filter('manage_posts_columns', 'post_column_views');

//Hooks a function to a specific action. 
//allows you to add custom columns to the list post/custom post type pages.
//'10' default: specify the function's priority.
//and '2' is the number of the functions' arguments.
add_action('manage_posts_custom_column', 'post_custom_column_views',10,2);
?>

Tags : #wordpress

기록할겸 다른분들께 도움이 될겸 정리해보고자 합니다.

  • the-box테마를 바탕으로 수정하기 시작 : 거의 뜯어고칠 생각이라 가능하면 깔끔하게 정리된 테마를 고름
  • nginx기반에 워드프레스를 사용 : apache에서는 어떻게 돌려도 워드프레스가 상당히 느렸는데 nginx에서는 제법 잘 돌아가는 것 같다.
  • 첫페이지는 template로 하는 탓에 전체 해상도와 첫페이지 해상도가 다름. 고민중
  • 첫페이지는 php로 wp_query를 사용해서 각각의 카테고리 글들을 불러오고 원하는 사항만 가져왔다. 예를들어 제목, 카테고리 등등이라던가
  • 모든 포스트 입력을 할 때 링크를 등록할 수 있게 Costom Fields 플러그인을 사용함.  http://www.advancedcustomfields.com/
  • Custom Fields 플러그인으로 url을 입력받는 text필드, 체크박스 필드를 만들고 이 두개가 입력이 되면 스크린샷을 자동으로 생성하게 만듬.
  • 2014-08-18_11-01-25
  • url을 바탕으로 스크린샷을 생성하는건 워드프레스쪽에서 제공하는 기능인데 이를 플러그인으로 구현한 Browser Shots을 사용.
  • Browser Shots를 사용하면 페이지 상에서 숏코드로 url을 넣어주면 실시간으로 스크린샷을 만들어준다. 계속 사용하면 어떨지 모르겠지만, 한번 만든 스크린샷은 캐쉬로 저장되는듯, 로딩이 너무 나쁘진 않다.
  • a.some.link는 본문없이 링크와 제목만 입력해서 만들었는데 템플릿 상에서 클릭할때 링크로 바로 이동하게 처리했다.
  • photo는 워드프레스의 fetch_feed 함수를 이용해서 내 다른 블로그에서 실시간으로 글을 끌어다 오고 있다.
  • 지금 가능 까다로운 문제는 바닥까지 이어지는 배경색 문제. 이름하여 height 100%인데, 될듯 말듯 하면서 자꾸 안된다. 고민중

 

Tags : #wordpress

워드프레스를 설치할때 계정의 root에 설치하면 상관없지만 다른 폴더가 있을 경우 지저분해 보일 가능성이 있다. 그래서 wordpress라는 폴더에다 설치하곤 하는데 그럴 경우 사이트 주소에

http://example.com/wordpress

처럼 보기 싫게 되는 경우가 있다. 이럴 때

/wordpress부분을 감추려면 어떻게 해야 할까.

우선 관리자의 설정 메뉴에 들어가보면 워드프레스 주소와 사이트 주소가 같이 되어 있을것이다.

ex) http://example.com/wordpress

여기에서 사이트 주소를

http://example.com

로 바꿔준다. 그리고 한가지 중요한 것은 /wordpress에 들어있던 index.php를 /에 복사한 다음 내용을 수정해 주어야 한다.

<?php
/**
 * Front to the WordPress application. This file doesn't do anything, but loads
 * wp-blog-header.php which does and tells WordPress to load the theme.
 *
 * @package WordPress
 */

/**
 * Tells WordPress to load the WordPress theme and output it.
 *
 * @var bool
 */
define('WP_USE_THEMES', true);

/** Loads the WordPress Environment and Template */
require( dirname( __FILE__ ) . '/wp-blog-header.php' );

이런식으로 되어있는데.

require( dirname( __FILE__ ) . '/wp-blog-header.php' );

이 부분을 해당 url로 바꾸어준다. 즉 이런식으로.

require( './wordpress/wp-blog-header.php' );
Tags : #wordpress