워드프레스 REST API, Underscore.js 자바스크립트 템플릿, 포스트 Ajax Load More

연재고품격 고품질 워드프레스 무료 사진 저장소완결2

워드프레스를 포함한 대부분 사이트에서 ‘더보기(Ajax Load More)’는 페이지 이동 없이 지정한 개수의 포스트를 로드하는 것을 말하며, 통용되는 명칭은 아닙니다. 보통 Ajax 통신의 JSON 데이터 포맷을 사용하므로 워드프레스 REST API를 사용하면 적합합니다.

예제 사이트에서 ‘더보기’ 기능은 ‘Infinite Scroll’로 부르는 스크롤 방식이 아닌 버튼 클릭 이벤트로 다루며, 아카이브 페이지에서는 다음 4가지 페이지의 조건에만 적용합니다.

  • 둘러보기 (is_home)
  • 등록자 아카이브 페이지 (is_author)
  • 검색 결과 페이지가 아닌 분류 아카이브 페이지 (is_tax, !is_search)
  • 검색 결과 페이지 (is_search)

위의 목록에서 세 번째는 검색 결과에서 할당하는 is_tax 조건이 아니라 일반적인 분류 아카이브 페이지를 말합니다. 네 번째는 검색 조건 태그를 포함한 검색 결과 페이지를 뜻합니다. 할당 결과 이해가 어렵다면 어드민바 QM 영역을 확인하세요.

이번 장에서 필요한 파일은 다음과 같은데, 편집기로 모두 엽니다.

  • assets/js/pics.js
  • inc/template-tags.php
  • inc/enqueue-script.php
  • inc/header-footer.php
  • inc/rest-api.php

이번에는 위 목록의 완성 파일을 먼저 제공합니다. 먼저, 다음 링크에서 완성 파일을 받고 압축을 풉니다. 아직 테마에 덮어쓰지 말고, 편집기로 5개 파일 따로 엽니다. 이 완성 파일을 참고하여 이어서 안내하는 내용을 확인하거나 따라 하면 됩니다. 완성 파일은 이번 장이 끝난 후에 테마 루트에 덮어쓰세요.

더보기의 엔드포인트 기준

예제의 ‘더보기’를 위한 엔드포인트는 지난 과정의 지도 마커를 위한 커스텀 엔드포인트가 아니라 워드프레스 사이트의 설정 정보 및 각 워드프레스 아카이브 페이지 메인 쿼리 정보를 워드프레스 REST API 엔드포인트의 파라미터와 필터 등에 사용하여 구성하는 ‘URL 쿼리 스트링 조합’으로 말할 수 있습니다. 엔드포인트는 서버의 응답이자 요청 내용이므로 구분이 필요한 때를 제외하고 모두 ‘엔드포인트’로 표기합니다.

둘러보기 아카이브 페이지

둘러보기 페이지의 워드프레스 메인 쿼리 URL은 다음과 같습니다.

localhost/pics
// 타입 attachment 포스트를 한 페이지에 20개 출력

‘더보기’는 위의 URL 요청에 의한 ‘1’ 페이지 attachment 타입 포스트 ‘20’개를 제외하고, 그다음 ‘2’페이지 포스트 20개를 출력해야 합니다. 다시 그다음 ‘더보기’는 ‘3’ 페이지의 ‘20’개 포스트가 되어야 합니다. 정렬 기준(order)은 모두 같아야 하며, 다음의 엔드포인트처럼 정의할 수 있습니다.

  • localhost/wp-json/wp/v2/media?page=2&per_page=20&order=desc
  • localhost/wp-json/wp/v2/media?page=3&per_page=20&order=desc

위의 엔드포인트 흐름에서 한 페이지 출력 개수는 워드프레스 기본 설정(Reading, 읽기)의 데이터를 사용하면 되고, 페이지 번호는 자동 증가로 처리하면 쉽게 동적 엔드포인트를 구성할 수 있습니다.

등록자 아카이브 페이지

등록자 아카이브 페이지의 메인 쿼리 URL은 다음과 같습니다.

localhost/author/photowoman
// PhotoWoman 회원이 등록한 attachment 포스트를 한 페이지에 20개 출력

둘러보기 페이지와 마찬가지로 ‘더보기’ 동적 엔드포인트 기준은 다음과 같습니다. 숫자 13은 PhotoWoman 회원의 아이디로 다를 수 있습니다.

  • localhost/wp-json/wp/v2/media?author=13&page=2&per_page=20&order=desc
  • localhost/wp-json/wp/v2/media?author=13&page=3&per_page=20&order=desc

등록자 아카이브 페이지의 조건 태그 is_author에서 등록자의 숫자 아이디만 구하면 나머지는 둘러보기 페이지처럼 쉽게 동적 엔드포인트를 만들 수 있습니다.

