Make.com을 활용하여 여러 WordPress 사이트를 중앙에서 관리합니다. 콘텐츠 동시 배포, 통합 리포팅, 플러그인/테마 일괄 관리를 구현합니다.
Make.com으로 중앙 콘텐츠 배포 시나리오 구축
콘텐츠 동시 배포의 원리와 설계
중앙 콘텐츠 배포 시스템은 하나의 콘텐츠를 작성하면 지정된 모든 WordPress 사이트에 동시에 발행되는 구조입니다. 이 시스템은 프랜차이즈 본사에서 각 지점 사이트에 공지사항을 배포하거나, 미디어 네트워크에서 동일한 뉴스를 여러 사이트에 동시 게재하거나, 에이전시가 클라이언트 사이트에 정기 콘텐츠를 배포하는 등의 시나리오에 적합합니다.
Make.com 시나리오의 핵심은 Iterator 모듈입니다. Google Sheets에서 사이트 목록을 가져온 후, Iterator가 각 사이트를 순회하면서 WordPress REST API를 통해 콘텐츠를 발행합니다. 에러 핸들러를 추가하면 특정 사이트에서 오류가 발생해도 나머지 사이트의 배포는 계속 진행됩니다.
1
사이트 마스터 시트 생성: Google Sheets에 관리 대상 사이트의 URL, API 사용자명, Application Password, 활성 상태, 카테고리 매핑 정보를 기록합니다. 각 사이트별로 고유한 Application Password를 발급받아 저장합니다. 이 시트가 전체 시스템의 Single Source of Truth(유일한 진실의 원천)가 됩니다.
2
Make.com 시나리오 생성: 새 시나리오를 생성하고 트리거 모듈을 설정합니다. Webhook 트리거(즉시 배포)와 Schedule 트리거(예약 배포)를 모두 준비합니다. Webhook은 외부 시스템에서 즉시 배포를 요청할 때 사용하고, Schedule은 정기 배포에 사용합니다.
3
사이트 목록 로드: Google Sheets 모듈로 사이트 마스터 시트를 읽어옵니다. Active 필드가 "YES"인 사이트만 필터링하여 비활성 사이트는 자동으로 건너뜁니다. 이렇게 하면 특정 사이트를 일시 중지하고 싶을 때 시트에서 Active를 "NO"로만 변경하면 됩니다.
4
Iterator 설정: 사이트 목록 배열을 Iterator에 연결합니다. Iterator는 각 사이트 정보를 하나씩 꺼내어 다음 모듈로 전달합니다. 각 반복(iteration)마다 해당 사이트의 URL, 인증 정보, 카테고리 매핑이 개별적으로 처리됩니다.
5
HTTP 요청 모듈: WordPress REST API에 POST 요청을 보내 콘텐츠를 발행합니다. URL은 Iterator에서 전달받은 사이트 URL + /wp-json/wp/v2/posts로 구성합니다. Basic Auth 헤더에 해당 사이트의 사용자명과 Application Password를 설정합니다.
6
에러 핸들링: HTTP 요청 모듈에 에러 핸들러를 추가합니다. 특정 사이트에서 오류(서버 다운, 인증 실패 등)가 발생해도 시나리오 전체가 중단되지 않도록 합니다. 오류 정보를 별도 배열에 기록하여 최종 리포트에 포함합니다.
7
결과 집계 및 알림: Array Aggregator로 모든 사이트의 배포 결과를 수집하고, 성공/실패 건수를 집계합니다. 결과를 Google Sheets 로그 시트에 기록하고, Slack이나 이메일로 배포 완료 알림을 발송합니다.
사이트 마스터 시트 구조
Google Sheets에 아래와 같은 구조로 사이트 정보를 관리합니다. 각 사이트별로 고유한 인증 정보와 설정을 저장하여 Make.com 시나리오에서 동적으로 참조합니다.
{
"title": "{{webhook.post_title}}",
"content": "{{webhook.post_content}}",
"status": "{{webhook.post_status}}",
"categories": ["{{iterator.category_id}}"],
"meta": {
"_source_site": "central-hub",
"_distribution_id": "{{webhook.distribution_id}}",
"_deployed_at": "{{now}}"
}
}
WordPress 측: 원격 관리용 커스텀 플러그인
모든 관리 대상 사이트에 동일한 커스텀 플러그인을 설치합니다. 이 플러그인은 Make.com에서 호출할 수 있는 REST API 엔드포인트를 제공하며, 사이트 상태 조회, 콘텐츠 일괄 발행, 플러그인 관리, 보안 스캔 등의 기능을 포함합니다. 표준 WordPress REST API만으로는 제공되지 않는 관리 기능을 커스텀 엔드포인트를 통해 확장합니다.
defined('ABSPATH') || exit;
class MAP_Remote_Manager {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action('rest_api_init', [$this, 'register_endpoints']);
}
public function register_endpoints() {
register_rest_route('map-remote/v1', '/status', [
'methods' => 'GET',
'callback' => [$this, 'get_site_status'],
'permission_callback' => [$this, 'check_admin_permission'],
]);
register_rest_route('map-remote/v1', '/bulk-publish', [
'methods' => 'POST',
'callback' => [$this, 'bulk_publish'],
'permission_callback' => [$this, 'check_publish_permission'],
]);
register_rest_route('map-remote/v1', '/plugins', [
'methods' => 'GET',
'callback' => [$this, 'get_plugins_status'],
'permission_callback' => [$this, 'check_admin_permission'],
]);
register_rest_route('map-remote/v1', '/plugins/update', [
'methods' => 'POST',
'callback' => [$this, 'update_plugins'],
'permission_callback' => [$this, 'check_admin_permission'],
]);
register_rest_route('map-remote/v1', '/security-scan', [
'methods' => 'GET',
'callback' => [$this, 'run_security_scan'],
'permission_callback' => [$this, 'check_admin_permission'],
]);
register_rest_route('map-remote/v1', '/backup-status', [
'methods' => 'GET',
'callback' => [$this, 'get_backup_status'],
'permission_callback' => [$this, 'check_admin_permission'],
]);
}
public function get_site_status() {
global $wp_version;
$theme = wp_get_theme();
return [
'site_name' => get_bloginfo('name'),
'site_url' => home_url(),
'wp_version' => $wp_version,
'php_version' => PHP_VERSION,
'mysql_version' => $GLOBALS['wpdb']->db_version(),
'theme_name' => $theme->get('Name'),
'theme_version' => $theme->get('Version'),
'post_count' => wp_count_posts()->publish,
'page_count' => wp_count_posts('page')->publish,
'user_count' => count_users()['total_users'],
'active_plugins' => count(get_option('active_plugins')),
'disk_usage' => size_format($this->get_upload_size()),
'last_post_date' => get_lastpostdate('blog', 'post'),
'updates_plugins' => $this->count_plugin_updates(),
'updates_themes' => $this->count_theme_updates(),
'ssl_valid' => is_ssl(),
'memory_limit' => WP_MEMORY_LIMIT,
'debug_mode' => WP_DEBUG,
'timestamp' => current_time('mysql'),
];
}
public function bulk_publish($request) {
$params = $request->get_json_params();
$results = [];
foreach ($params['posts'] as $post_data) {
$post_id = wp_insert_post([
'post_title' => sanitize_text_field($post_data['title']),
'post_content' => wp_kses_post($post_data['content']),
'post_status' => $post_data['status'] ?? 'draft',
'post_author' => get_current_user_id(),
'post_category' => $post_data['categories'] ?? [],
'meta_input' => $post_data['meta'] ?? [],
]);
if (!is_wp_error($post_id)) {
if (!empty($post_data['featured_image_url'])) {
$this->set_featured_image($post_id, $post_data['featured_image_url']);
}
$results[] = [
'status' => 'success',
'post_id' => $post_id,
'url' => get_permalink($post_id),
];
} else {
$results[] = [
'status' => 'error',
'error' => $post_id->get_error_message(),
];
}
}
return [
'total' => count($results),
'success' => count(array_filter($results, fn($r) => $r['status'] === 'success')),
'results' => $results,
'timestamp' => current_time('mysql'),
];
}
public function check_admin_permission() {
return current_user_can('manage_options');
}
public function check_publish_permission() {
return current_user_can('publish_posts');
}
private function get_upload_size() {
$upload_dir = wp_upload_dir();
$size = 0;
$path = $upload_dir['basedir'];
if (is_dir($path)) {
foreach (new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path)
) as $file) {
$size += $file->getSize();
}
}
return $size;
}
private function count_plugin_updates() {
$updates = get_site_transient('update_plugins');
return isset($updates->response) ? count($updates->response) : 0;
}
private function count_theme_updates() {
$updates = get_site_transient('update_themes');
return isset($updates->response) ? count($updates->response) : 0;
}
private function set_featured_image($post_id, $image_url) {
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
$attach_id = media_sideload_image($image_url, $post_id, null, 'id');
if (!is_wp_error($attach_id)) {
set_post_thumbnail($post_id, $attach_id);
}
}
}
MAP_Remote_Manager::get_instance();
Application Password 관리 팁
WordPress 5.6부터 Application Password 기능이 기본 내장되어 있습니다. 각 사이트에서 사용자 프로필 > Application Passwords에서 Make.com 전용 비밀번호를 발급하세요. 일반 로그인 비밀번호와 분리되어 있어 보안적으로 안전하며, 문제 발생 시 해당 Application Password만 삭제하면 됩니다. 중요: Application Password는 발급 시 한 번만 표시되므로 즉시 Google Sheets에 기록해야 합니다. 또한 각 사이트마다 고유한 Application Password를 사용하여, 하나의 사이트 인증이 유출되어도 다른 사이트에 영향이 없도록 관리하세요.