complete refactor

This commit is contained in:
2025-05-23 21:57:53 +01:00
parent 6517f0dc39
commit 64ed76913a
2 changed files with 154 additions and 37 deletions

3
door-status-config.php Normal file
View File

@@ -0,0 +1,3 @@
define( 'DSI_API_URL', 'https://nodered.jfig.net/api/v1/door-open' );
define( 'DSI_CACHE_KEY', 'dsi_door_open_status' );
define( 'DSI_CACHE_TTL', 10 );

View File

@@ -1,48 +1,162 @@
<?php <?php
/** /**
* Plugin Name: WP API Consumer * Plugin Name: Door Status Indicator
* Plugin URI: https://gitea.alluna.pt/jfig/wp-api-consumer * Plugin URI: https://gitea.alluna.pt/jfig/wp-api-consumer
* Description: Shows the live value of https://nodered.jfig.net/api/v1/door-open in a menu item or via shortcode. * Description: Lightweight, dependencyfree plugin that polls <https://nodered.jfig.net/api/v1/door-open>, caches the status for a few seconds, and shows a realtime door open/closed indicator (🟢/🔴) via [door_status] shortcode and the Admin Bar.
* Version: 1.0 * Version: 1.1.0
* License: GPL-2.0+ * Author: Joao Figueiredo (ChatGPT helper)
* Author URI: https://jfig.net
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: door-status-indicator
*/ */
defined( 'ABSPATH' ) || exit; if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/*
|--------------------------------------------------------------------------
| Configuration
|--------------------------------------------------------------------------
| Place environmentspecific constants inside door-status-config.php.
| They will be loaded automatically. If the file is missing we fall back to
| bundled defaults so the plugin keeps working outofthebox.
*/
$config_file = plugin_dir_path( __FILE__ ) . 'door-status-config.php';
if ( file_exists( $config_file ) ) {
require_once $config_file;
} else {
// Fallback defaults safe to adjust directly here if you prefer.
define( 'DSI_API_URL', 'https://nodered.jfig.net/api/v1/door-open' );
define( 'DSI_CACHE_KEY', 'dsi_door_open_status' );
define( 'DSI_CACHE_TTL', 10 );
}
/*
|--------------------------------------------------------------------------
| Core fetch & cache
|--------------------------------------------------------------------------
*/
/** /**
* Fetch the Boolean once every 10 s (adjust TTL to taste). * Retrieves the dooropen status (boolean) with transient caching.
*
* @return bool True if open, false if closed.
*/ */
function ds_get_state() { function dsi_get_status() : bool {
$state = get_transient( 'ds_state' ); $cached = get_transient( DSI_CACHE_KEY );
if ( false !== $cached ) {
return (bool) $cached;
}
if ( false === $state ) { $response = wp_remote_get( DSI_API_URL, [
$r = wp_remote_get( 'https://nodered.jfig.net/api/v1/door-open', [ 'timeout' => 4 ] ); // 4 s hard stop 'timeout' => 3,
$state = is_wp_error( $r ) ? '' : trim( wp_remote_retrieve_body( $r ) ); 'user-agent' => 'DoorStatusIndicator/1.1 (+https://wordpress.org/)',
set_transient( 'ds_state', $state, 10 ); ] );
if ( is_wp_error( $response ) ) {
// On error, assume closed and set a short transient to avoid hammering.
set_transient( DSI_CACHE_KEY, false, DSI_CACHE_TTL );
return false;
} }
return $state;
$body = wp_remote_retrieve_body( $response );
$decoded = json_decode( $body, true );
$status = false;
if ( is_bool( $decoded ) ) {
$status = $decoded;
} elseif ( is_array( $decoded ) && isset( $decoded['open'] ) ) {
$status = (bool) $decoded['open'];
} }
set_transient( DSI_CACHE_KEY, $status, DSI_CACHE_TTL );
return $status;
}
/*
|--------------------------------------------------------------------------
| Shortcode [door_status]
|--------------------------------------------------------------------------
*/
/** /**
* Returns a coloured dot (🟢 / 🔴) or ⚪ if the API is unreachable. * Outputs a 🟢 or 🔴 indicator reflecting current door status.
* Usage: [door_status]
*
* @return string HTML span with coloured emoji.
*/ */
function ds_render() { function dsi_shortcode() : string {
$s = strtolower( ds_get_state() ); $open = dsi_get_status();
if ( 'true' === $s ) return '<span class="door-state door-open" aria-label="door open">🟢</span>'; $emoji = $open ? '🟢' : '🔴';
if ( 'false' === $s ) return '<span class="door-state door-closed" aria-label="door closed">🔴</span>';
return '<span class="door-state door-unknown" aria-label="status unknown">⚪</span>'; return sprintf(
'<span class="door-status-indicator" aria-label="Door is %s">%s</span>',
$open ? 'open' : 'closed',
$emoji
);
} }
add_shortcode( 'door_state', 'ds_render' ); // [door_state] add_shortcode( 'door_status', 'dsi_shortcode' );
/*
|--------------------------------------------------------------------------
| Admin Bar indicator
|--------------------------------------------------------------------------
*/
/** /**
* Automatically append the indicator to a menu (optional). * Adds a live indicator to the WordPress Admin Bar (front and backend).
* Replace 'primary' with your themes menu slug if different. *
* @param WP_Admin_Bar $wp_admin_bar The admin bar instance.
*/ */
function ds_menu_item( $items, $args ) { function dsi_admin_bar( WP_Admin_Bar $wp_admin_bar ) : void {
if ( 'primary' === $args->theme_location ) { if ( ! current_user_can( 'read' ) ) {
$items .= '<li class="menu-item menu-item-door-state">' . ds_render() . '</li>'; return; // Only show to loggedin users who can read.
} }
return $items;
}
add_filter( 'wp_nav_menu_items', 'ds_menu_item', 10, 2 );
$open = dsi_get_status();
$emoji = $open ? '🟢' : '🔴';
$text = $open ? __( 'Door Open', 'door-status-indicator' ) : __( 'Door Closed', 'door-status-indicator' );
$wp_admin_bar->add_node( [
'id' => 'door-status-indicator',
'title' => sprintf( '%s %s', $emoji, $text ),
'href' => '#',
'meta' => [
'title' => $text,
],
] );
}
add_action( 'admin_bar_menu', 'dsi_admin_bar', 1000 );
/*
|--------------------------------------------------------------------------
| Frontend inline CSS
|--------------------------------------------------------------------------
*/
function dsi_enqueue_assets() : void {
if ( is_admin() ) {
return;
}
$css = '.door-status-indicator{font-size:1.2em;line-height:1}';
wp_add_inline_style( 'wp-block-library', $css );
}
add_action( 'wp_enqueue_scripts', 'dsi_enqueue_assets' );
/*
|--------------------------------------------------------------------------
| WPCLI command (optional)
|--------------------------------------------------------------------------
*/
if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::add_command( 'door-status', function() {
$status = dsi_get_status() ? 'open 🟢' : 'closed 🔴';
WP_CLI::success( "Door is $status" );
} );
}
// End of file