분류 아카이브 페이지

분류 아카이브 페이지의 메인 쿼리 URL은 다음과 같습니다. 분류 mediacat term ‘사진’을 예로 든 것입니다.

localhost/mediacat/사진
// 분류 mediacat term ‘사진’에 속한 attachment 포스트 타입을 한 페이지에 20개 출력

‘더보기’를 위한 워드프레스 REST API 엔드포인트는 다음과 같습니다. 숫자 11은 mediacat term ‘사진’의 숫자 아이디로 다를 수 있습니다.

  • localhost/wp-json/wp/v2/media?mediacat=11&page=2&per_page=20&order=desc
  • localhost/wp-json/wp/v2/media?mediacat=11&page=3&per_page=20&order=desc

분류 아카이브 페이지의 조건 태그 is_tax일 때만 분류 이름과 term의 숫자 아이디를 구하면, 동적 엔드포인트를 구성할 수 있습니다.

검색 결과 페이지의 ‘더보기’ 엔드포인트는 나중에 구성할 때 알아봅니다.

응답 데이터 목록

‘더보기’에 필요한 데이터 목록은 다음과 같은데, 타입 attachment(media) 엔드포인트 하나를 아무거나 선택하고 브라우저나 POSTMAN 애플리케이션으로 접근하여 JSON 응답 데이터를 확인해보세요. 따로 안내하지 않습니다.

id // 이미지 포스트 아이디
title.rendered // 이미지 포스트 제목
alt_text // alt 필드 데이터 (_wp_attachment_image_alt 메타 필드)
link // 이미지 포스트 URL
media_details.sizes.medium.width // medium 이미지 사이즈 이미지의 가로
media_details.sizes.medium.height // medium 이미지 사이즈 이미지의 세로
media_details.sizes.medium.source_url // medium 이미지 사이즈 이미지 URL
download_count // 이미지(포스트) 다운로드 수
like_count // 이미지(포스트) 추천 수

자바스크립트에 초점을 둘 때, 관련 워드프레스 제공 API 사용할 때 등에 따라 방식과 방법이 다양하지만, 예제는 워드프레스 기본의 데이터와 함수 기준으로 단순하게 구성합니다.

더보기 버튼 템플릿 태그 추가

하나만 예를 들어, 사이트 둘러보기 페이지 아래에는 숫자 페이지 내비게이션이 있습니다. 직접 확인해보세요. 이 내비게이션은 템플릿 태그를 사용하여 테마 템플릿 파일에 추가한 것인데, ‘더보기’를 적용하는 조건의 아카이브 페이지에서는 버튼으로 변경합니다.

숫자 페이지 내비게이션은 template-tags.php 파일에 정의되어 있는데, 대략 101번 줄부터 시작합니다.

function pics_posts_navigation() {
    
    // 나중에 추가하여 변경
    
    the_posts_pagination( array(
        'mid_size' => 5,
        'prev_text' => '«',
        'next_text' => '»',
    ) );

}

다음 코드로 대체하고 저장하면 지정 조건일 때의 페이지에서 ‘더보기’ 버튼을 볼 수 있습니다.

function pics_posts_navigation() {
    global $wp_query;
    $max_num_pages = $wp_query->max_num_pages;

    if ( $max_num_pages > 1 && ( is_home() || is_author() || ( is_tax() && !is_search() ) || is_search() ) ) {
    ?>
        <div class="load_more">
            <button id="btn_load_more"><span>더보기</span></button>
        </div>
    <?php
    } else {
        the_posts_pagination( array(
            'mid_size' => 5,
            'prev_text' => '«',
            'next_text' => '»',
        ) );
    }
}

위의 코드 5번 줄은 페이지 수가 2 이상일 때만 버튼을 출력한 것이며, 조건 태그는 앞에서 안내한 것입니다. 사이트에서 다음 목록의 주소로 접근하여 숫자 내비게이션이 버튼으로 변경되었는지 확인해보세요. 목록은 일부만 나열하였습니다.

  • localhost/pics
  • localhost/author/photoman
  • localhost/mediacat/사진

작업 중과 완성 template-tags.php 파일은 모두 닫아도 됩니다.

jQuery Ajax REST API Request

작업 pics.js 파일 대략 28번 줄에서 32번 줄은 다음과 같습니다.

$(document).click(function(e) {
    if (!$(e.target).closest('.ddb, .pop_dropdown').length) {
        $('.pop_dropdown').hide();
    }
});

자바스크립트 변수

위의 코드 다음에 아래의 자바스크립트에 사용할 변수를 추가합니다.

var  restEndpoint = currentPage.rest_endpoint; // 워드프레스 REST API 엔드포인트
    pageCounter = currentPage.page_counter; // 페이지 번호
    perPage = currentPage.per_page; // 한 페이지 출력 개수
    blankImage = currentPage.blank_image; // Lazy Load Blank Image

