171 lines
5.5 KiB
PHP
171 lines
5.5 KiB
PHP
<?php
|
||
/**
|
||
* Plugin Name: WordPress SpaceAPI Consumer
|
||
* Plugin Slug: wp-spaceapi-consumer
|
||
* Plugin URI: https://gitea.alluna.pt/jfig/wp-spaceapi-consumer
|
||
* Description: WordPress plugin to consume a SpaceAPI endpoint and indicate if the Space is Open or Closed
|
||
* Version: 0.3.0
|
||
* Author: Joao Figueiredo, LCD Porto Team, ChatGPT o3
|
||
* Author URI: https://lcdporto.org
|
||
* License: MIT
|
||
* License URI: https://gitea.alluna.pt/jfig/wp-spaceapi-consumer/src/branch/dev/LICENSE
|
||
* Text Domain: wp-spaceapi-consumer
|
||
*/
|
||
|
||
if ( ! defined( 'ABSPATH' ) ) {
|
||
exit; // Exit if accessed directly.
|
||
}
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Configuration
|
||
|--------------------------------------------------------------------------
|
||
| Constants are expected in wp-spaceapi-consumer-config.php located in the same
|
||
| directory. If that file is missing, sane defaults are used so the plugin
|
||
| still works out‑of‑the‑box.
|
||
*/
|
||
|
||
$config_file = plugin_dir_path( __FILE__ ) . 'wp-spaceapi-consumer-config.php';
|
||
if ( file_exists( $config_file ) ) {
|
||
require_once $config_file;
|
||
}
|
||
|
||
// Fallback defaults (only if not already defined by the config file).
|
||
! defined( 'SSI_API_URL' ) && define( 'SSI_API_URL', 'https://lcdporto.org/api/spaceapi' );
|
||
! defined( 'SSI_CACHE_KEY' ) && define( 'SSI_CACHE_KEY', 'ssi_space_api_status' );
|
||
! defined( 'SSI_CACHE_TTL' ) && define( 'SSI_CACHE_TTL', 10 ); // seconds
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Core – fetch & cache
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
/**
|
||
* Retrieves space open status (boolean) with transient caching.
|
||
*
|
||
* Supported JSON payloads (any case):
|
||
* – true / false (bare boolean)
|
||
* – {"state": {"open": true}} (SpaceAPI standard)
|
||
*
|
||
* @return bool True if open, false if closed (or on error).
|
||
*/
|
||
function ssi_get_status() : bool {
|
||
$cached = get_transient( SSI_CACHE_KEY );
|
||
if ( false !== $cached ) {
|
||
return (bool) $cached;
|
||
}
|
||
|
||
// Get plugin data for dynamic user agent
|
||
$plugin_data = get_file_data( __FILE__, array(
|
||
'Version' => 'Version',
|
||
'TextDomain' => 'Text Domain'
|
||
), 'plugin' );
|
||
|
||
$response = wp_remote_get( SSI_API_URL, [
|
||
'timeout' => 3,
|
||
'user-agent' => $plugin_data['TextDomain'] . '/' . $plugin_data['Version'] . ' (+https://wordpress.org/)',
|
||
] );
|
||
|
||
if ( is_wp_error( $response ) ) {
|
||
set_transient( SSI_CACHE_KEY, false, SSI_CACHE_TTL );
|
||
return false;
|
||
}
|
||
|
||
$body = wp_remote_retrieve_body( $response );
|
||
$decoded = json_decode( $body, true );
|
||
$status = false; // default to closed
|
||
|
||
if ( is_bool( $decoded ) ) {
|
||
$status = $decoded;
|
||
} elseif ( is_array( $decoded ) ) {
|
||
// SpaceAPI standard format - state.open
|
||
if ( isset( $decoded['state']['open'] ) ) {
|
||
$status = (bool) $decoded['state']['open'];
|
||
}
|
||
}
|
||
|
||
set_transient( SSI_CACHE_KEY, $status, SSI_CACHE_TTL );
|
||
return $status;
|
||
}
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Shortcode [door_status]
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
function ssi_shortcode() : string {
|
||
$open = ssi_get_status();
|
||
$emoji = $open ? '<div class="space-status-indicator open">🟢 Open</div>' : '<div class="space-status-indicator closed">🔴 Closed</div>';
|
||
|
||
return sprintf(
|
||
'<span class="space-status-indicator" aria-label="Space is %s">%s</span>',
|
||
$open ? 'open' : 'closed',
|
||
$emoji
|
||
);
|
||
}
|
||
add_shortcode( 'space_status', 'ssi_shortcode' );
|
||
// Keep the old shortcode for backward compatibility
|
||
add_shortcode( 'door_status', 'ssi_shortcode' );
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Admin Bar indicator
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
function ssi_admin_bar( WP_Admin_Bar $bar ) : void {
|
||
if ( ! current_user_can( 'read' ) ) {
|
||
return; // Logged‑in users only.
|
||
}
|
||
|
||
$open = ssi_get_status();
|
||
$emoji = $open ? '🟢' : '🔴';
|
||
$text = $open ? __( 'Space Open', 'wp-spaceapi-consumer' ) : __( 'Space Closed', 'wp-spaceapi-consumer' );
|
||
|
||
$bar->add_node( [
|
||
'id' => 'space-status-indicator',
|
||
'title' => "$emoji $text",
|
||
'href' => '#',
|
||
'meta' => [ 'title' => $text ],
|
||
] );
|
||
}
|
||
add_action( 'admin_bar_menu', 'ssi_admin_bar', 1000 );
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| Front‑end inline CSS (kept minimal)
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
/**
|
||
* Front-end + admin-bar styles for the indicator.
|
||
*/
|
||
function ssi_enqueue_assets() : void {
|
||
// register & enqueue the standalone CSS file
|
||
wp_enqueue_style(
|
||
'space-status-indicator',
|
||
plugins_url( 'wp-spaceapi-consumer-style.css', __FILE__ ),
|
||
[], // no dependencies
|
||
'1.0.0' // file version
|
||
);
|
||
}
|
||
add_action( 'wp_enqueue_scripts', 'ssi_enqueue_assets' );
|
||
add_action( 'admin_enqueue_scripts', 'ssi_enqueue_assets' ); // so the Admin Bar icon also gets styled
|
||
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| WP‑CLI command (optional)
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
if ( defined( 'WP_CLI' ) && WP_CLI ) {
|
||
WP_CLI::add_command( 'space-status', function() {
|
||
WP_CLI::success( ssi_get_status() ? 'Space is open 🟢' : 'Space is closed 🔴' );
|
||
} );
|
||
}
|
||
|
||
// End of file
|