워드프레스 포스트 편집 화면에 메타박스 추가하기

위 이미지와 같은 커스텀 메타박스를 편집 화면에 추가하는 방법으로 플러그인 형태로 코드를 작성했다.

<?php

/**
 * @package Codepub Meta box
 * @version 1.0
 */
/*
Plugin Name: Codepub Meta box
Plugin URI: https://ncube.net/
Description: This plugin add custom meta box.
Author: chicpro
Version: 1.0
Author URI: https://ncube.net/
*/

// meta box render
function codepub_meta_box($post)
{
    wp_nonce_field( basename( __FILE__ ), 'codepub_meta_box_nonce' );

    $codepub_meta_box_value = (int)get_post_meta($post->ID, 'codepub_meta_box_value', true);

    echo '<div>'.PHP_EOL;
    echo '<p>'.PHP_EOL;
    echo '<input type="checkbox" name="codepub_meta_box_value" id="codepub_meta_box_value" value="1"'.($codepub_meta_box_value ? ' checked="checked"' : '').'>'.PHP_EOL;
    echo '<label for="codepub_meta_box_value">메타박스</label>'.PHP_EOL;
    echo '</p>'.PHP_EOL;
    echo '</div>'.PHP_EOL;
}

function add_codepub_meta_box()
{
    foreach (array('post', 'page') as $post_type)
        add_meta_box( 'codepub_meta_box', __( 'Codepub 메타박스', 'codepub_meta_box' ), 'codepub_meta_box', $post_type, 'side', 'low' );
}

// Save meta value
function save_codepub_meta_box_data($post_id)
{
    if ( !isset( $_POST['codepub_meta_box_nonce'] ) || !wp_verify_nonce( $_POST['codepub_meta_box_nonce'], basename( __FILE__ ) ) ) {
        return;
    }

    // return if autosave
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    // Check the user's permissions.
    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    if ( isset( $_REQUEST['codepub_meta_box_value'] ) ) {
        update_post_meta( $post_id, 'codepub_meta_box_value', sanitize_text_field( $_POST['codepub_meta_box_value'] ) );
    } else {
        // delete data
        delete_post_meta( $post_id, 'codepub_meta_box_value' );
    }
}

add_action( 'admin_init', 'add_codepub_meta_box' );
add_action( 'save_post',  'save_codepub_meta_box_data' );

33 라인의 array('post', 'page') 에서 워드프레스 포스트 타입이 postpage인 경우에만 메타박스가 출력된다. 메타박스 디자인 부분과 데이터를 저장하는 부분이 포함되어 있다.

[PHP] 문자열에 포함된 다수의 특정 문자를 순차적으로 치환하기

문자열에 포함된 동일한 다수의 특정 문자를 순차적으로 치환하는 방법이다. 순차적으로 치환한다는 것의 의미가 불분명할 수 있는데.. 예를 들면 이런 것이다. a b a c d 문자열에서 a 를  a_1 b a_2 c d 로 치환하는 것이다. 설명을 자세히 할 능력이 없기 때문에 코드를 보자.

<?php
$string = 'test [form] string with [form] replace';

$form = '[ id : id_{{idx}} ]';

function replaceForm($form) {
    static $idx = 0;

    $idx++;

    return str_replace('{{idx}}', $idx, $form);
}

echo preg_replace_callback('#\[form\]#',
        function($match) use ($form) {
            return replaceForm($form);
        },
        $string);

위 코드는 문자열에 포함된 [form] 문자를 [ id : id_1 ] 과 같은 형식으로 치환하여 출력한다. 결과는 아래와 같다.

test [ id : id_1 ] string with [ id : id_2 ] replace

참고 : http://www.php.net/manual/en/function.preg-replace-callback.php

위의 예제를 수정하여 동일한 웹페이지에 다수의 [form] 문자열을 입력폼으로 치환하여 출력할 때 입력 필드의 id와 label의 for 를 각각 매치시켜줄 때 사용할 수 있다.

카카오 번역 API 사용을 위한 PHP 클라이언트

카카오 번역 API 사용을 위한 PHP 클라이언트 코드이다. PHP 7.0 이상의 환경에서 사용할 수 있다.

카카오 번역 API : https://developers.kakao.com/docs/restapi/translation

<?php
/**
* @author chicpro <chicpro@gmail.com>
* @copyright (c) chicpro
* @link https://ncube.net
*/

namespace chicpro\KAKAO;

class TRANSLATE
{
    protected $host;
    protected $appKey;

    protected $query;
    protected $sourceLanguage;
    protected $targetLanguage;

    public function __construct(string $appKey = '')
    {
        $this->host   = 'https://kapi.kakao.com/v1/translation/translate';
        $this->appKey = $appKey;
    }

    public function setHost(string $host)
    {
        $this->host = $host;
    }

    public function setAppKey(string $appKey)
    {
        $this->appKey = $appKey;
    }

    public function setQuery(string $query)
    {
        $this->query = $query;
    }

    public function setSourceLanguage(string $source)
    {
        $this->sourceLanguage = $source;
    }

    public function setTargetLanguage(string $target)
    {
        $this->targetLanguage = $target;
    }