이 변수들은 지난 과정에서 몇 번 경험한 것처럼 워드프레스 함수를 사용하여 사이트 소스에 추가하여 사용합니다. 같은 값이 있지만, 각 페이지의 조건에 따라 구분하여 생성합니다.

버튼 이벤트와 동적 엔드포인트

계속해서 다음처럼 버튼 이벤트에 앞에서 정의한 변수를 사용하여 동적 엔드포인트를 추가합니다.

$('#btn_load_more').click(function(){
    $('#btn_load_more span').text('loading...');
    $.ajax({
        type: 'GET',
        url: restEndpoint + '&page=' + pageCounter + '&per_page=' + perPage + '&order=desc',
        success: renderHtml
    });
    pageCounter++; // 페이지 번호 증가
});

일부 변경하지만, 위의 코드는 사이트 ‘더보기’ 워드프레스 REST API 엔드포인트 jQuery Ajax 요청의 전부입니다.

다음은 요청 성공 시 실행 함수로 워드프레스 REST API 응답 데이터를 출력하는 것입니다. 이어서 추가하면 됩니다. 일부만 나열한 것이며 전체는 완성 파일을 참고하세요.

function renderHtml(data, textStatus, xhr){
    var total_pages = parseInt( xhr.getResponseHeader('X-WP-TotalPages') );
    var total_counts = parseInt( xhr.getResponseHeader('X-WP-Total') );
    $.each(data, function(index, post){
        //
    });
    $('#btn_load_more span').text( total_counts - ( perPage * ( pageCounter-1 ) ) + '개 남음' );
}

둘러보기 페이지의 더보기

둘러보기 페이지는 is_home 조건 태그를 가지고 있습니다. 사이트에서 둘러보기 페이지에 접근하여 어드민바의 QM 영역을 확인해보세요.

편집기의 작업 enqueue-script.php 파일 대략 36번 줄에서 41번 줄은 다음과 같습니다.

// 둘러보기, 아카이브, 검색 결과, 앨범 아카이브 페이지, 회원 활동
elseif ( is_home() || is_archive() || is_search() || is_page_template( 'page-templates/album-page.php' ) || is_page_template( 'page-templates/user-history.php' ) ) {
    wp_localize_script('pics-js', 'currentPage', array(
        'current_condition' => 'archive',
    ));
}

위의 코드를 다음으로 대체하고 저장합니다.

// 앨범 아카이브, 회원 활동 페이지
elseif ( is_page_template( 'page-templates/album-page.php' ) || is_page_template( 'page-templates/user-history.php' ) ) {
    wp_localize_script('pics-js', 'currentPage', array(
        'current_condition' => 'archive',
    ));
}
// 둘러보기, is_home()
elseif ( is_home() ) {
    $per_page = get_option( 'posts_per_page' );
    wp_localize_script('pics-js', 'currentPage', array(
        'current_condition' => 'archive',
        'blank_image' => get_theme_file_uri( '/assets/images/blank.gif' ),
        'rest_endpoint' => esc_url_raw( rest_url( 'wp/v2/media?parent=0' ) ),
        'page_counter' => 2,
        'per_page' => $per_page,
    ));
}

위의 코드 9번 줄은 관리페이지에서 설정하는 포스트 출력 개수로 관리페이지에서 변경하면 엔드포인트 구성에 그대로 적용되므로 다른 변경 작업이 필요하지 않습니다. 단, 워드프레스 기본 엔드포인트의 한 페이지 최대 출력 개수는 100이므로 100보다 큰 수를 입력하면 오류가 발생합니다.

13번 줄의 다음 코드에서 parent 파라미터는 pics.js 파일의 공통 엔드포인트(url) 파라미터 연결 구조를 맞추기 위해 추가한 것이며, 예제의 이미지 포스트는 특정 포스트에 첨부되지 않은 attachment 포스트 타입이므로 추가하거나 제외해도 결과는 같습니다.

// 둘러보기 페이지의 엔드포인트
'rest_endpoint' => esc_url_raw( rest_url( 'wp/v2/media?parent=0' ) ),

위의 코드는 사이트 둘러보기 페이지 소스에 다음 데이터를 출력합니다.

// 둘러보기 페이지 사이트 소스의 자바스크립트 로컬 데이터
var currentPage = {"current_condition":"archive","blank_image":"http:\/\/localhost\/wp-content\/themes\/pics_press\/assets\/images\/blank.gif","rest_endpoint":"http:\/\/localhost\/wp-json\/wp\/v2\/media?parent=0","page_counter":"2","per_page":"20"};

