Initial commit of slide manager plugin
This commit is contained in:
@@ -0,0 +1,532 @@
|
||||
<?php
|
||||
/**
|
||||
* HSSM REST API Class
|
||||
*
|
||||
* Handles REST API endpoints for companion sites to fetch slides
|
||||
*
|
||||
* @package Hi_School_Slide_Manager
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit( 'Direct access forbidden.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* HSSM REST API Class
|
||||
*
|
||||
* Custom REST API endpoints for slide distribution to companion sites
|
||||
*/
|
||||
class HSSM_REST_API {
|
||||
|
||||
/**
|
||||
* API namespace
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
const NAMESPACE = 'hssm/v1';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
// Hook is registered in main class
|
||||
}
|
||||
|
||||
/**
|
||||
* Register REST API routes
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function register_routes() {
|
||||
// Get slides for a specific site
|
||||
register_rest_route( self::NAMESPACE, '/slides/(?P<site>[a-zA-Z0-9-]+)', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_slides_for_site' ),
|
||||
'permission_callback' => array( $this, 'check_api_permissions' ),
|
||||
'args' => array(
|
||||
'site' => array(
|
||||
'required' => true,
|
||||
'validate_callback' => array( $this, 'validate_site_slug' ),
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'description' => 'Site slug (hi-school, one-stop, ace)',
|
||||
),
|
||||
'date' => array(
|
||||
'required' => false,
|
||||
'validate_callback' => array( $this, 'validate_date' ),
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'description' => 'Date to get slides for (YYYY-MM-DD format)',
|
||||
),
|
||||
'limit' => array(
|
||||
'required' => false,
|
||||
'default' => 10,
|
||||
'validate_callback' => array( $this, 'validate_limit' ),
|
||||
'sanitize_callback' => 'absint',
|
||||
'description' => 'Maximum number of slides to return (1-50)',
|
||||
),
|
||||
'status' => array(
|
||||
'required' => false,
|
||||
'default' => 'active',
|
||||
'validate_callback' => array( $this, 'validate_status' ),
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'description' => 'Slide status: active, scheduled, all',
|
||||
),
|
||||
),
|
||||
) );
|
||||
|
||||
// Get all available sites
|
||||
register_rest_route( self::NAMESPACE, '/sites', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_available_sites' ),
|
||||
'permission_callback' => array( $this, 'check_api_permissions' ),
|
||||
) );
|
||||
|
||||
// Get slide by ID
|
||||
register_rest_route( self::NAMESPACE, '/slide/(?P<id>\d+)', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_slide_by_id' ),
|
||||
'permission_callback' => array( $this, 'check_api_permissions' ),
|
||||
'args' => array(
|
||||
'id' => array(
|
||||
'required' => true,
|
||||
'validate_callback' => array( $this, 'validate_slide_id' ),
|
||||
'sanitize_callback' => 'absint',
|
||||
'description' => 'Slide ID',
|
||||
),
|
||||
),
|
||||
) );
|
||||
|
||||
// Health check endpoint
|
||||
register_rest_route( self::NAMESPACE, '/health', array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'health_check' ),
|
||||
'permission_callback' => '__return_true', // Public endpoint
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slides for a specific site
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object
|
||||
*/
|
||||
public function get_slides_for_site( $request ) {
|
||||
$site_slug = $request->get_param( 'site' );
|
||||
$date = $request->get_param( 'date' );
|
||||
$limit = $request->get_param( 'limit' );
|
||||
$status = $request->get_param( 'status' );
|
||||
|
||||
// Get the site term
|
||||
$site_term = get_term_by( 'slug', $site_slug, 'hssm_site' );
|
||||
if ( ! $site_term ) {
|
||||
return new WP_Error( 'invalid_site', 'Invalid site slug', array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
// Build query args
|
||||
$query_args = array(
|
||||
'post_type' => 'hssm_slide',
|
||||
'posts_per_page' => $limit,
|
||||
'post_status' => 'publish',
|
||||
'meta_key' => '_hssm_order',
|
||||
'orderby' => 'meta_value_num',
|
||||
'order' => 'ASC',
|
||||
'tax_query' => array(
|
||||
array(
|
||||
'taxonomy' => 'hssm_site',
|
||||
'field' => 'term_id',
|
||||
'terms' => $site_term->term_id,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Add date filtering if specified
|
||||
if ( $date ) {
|
||||
$target_date = $date . ' 23:59:59';
|
||||
$query_args['meta_query'] = array(
|
||||
'relation' => 'AND',
|
||||
array(
|
||||
'relation' => 'OR',
|
||||
array(
|
||||
'key' => '_hssm_start_date',
|
||||
'value' => '',
|
||||
'compare' => '='
|
||||
),
|
||||
array(
|
||||
'key' => '_hssm_start_date',
|
||||
'value' => $target_date,
|
||||
'compare' => '<='
|
||||
),
|
||||
array(
|
||||
'key' => '_hssm_start_date',
|
||||
'compare' => 'NOT EXISTS'
|
||||
)
|
||||
),
|
||||
array(
|
||||
'relation' => 'OR',
|
||||
array(
|
||||
'key' => '_hssm_end_date',
|
||||
'value' => '',
|
||||
'compare' => '='
|
||||
),
|
||||
array(
|
||||
'key' => '_hssm_end_date',
|
||||
'value' => $target_date,
|
||||
'compare' => '>='
|
||||
),
|
||||
array(
|
||||
'key' => '_hssm_end_date',
|
||||
'compare' => 'NOT EXISTS'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Handle status filtering
|
||||
if ( $status === 'scheduled' ) {
|
||||
$current_time = current_time( 'mysql' );
|
||||
$query_args['meta_query'] = array(
|
||||
array(
|
||||
'key' => '_hssm_start_date',
|
||||
'value' => $current_time,
|
||||
'compare' => '>'
|
||||
)
|
||||
);
|
||||
} elseif ( $status === 'all' ) {
|
||||
$query_args['post_status'] = array( 'publish', 'future', 'draft' );
|
||||
}
|
||||
|
||||
$slides_query = new WP_Query( $query_args );
|
||||
$slides_data = array();
|
||||
|
||||
if ( $slides_query->have_posts() ) {
|
||||
while ( $slides_query->have_posts() ) {
|
||||
$slides_query->the_post();
|
||||
$slides_data[] = $this->format_slide_data( get_post() );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
$response_data = array(
|
||||
'slides' => $slides_data,
|
||||
'site' => array(
|
||||
'slug' => $site_slug,
|
||||
'name' => $site_term->name,
|
||||
'description' => $site_term->description,
|
||||
),
|
||||
'meta' => array(
|
||||
'total_slides' => count( $slides_data ),
|
||||
'query_date' => $date ?: current_time( 'Y-m-d' ),
|
||||
'status_filter' => $status,
|
||||
'timestamp' => current_time( 'c' ),
|
||||
'cache_duration' => get_option( 'hssm_cache_duration', 3600 ),
|
||||
),
|
||||
);
|
||||
|
||||
return rest_ensure_response( $response_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available sites
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response Response object
|
||||
*/
|
||||
public function get_available_sites( $request ) {
|
||||
$sites = get_terms( array(
|
||||
'taxonomy' => 'hssm_site',
|
||||
'hide_empty' => false,
|
||||
) );
|
||||
|
||||
$sites_data = array();
|
||||
if ( ! is_wp_error( $sites ) ) {
|
||||
foreach ( $sites as $site ) {
|
||||
$sites_data[] = array(
|
||||
'slug' => $site->slug,
|
||||
'name' => $site->name,
|
||||
'description' => $site->description,
|
||||
'slide_count' => $this->get_site_slide_count( $site->term_id ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return rest_ensure_response( array(
|
||||
'sites' => $sites_data,
|
||||
'total' => count( $sites_data ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slide by ID
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object
|
||||
*/
|
||||
public function get_slide_by_id( $request ) {
|
||||
$slide_id = $request->get_param( 'id' );
|
||||
$slide = get_post( $slide_id );
|
||||
|
||||
if ( ! $slide || $slide->post_type !== 'hssm_slide' ) {
|
||||
return new WP_Error( 'slide_not_found', 'Slide not found', array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
return rest_ensure_response( $this->format_slide_data( $slide ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Health check endpoint
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response Response object
|
||||
*/
|
||||
public function health_check( $request ) {
|
||||
return rest_ensure_response( array(
|
||||
'status' => 'healthy',
|
||||
'plugin' => 'Hi-School Slide Manager',
|
||||
'version' => HSSM_VERSION,
|
||||
'timestamp' => current_time( 'c' ),
|
||||
'endpoints' => array(
|
||||
'slides' => rest_url( self::NAMESPACE . '/slides/{site}' ),
|
||||
'sites' => rest_url( self::NAMESPACE . '/sites' ),
|
||||
'slide' => rest_url( self::NAMESPACE . '/slide/{id}' ),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check API permissions
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return bool|WP_Error Permission check result
|
||||
*/
|
||||
public function check_api_permissions( $request ) {
|
||||
// Get the API key from header or query parameter
|
||||
$api_key = $request->get_header( 'X-HSSM-API-Key' );
|
||||
if ( ! $api_key ) {
|
||||
$api_key = $request->get_param( 'api_key' );
|
||||
}
|
||||
|
||||
if ( ! $api_key ) {
|
||||
return new WP_Error( 'missing_api_key', 'API key required', array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
// Validate API key
|
||||
$valid_keys = get_option( 'hssm_api_keys', array() );
|
||||
if ( ! in_array( $api_key, $valid_keys ) ) {
|
||||
return new WP_Error( 'invalid_api_key', 'Invalid API key', array( 'status' => 403 ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format slide data for API response
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param WP_Post $slide Slide post object
|
||||
* @return array Formatted slide data
|
||||
*/
|
||||
private function format_slide_data( $slide ) {
|
||||
$slide_data = array(
|
||||
'id' => $slide->ID,
|
||||
'title' => $slide->post_title,
|
||||
'subtitle' => get_post_meta( $slide->ID, '_hssm_subtitle', true ),
|
||||
'content' => $slide->post_content,
|
||||
'excerpt' => $slide->post_excerpt,
|
||||
'buttons' => get_post_meta( $slide->ID, '_hssm_buttons', true ) ?: array(),
|
||||
'order' => (int) get_post_meta( $slide->ID, '_hssm_order', true ),
|
||||
'background_image' => $this->get_slide_background_image( $slide->ID ),
|
||||
'schedule' => array(
|
||||
'start_date' => get_post_meta( $slide->ID, '_hssm_start_date', true ),
|
||||
'end_date' => get_post_meta( $slide->ID, '_hssm_end_date', true ),
|
||||
'auto_publish' => get_post_meta( $slide->ID, '_hssm_auto_publish', true ) === '1',
|
||||
'auto_unpublish' => get_post_meta( $slide->ID, '_hssm_auto_unpublish', true ) === '1',
|
||||
),
|
||||
'target_sites' => $this->get_slide_target_sites( $slide->ID ),
|
||||
'client' => $this->get_slide_client( $slide->ID ),
|
||||
'status' => $slide->post_status,
|
||||
'created' => $slide->post_date,
|
||||
'modified' => $slide->post_modified,
|
||||
);
|
||||
|
||||
return $slide_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slide background image data
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param int $slide_id Slide ID
|
||||
* @return array|null Background image data
|
||||
*/
|
||||
private function get_slide_background_image( $slide_id ) {
|
||||
$thumbnail_id = get_post_thumbnail_id( $slide_id );
|
||||
if ( ! $thumbnail_id ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$image_data = wp_get_attachment_image_src( $thumbnail_id, 'full' );
|
||||
if ( ! $image_data ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array(
|
||||
'id' => $thumbnail_id,
|
||||
'url' => $image_data[0],
|
||||
'width' => $image_data[1],
|
||||
'height' => $image_data[2],
|
||||
'alt' => get_post_meta( $thumbnail_id, '_wp_attachment_image_alt', true ),
|
||||
'sizes' => array(
|
||||
'full' => wp_get_attachment_image_src( $thumbnail_id, 'full' )[0],
|
||||
'large' => wp_get_attachment_image_src( $thumbnail_id, 'large' )[0],
|
||||
'medium' => wp_get_attachment_image_src( $thumbnail_id, 'medium' )[0],
|
||||
'thumbnail' => wp_get_attachment_image_src( $thumbnail_id, 'thumbnail' )[0],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slide target sites
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param int $slide_id Slide ID
|
||||
* @return array Target sites data
|
||||
*/
|
||||
private function get_slide_target_sites( $slide_id ) {
|
||||
$sites = wp_get_post_terms( $slide_id, 'hssm_site' );
|
||||
$sites_data = array();
|
||||
|
||||
if ( ! is_wp_error( $sites ) ) {
|
||||
foreach ( $sites as $site ) {
|
||||
$sites_data[] = array(
|
||||
'slug' => $site->slug,
|
||||
'name' => $site->name,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $sites_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slide client
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param int $slide_id Slide ID
|
||||
* @return array|null Client data
|
||||
*/
|
||||
private function get_slide_client( $slide_id ) {
|
||||
$clients = wp_get_post_terms( $slide_id, 'hssm_client' );
|
||||
|
||||
if ( ! is_wp_error( $clients ) && ! empty( $clients ) ) {
|
||||
$client = $clients[0];
|
||||
return array(
|
||||
'slug' => $client->slug,
|
||||
'name' => $client->name,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slide count for a site
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param int $site_term_id Site term ID
|
||||
* @return int Slide count
|
||||
*/
|
||||
private function get_site_slide_count( $site_term_id ) {
|
||||
$query = new WP_Query( array(
|
||||
'post_type' => 'hssm_slide',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => -1,
|
||||
'fields' => 'ids',
|
||||
'tax_query' => array(
|
||||
array(
|
||||
'taxonomy' => 'hssm_site',
|
||||
'field' => 'term_id',
|
||||
'terms' => $site_term_id,
|
||||
),
|
||||
),
|
||||
) );
|
||||
|
||||
return $query->found_posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate site slug parameter
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $value Site slug
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @param string $param Parameter name
|
||||
* @return bool Validation result
|
||||
*/
|
||||
public function validate_site_slug( $value, $request, $param ) {
|
||||
$companion_sites = HSSM_Main::get_companion_sites();
|
||||
$valid_sites = wp_list_pluck( $companion_sites, 'slug' );
|
||||
return in_array( $value, $valid_sites );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate date parameter
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $value Date string
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @param string $param Parameter name
|
||||
* @return bool Validation result
|
||||
*/
|
||||
public function validate_date( $value, $request, $param ) {
|
||||
return (bool) strtotime( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate limit parameter
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param int $value Limit value
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @param string $param Parameter name
|
||||
* @return bool Validation result
|
||||
*/
|
||||
public function validate_limit( $value, $request, $param ) {
|
||||
return is_numeric( $value ) && $value >= 1 && $value <= 50;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate status parameter
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $value Status value
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @param string $param Parameter name
|
||||
* @return bool Validation result
|
||||
*/
|
||||
public function validate_status( $value, $request, $param ) {
|
||||
$valid_statuses = array( 'active', 'scheduled', 'all' );
|
||||
return in_array( $value, $valid_statuses );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate slide ID parameter
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param int $value Slide ID
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @param string $param Parameter name
|
||||
* @return bool Validation result
|
||||
*/
|
||||
public function validate_slide_id( $value, $request, $param ) {
|
||||
return is_numeric( $value ) && $value > 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user