    public function sendRequest()
    {
        $headers = array(
            'Authorization: KakaoAK ' . $this->appKey
        );

        $postData = [
            'src_lang'    => $this->sourceLanguage,
            'target_lang' => $this->targetLanguage,
            'query'       => $this->query
        ];

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_URL, $this->host);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));

        $json = curl_exec($ch);

        if ($errno = curl_errno($ch)) {
            $result = new \stdClass;
            $result->errno = $errno;
            $result->error = 'Curl error: ' . curl_error($ch);
        } else {
            $response = json_decode($json);
            $result = $response;
        }

        return $result;
    }
}

카카오 번역 API 예제 코드는 아래와 같다. Read More

[PHP] 영카트5에 사용할 수 있는 사이트맵 생성 코드

영카트5에 등록된 상품의 사이트맵을 생성하는 PHP 코드이다. 사이트맵 생성 Class 는 https://github.com/o/sitemap-php/blob/master/Sitemap.php 를 이용한다. 사이트맵 xml 파일은 sitemap 디렉토리에 저장되며 웹서버의 파일 쓰기 권한이 부여되어야 한다.

<?php
if (PHP_SAPI != 'cli')
    die('');

require_once './_common.php';
require_once G5_LIB_PATH.'/Sitemap.php';

session_write_close();

if (isset($argv[1]) && $argv[1])
    define('SITE_URL', set_http($argv[1]));

if (!defined('SITE_URL') || SITE_URL == '')
    die('Please specify your site url.');

$sitemap = new Sitemap(SITE_URL);

$path = G5_PATH.'/sitemap/';

if (!is_writable($path))
    die('You do not have write permission.');

$sitemap->setPath($path);

// index
$sitemap->addItem('/');

// item
$sql = " select it_id, it_update_time from `{$g5['g5_shop_item_table']}` where it_use = '1' and it_soldout = '0' ";
$result = sql_query($sql);

for ($i = 0; $row = sql_fetch_array($result); $i++) {
    if (!$row['it_id'])
        continue;

    $sitemap->addItem('/shop/item.php?it_id='.$row['it_id'], '1.0', 'daily', substr($row['it_update_time'], 0, 10));
}

// sitemap create
$sitemap->createSitemapIndex(SITE_URL.'/sitemap/', 'Today');

위 코드를 실행하는 쉘스크립트 코드는 아래와 같다.

#!/bin/sh
DIRECTORY=$(cd `dirname $0` && pwd)

cd "${DIRECTORY}"

sudo -u www-data  php sitemap.php "$1"

위 쉘스크립트 실행은 아래와 같이 한다.

$ ./sitemap.sh example.com

쉘 상에서는 G5_URL 등의 상수가 제대로 정의되지 않기 때문에 사용할 수 있어 sh 파일 실행 때 도메인을 지정하는 방법으로 구현했다. 예제 코드와 Class 파일은 첨부된 압축파일에 포함되어 있다.

sitemap.tar.gz

crotntab 에 등록할 때는 아래와 같이 하면 된다.

# sitemap
1 5 * * * /home/example/www/sitemap.sh example.com

사이트맵 url 은 http://example.com/sitemap/sitemap-index.xml 이다.

[PHP] 방문로그에 특정 에이전트 제외하고 로그 남기기

PHP 에서 특정 사용자 에이전트(예: Googlebot 등)를 제외하고 방문로그를 DB에 남기는 코드이다. 방문로그 테이블 구조에 따라 아래 코드는 수정된 후 사용되어야 한다.

<?php
$_AGENT_EXCLUDE = array(
    'mod_pagespeed',
    'bot'
);

if (!isset($_SESSION['ss_visit_log']) || !$_SESSION['ss_visit_log']) {
    if (str_replace($_AGENT_EXCLUDE, '', $_SERVER['HTTP_USER_AGENT']) == $_SERVER['HTTP_USER_AGENT']) {
        $sql = " insert into `{$nt['visit_table']}` ( vi_date, vi_time, vi_referer, vi_agent, vi_ip ) values ( :vi_date, :vi_time, :vi_referer, :vi_agent, :vi_ip ) ";
        $DB->prepare($sql);
        $DB->bindValueArray([
            ':vi_date'    => NT_TIME_YMD,
            ':vi_time'    => NT_TIME_HIS,
            ':vi_referer' => $_SERVER['HTTP_REFERER'] ? $_SERVER['HTTP_REFERER'] : '',
            ':vi_agent'   => $_SERVER['HTTP_USER_AGENT'],
            ':vi_ip'      => $_SERVER['REMOTE_ADDR']
        ]);

        $_SESSION['ss_visit_log'] = $DB->execute();
    }
}
$_AGENT_EXCLUDE 지정된 문자열을 HTTP_USER_AGENT 에 포함하고 있으면 로그를 DB에 남기지 않는다. 제외될 문자열은 배열인데 str_replace 함수를 이용해 치환 후 치환된 문자열과 원래 문자열이 비교해서 같은 경우에만 로그를 남기는 것이다. 코드의 8 라인에 해당된다.