브라우저 개발자 도구를 열고, 둘러보기 페이지에 접근 또는 페이지를 새로 고칩니다. 그다음 ‘더보기’ 버튼을 클릭하여 변화를 확인해보세요. 다시, 개발자 도구에서 Network, XHR 탭을 클릭하고, 둘러보기 페이지를 새로 고친 후 ‘더보기’ 버튼을 몇 번 클릭하면서 개발자 도구를 확인해보세요.

개발자 도구의 XHR 탭에서 ‘더보기’ 버튼을 클릭할 때마다 나오는 Name 영역의 엔드포인트를 클릭하여 Headers, Preview 탭의 정보를 확인하세요. 지난 과정에서 안내한 것이므로 따로 설명하지 않습니다.

‘더보기’ 버튼을 클릭할 때마다 페이지 이동없이 이미지 포스트가 올바르게 출력되지만, 이미 출력된 이미지 깜빡거림이나 인접한 이미지 줄 외 이미지가 재정렬되는 현상이 있을 수 있습니다. 다음처럼 편집 중인 pics.js 파일 19번에서 21번 줄 빗금을 제거하고 저장 후 둘러보기 페이지를 새로 고쳐 ‘더보기’ 버튼을 클릭해보세요.

load: function() {
    $('.lazy').attr('class','early-bird');
}

등록자 아카이브 페이지의 더보기

먼저, 예제에서는 기여자(Contributor) 역할(Role) 등록자의 아카이브 페이지만 허용합니다. 로그인 회원 기준이 아닌 등록자입니다. 다음 코드로 기여자가 아닌 등록자의 아카이브 페이지에 접근하면 사이트 프런트 페이지로 이동합니다.

// A
$object_author_id = get_queried_object()->ID;
$author_meta = get_userdata( $object_author_id );
$author_roles = $author_meta->roles;
if ( !in_array( 'contributor', $author_roles ) ) {
    wp_redirect( esc_url( home_url( '/' ) ) );
    exit;
}

브라우저에서 generalMember 회원 아카이브 페이지 URL로 접근해보세요.

이어서 등록자 아카이브 페이지의 ‘더보기’ 엔드포인트에 필요한 자바스크립트 변수를 다음처럼 정의할 수 있습니다.

// B
$per_page = get_option( 'posts_per_page' );
wp_localize_script('pics-js', 'currentPage', array(
    'current_condition' => 'archive',
    'blank_image' => get_theme_file_uri( '/assets/images/blank.gif' ),
    'rest_endpoint' => esc_url_raw( rest_url( 'wp/v2/media?author=' . $object_author_id ) ),
    'page_counter' => 2,
    'per_page' => $per_page,
));

사이트에서 등록자 아카이브 페이지는 is_author 조건 태그를 가집니다. 조건 태그와 위의 A, B 코드를 함께 편집 중인 enqueue-script.php 파일의 둘러보기 페이지 코드 다음에 추가하고 저장합니다. 혹시 따라 하고 있다면 완성 enqueue-script.php 파일을 참고하세요

elseif ( is_author() ) {
    // A
    // B
}

하나의 결과만 확인하는데, 사이트에서 기여자 중 PhotoMan 회원의 아카이브 페이지에 접근하여 ‘더보기’ 버튼을 클릭하고, 개발자 도구의 여러 탭의 정보를 확인해보세요. 사이트 소스 페이지의 로컬 변수 데이터도 둘러보세요.

분류 아카이브 페이지의 더보기

분류 아카이브 페이지의 자바스크립트 변수를 위해 다음 코드를 편집 중인 enqueue-script.php 파일의 등록자 아카이브 코드 다음에 이어서 추가하고 저장합니다.

elseif ( is_tax() && !is_search() ) {
    $current_tax_name = get_queried_object()->taxonomy;
    $current_term_id = get_queried_object()->term_id;
    $per_page = get_option( 'posts_per_page' );
    wp_localize_script('pics-js', 'currentPage', array(
        'current_condition' => 'archive',
        'blank_image' => get_theme_file_uri( '/assets/images/blank.gif' ),
        'rest_endpoint' => esc_url_raw( rest_url( 'wp/v2/media?' . $current_tax_name . '=' . $current_term_id ) ),
        'page_counter' => 2,
        'per_page' => $per_page,
    ));
}

예제 사이트에서 검색 조건 없이 검색 버튼을 클릭할 때, ‘미디어 종류’나 ‘카테고리’ 항목의 분류 선택 없이 ‘방향’과 ‘크기’ 항목에 조건을 설정하여 검색할 때 검색 결과 페이지는 is_search 조건 태그만 가집니다. 하나 이상의 분류 선택만 추가되면 is_tax (상위 태그 is_archive 제외) 조건 태그가 추가됩니다. 사이트 검색 쿼리 구성에 따른 결과입니다.

워드프레스 사이트는 조건 태그 기준에 따라 결과를 다양하게 제어할 수 있는데, 조금 더 복잡한 콘텐츠의 사이트일 때 조건 태그의 중복 등을 확인하지 못하면 원하는 결과 도출이나 오류 수정에 괜한 어려움이 있습니다. 예제처럼 최소한 QM 플러그인 유형의 구성 도움 요소와 함께 사이트를 구성하기 바랍니다.

사이트에서 다음 목록의 메인 쿼리 URL로 접근하여 둘러보기와 등록자 아카이브 페이지처럼 ‘더보기’ 버튼을 클릭 후 개발자 도구 및 사이트 소스를 확인해보세요.

  • localhost/mediacat/사진
  • localhost/photocat/사람

멀티 메타 필드 검색을 위한 워드프레스 REST API 필터

둘러보기, 등록자 및 분류 아카이브 페이지의 ‘더보기’를 위한 엔드포인트는, 워드프레스 메인 쿼리 기준에서 워드프레스 REST API 기본 제공 파라미터만 추가하면 쉽게 구성할 수 있었습니다.

검색도 다음처럼 파라미터를 조합하여 구성할 수 있습니다. 두 번째와 같이 예제 검색 폼에서 구성하지 않은 등록자(author)도 포함할 수 있습니다. 모두 워드프레스 REST API 기본 제공에 의한 것입니다.

  • localhost/wp-json/wp/v2/media?mediacat=11&photocat=328
  • localhost/wp-json/wp/v2/media?mediacat=11&photocat=328&search=바다&author=13

문제는 메타 데이터에 관한 것인데, 워드프레스 4.7부터 REST API를 코어에 포함하면서 메타 데이터와 메타 데이터의 비교 연산자 포함 기준의 검색까지 가능했던 filter 파라미터가 제외되었습니다. 이 글을 쓰는 시점 기준이므로 이미 말한 것처럼 코덱스를 먼저 확인 후 워드프레스 REST API에 접근해야 합니다.

WP REST Filter

워드프레스 REST API 팀에서 해당 파라미터를 사용할 수 있는 플러그인을 제공하고 있지만, 예제의 검색 결과를 위한 ‘더보기’ 엔드포인트 구성에는 추가 작업이 필요합니다. 그러나, 추가 작업 없이 예제에 적합한 WP REST Filter 플러그인을 사용하면 바로 비교 연산을 포함한 멀티 메타 필드 엔드포인트를 구성할 수 있습니다.

이 플러그인은 설치해도 되지만, 훅과 함수의 간단한 코드로 구성되어 있어 완성 rest-api.php 파일 84번 줄부터 추가하여 제공하였습니다. 완성 rest-api.php 파일의 모든 코드를 복사하여 작업 중인 rest-api.php 파일의 모든 코드와 대체하고 저장합니다. 그리고 모든 rest-api.php 파일은 닫습니다.

검색 결과 페이지를 위한 엔드포인트

먼저, 완성 enqueue-script.php 파일의 모든 코드를 복사하여 작업 중인 enqueue-script.php 파일의 모든 코드와 대체하고 저장합니다. 검색 결과 페이지의 ‘더보기’를 위한 엔드포인트 구성은 완성 파일로 안내합니다.

다음 코드는 검색 결과 페이지 엔드포인트를 위한 자바스크립트 로컬 데이터 생성 코드입니다.

$per_page = get_option( 'posts_per_page' );
wp_localize_script('pics-js', 'currentPage', array(
    'current_condition' => 'archive',
    'rest_endpoint' => esc_url_raw( rest_url( 'wp/v2/media?' . $endpoint ) ),
    'page_counter' => 2,
    'per_page' => $per_page,
));

엔드포인트를 위한 $endpoint 변수만 구성하면 됩니다. 검색 결과 페이지 엔드포인트는 다음처럼 구성하는 것이 목표입니다. 키워드 REST API 파라미터 search는 제외하였는데, 키워드를 포함하여 검색하면 추가됩니다.

localhost/wp-json/wp/v2/media?
mediacat=11&photocat=12&
filter[meta_query][0][key]=pic_axis&
filter[meta_query][0][value]=가로&
filter[meta_query][0][compare]==&
filter[meta_query][1][key]=pic_width&
filter[meta_query][1][value]=4000&
filter[meta_query][1][compare]=>&
filter[meta_query][2][key]=pic_height&
filter[meta_query][2][value]=2001&
filter[meta_query][2][compare]=>&
page=2&per_page=20&order=desc

위의 엔드포인트는 페이지 번호를 제외하고 다음의 그림처럼 검색 폼에서 검색한 조건입니다. 먼저, 브라우저의 개발자 도구를 열고, 사이트의 검색 폼을 펼쳐 다음 그림을 참고하여 검색합니다.

검색 폼의 이미지 포스트 검색

다음 그림은 개발자 도구에서 확인한 폼 데이터입니다. 검색 키워드(s)는 입력하지 않았으므로 나오지 않습니다.

개발자 도구에서 확인한 폼 데이터

검색 결과 포스트 개수는 ‘23’개인데, 이 검색 기준과 결과로 검색 페이지 ‘더보기’ 결과를 확인합니다.

워드프레스 REST API 엔드포인트에 값이 없는 파라미터가 있다면 오류가 나오므로 위의 검색 폼 파라미터를 기준으로 하나씩 조건으로 정의합니다.

분류와 키워드

다음은 mediacat 쿼리 변수 데이터의 term 이름으로 term의 숫자 아이디를 구하는 코드입니다. 엔드포인트에는 분류 term의 숫자 아이디가 필요하며, 사이트의 검색은 분류 term 이름 기준입니다.

if ( $_REQUEST[ 'mediacat' ] ) {
    $mediacat_obj = get_term_by( 'name', $_REQUEST[ 'mediacat' ], 'mediacat' );
    $mediacat_term_id = $mediacat_obj->term_id;
    $tax_mediacat = absint( $mediacat_term_id );
} else {
    $tax_mediacat = '';
} // mediacat

나머지 분류 photocat의 term과 s 검색 키워드는 완성 파일을 참고하세요.

메타 필드

다음은 에제의 검색 폼에 사용하는 3가지 메타 필드를 엔드포인트에 사용하기 위해 key, value, compare 3가지 키를 배열에 포함한 것입니다.

if ( $_REQUEST[ 'pic_axis' ] ) {
    $pic_axis = strip_tags( sanitize_text_field( $_REQUEST[ 'pic_axis' ] ) );
    $pic_axis_array = array(
        'key' => 'pic_axis', 'value' => $pic_axis, 'compare' => '=',
    );
} else {
    $pic_axis_array = '';
} // pic_axis
if ( $_REQUEST[ 'pic_width' ] ) {
    $pic_width = absint( $_REQUEST[ 'pic_width' ] );
    $pic_width_array = array(
        'key' => 'pic_width', 'value' => $pic_width, 'compare' => '>',
    );
} else {
    $pic_width_array = '';
} // pic_width
if ( $_REQUEST[ 'pic_height' ] ) {
    $pic_height = absint( $_REQUEST[ 'pic_height' ] );
    $pic_height_array = array(
        'key' => 'pic_height', 'value' => $pic_height, 'compare' => '>',
    );
} else {
    $pic_height_array = '';
} // pic_height

완성 enqueue-script.php 파일 140번 줄과 145번 줄은 다음과 같습니다.

$endpoint = http_build_query( array_merge( $rest_args1, $rest_args2 ) );
'rest_endpoint' => esc_url_raw( rest_url( 'wp/v2/media?' . $endpoint ) ),

분류 및 키워드 배열 $rest_args1, 메타 필드 배열 $rest_args2 변수를 http_build_query PHP 함수를 사용하여 URL 쿼리 스트링 형태로 엔드포인트에 추가한 것입니다. 편집기에 열린 모든 enqueue-script.php 파일을 닫으세요.

검색 결과 더보기

브라우저에서 개발자 도구를 열고, 앞에서 23개의 포스트를 출력한 검색 조건으로 다시 검색한 후 ‘더보기’ 버튼을 클릭하여 3개의 이미지가 추가 로드된 후 버튼이 제거되는지 확인합니다. 그리고, 사이트 소스를 확인하여 다음 로컬 자바스크립트 변수와 데이터가 있는지 봅니다.

// 검색 페이지 사이트 소스의 로컬 자바스크립트 데이터
var currentPage = {"current_condition":"archive","rest_endpoint":"http:\/\/localhost\/wp-json\/wp\/v2\/media?mediacat=11&photocat=12&filter%5Bmeta_query%5D%5B0%5D%5Bkey%5D=pic_axis&filter%5Bmeta_query%5D%5B0%5D%5Bvalue%5D=\uac00\ub85c&filter%5Bmeta_query%5D%5B0%5D%5Bcompare%5D==&filter%5Bmeta_query%5D%5B1%5D%5Bkey%5D=pic_width&filter%5Bmeta_query%5D%5B1%5D%5Bvalue%5D=4000&filter%5Bmeta_query%5D%5B1%5D%5Bcompare%5D=>&filter%5Bmeta_query%5D%5B2%5D%5Bkey%5D=pic_height&filter%5Bmeta_query%5D%5B2%5D%5Bvalue%5D=2001&filter%5Bmeta_query%5D%5B2%5D%5Bcompare%5D=>","page_counter":"2","per_page":"20"};

버튼 클릭 후 개발자 도구의 해당 엔드포인트 Headers 탭의 Request URL을 보면 다음 그림과 같습니다.

개발자 도구의 엔드포인트 Headers 탭의 Request URL

인코드Encode URL이므로 쉽게 알아보기 어려운데, 다른 방법 생각하지 말고 브라우저 탭을 하나 추가하여 meyerweb.com/eric/tools/dencoder/ 페이지에 접근합니다. Request URL을 복사하여 디코드 폼에 추가하고 디코드 버튼을 클릭하세요. 앞에서 게시한 엔드포인트 목표와 일치할 것입니다.

다음 그림을 보면 ‘23’개의 포스트, 페이지 수 ‘2’를 확인할 수 있습니다. 검색 결과와 일치합니다.

개발자 도구 Header 탭의 검색 결과 포스트 수와 페이지

다음 그림은 쿼리 스트링 파라미터로, 검색 결과 페이지의 ‘더보기’ 엔드포인트 구성을 직관적으로 볼 수 있습니다.

엔드포인트 쿼리 스트링 파라미터

‘더보기’를 위한 엔드포인트는 단순히 각 페이지의 기준 워드프레스 메인 쿼리에 맞게 특정 파라미터와 값을 동적으로 정의한 것에 불과하며, 워드프레스 REST API를 사용하지 않는다면 단순 문자에 지나지 않습니다. 몇 가지 다른 조건으로도 검색해보세요.

워드프레스 내장 Underscore.js 자바스크립트 템플릿

편집기에 열린 파일을 모두 닫고, 앞에서 제공한 완성 파일을 테마 루트에 모두 덮어쓴 후 편집기로 테마 루트의 다음 파일을 다시 엽니다.

  • assets/js/pics.js
  • inc/header-footer.php
  • inc/enqueue-script.php

편집기의 pics.js 완성 파일 38번 줄, 46번 줄에서 66번 줄은 다음과 같습니다.

// 38번 줄
archiveTemplate = wp.template('pic-archive');

// 46번에서 66번 줄
//success: renderHtml
success: function(data, textStatus, xhr){
    var total_pages = parseInt(xhr.getResponseHeader('X-WP-TotalPages'));
    var total_counts = parseInt(xhr.getResponseHeader('X-WP-Total'));
    console.log(data);
    // archive - 둘러보기, 등록자, 분류, 검색 결과
    if ( currentCondition === 'archive' ) {
        $(archiveTemplate(data)).appendTo('.flex-images');
        $('.flex-images').flexImages({ rowHeight: 300 });
        $('img.lazy').lazyload({
            effect: "fadeIn",
            load: function() {
                $('.lazy').attr('class','early-bird'); // 더보기에서 reload 방지
            }
        });
    }
    if ( pageCounter > total_pages ) {
        $('#btn_load_more').remove(); //페이지 번호가 총 페이지 수보다 크면 버튼 제거
    }
    $('#btn_load_more span').text( total_counts - ( perPage * ( pageCounter-1 ) ) + '개 남음' );
}

5번 줄에서 renderHtml 함수를 빗금으로 비활성화하고, 2번 줄의 wp.template 워드프레스 자바스크립트 함수를 변수에 할당하였습니다. 12번 줄에서 워드프레스 REST API 응답 데이터를 archiveTemplate 변수에 전달하여 데이터와 함께 Html을 생성하는 간단한 코드입니다. 이때 archiveTemplate 변수의 wp.template 함수는 Underscore.js 자바스크립트 라이브러리 형식의 자바스크립트 템플릿을 렌더링하는 함수입니다. 2번 줄의 pic-archive 이름은 지정한 템플릿 이름입니다.

편집기의 완성 header-footer.php 파일 12번 줄에서 27번 줄의 코드를 보면 흐름을 알 수 있는데, 다음과 같습니다.

<script type="text/html" id="tmpl-pic-archive">       
    <# _.each( data, function( post ){ #>
        <article id="post-{{ post.id }}">
            <div class="item" data-w="{{ post.media_details.sizes.medium.width }}" data-h="{{ post.media_details.sizes.medium.height }}">
                <a href="{{ post.link }}"><img title="{{ post.alt_text }}" alt="{{ post.title.rendered }}" class="lazy" src="{{ currentPage.blank_image }}" data-original="{{ post.media_details.sizes.medium.source_url }}"></a>
                <div class="hover_info">
                    <div class="dl_count">
                        <span class="dc">{{ post.download_count }}</span>
                        <span class="lc">{{ post.like_count }}</span>
                    </div>
                    <span class="iname">{{{ post.title.rendered }}}</span>
                </div>
            </div>
        </article>
    <# }) #>
</script>

1번 줄의 tmpl-pic-archive 템플릿 아이디에서 tmpl- 접두어로 시작하는 pic-archive 템플릿 이름을 볼 수 있습니다. 워드프레스 REST API 응답 데이터를 모두 자바스크립트로 전달하여 Html과 함께 렌더링합니다. ‘더보기’를 구성한 페이지의 사이트 소스를 보면 위의 템플릿 소스가 추가된 것을 볼 수 있습니다.

3번 줄에서 14번 줄의 Html 마크업은 예제 사이트의 아카이브 페이지에서 이미지 포스트 하나의 루프 파일 소스를 참고하면 됩니다.

Underscore.js 라이브러리는 워드프레스에 내장된 외부 라이브러리로 워드프레스에서는 약간 수정된 형태로 사용한다는 것과 간단한 예로 경험하는 정도로 생각하세요. 나머지는 코덱스에서 약간의 추가 정보를 얻기 바랍니다. 이 라이브러리는 다음의 enqueue-script.php 파일 13번 줄의 코드를 추가하는 것으로 사용할 수 있습니다.

//enqueue-script.php 파일 13번 줄
wp_enqueue_script( 'wp-util' );

자바스크립트 템플릿 사용의 이유와 장∙단점은 개인 판단 영역이므로 좋거나 나쁘거나, 틀리거나로 말할 수 없습니다. 예제의 짧은 경험을 시작으로 직접 사용 명분을 만들어 보세요.

혹시 예제 오류가 나지 않도록 이번 장에서 제공한 완성 파일을 테마 루트에 다시 덮어쓰세요.

예제 목차

0. 고품격 고품질 워드프레스 무료 사진 저장소

1. 예제 구성 환경과 파일

2. XAMPP, 워드프레스, 테마, 플러그인 설치와 설정

3. 테마 Pics Press

4. page 포스트 타입과 페이지 템플릿, 메뉴 구성

5. 워드프레스 핵심 용어 짚기

6. 워드프레스 포스트 타입 attachment

7. 워드프레스 이미지 사이즈

8. 워드프레스 이미지 사이즈 추가 및 변경

9. 워드프레스 이미지 파일 제어

10. 타입 attachment 템플릿과 image.php

11. 워드프레스 이미지 메타 데이터

12. GPS 데이터를 워드프레스 메타 데이터로 저장

13. 이미지 메타 데이터를 포스트 메타 데이터에 추가

14. Attachment 타입을 위한 워드프레스 커스텀 분류 등록

15. 이미지 메타 데이터를 워드프레스 분류와 필드 데이터에 저장

16. 이미지를 편집할 때 포스트 데이터와 메타 데이터 업데이트

17. 워드프레스 미디어 파일 업로드

18. 워드프레스 싱글 이미지 포스트 페이지

19. 워드프레스 아바타와 Author Archives

20. 워드프레스 이미지 사이즈별 데이터 출력

21. 워드프레스 폼 요소로 원하는 이미지 사이즈 다운로드

22. 워드프레스 텍스트 단락 및 줄 바꿈, wpautop

23. 워드프레스 사진의 EXIF 데이터 출력

24. 구글 지도에 표시하는 사진 촬영 위치

25. 워드프레스 attachment 포스트 타입의 아카이브

26. 워드프레스 함수로 자바스크립트 변수 데이터 생성

27. 워드프레스 커스텀 검색 – 쿼리 변수

28. 워드프레스 커스텀 검색 – 검색 폼과 쿼리 데이터

29. 워드프레스 커스텀 포스트 타입 ‘pic_album’

30. 커스텀 포스트 타입의 싱글 페이지

31. 워드프레스 WP_Query

32. 커스텀 쿼리, 페이지 템플릿, 포스트 아카이브

33. 분류 기준의 관련 포스트 커스텀 쿼리

34. wpdb 클래스로 구글 지도에 마커와 섬네일 표시

35. 워드프레스 분류 데이터 쿼리 클래스, WP_Term_Query

36. 워드프레스 템플릿 태그

37. 워드프레스 옵션 페이지, 옵션 필드

38. 워드프레스 사이트 프런트 페이지

39. 사이트 메뉴 및 포스트 페이지 링크

40. 워드프레스 Transient API

41. 워드프레스 분류의 term 데이터를 캐시 데이터로 생성

42. 워드프레스 역할 그룹과 권한으로 구성 요소 제어

43. 간단한 워드프레스 코멘트 폼 수정

44. 워드프레스 대시보드 위젯 추가

45. 워드프레스 REST API 간략 이해

46. 워드프레스 REST API 응답에 커스텀 필드 추가

47. 워드프레스 REST API 커스텀 라우트 및 엔드포인트

48. 워드프레스 REST API 커스텀 엔드포인트로 구글 클러스터 지도 마커와 인포 윈도 표시

» 워드프레스 REST API, Underscore.js 자바스크립트 템플릿, 포스트 Ajax Load More

50. 워드프레스 REST API, Underscore.js 자바스크립트 템플릿, 코멘트 Ajax Load More

51. 워드프레스 REST API 인증과 제한 및 제어