Compare commits

...

21 Commits

Author SHA1 Message Date
05c4e67266 Merge pull request '001-gutenberg-block' (#2) from 001-gutenberg-block into dev
Reviewed-on: #2
2025-06-14 00:10:17 +00:00
5bd7dcd9d2 change Block icon to building 2025-06-14 01:02:38 +01:00
88b145d6b3 change Block icon to door 2025-06-14 00:51:49 +01:00
b21a0f03aa fix 1 2025-06-14 00:37:12 +01:00
55c20df3b5 first try 2025-06-13 23:36:21 +01:00
0ed97819fe improve readme 2025-06-02 02:15:42 +01:00
6fa42e8f45 remove non ASCII chars 2025-06-02 00:44:43 +01:00
42345c47b9 major refactor, numenculature change
remove mentions to "door" status, to space
2025-06-02 00:17:55 +01:00
f0f2814d35 make user agent dynamic with changes to plugin's Text Domainand Version 2025-06-01 19:19:36 +01:00
f913cb1f6d change API to LCD Porto' s SpaceAPI 2025-06-01 19:12:13 +01:00
754738eebd adapt WordPress plugin header fields to refles project name change 2025-06-01 19:09:05 +01:00
f52a1a60e3 chage os CSS style file to reflct new project name 2025-06-01 18:52:45 +01:00
7bdb9df5f4 config file name change to reflect new project name 2025-06-01 18:49:39 +01:00
310cc2a009 File name change to match project renaming 2025-06-01 18:45:27 +01:00
a1e856c008 project renaming 2025-06-01 18:44:06 +01:00
bfca0c8fa4 better look 2025-05-23 23:15:30 +01:00
e6ff012774 better look 2025-05-23 23:15:15 +01:00
b979b0f938 better CSS 2025-05-23 23:10:39 +01:00
306f368ae2 removed balls 2025-05-23 22:59:37 +01:00
d95e013301 add support for CSS 2025-05-23 22:58:41 +01:00
279f717973 added <div> tags on short code 2025-05-23 22:48:08 +01:00
16 changed files with 330 additions and 162 deletions

6
.gitignore vendored
View File

@@ -47,3 +47,9 @@ wp-config.php
# Note: If you wish to whitelist themes,
# uncomment the next line
#/wp-content/themes
# ---> Node.js
/node_modules/
/package-lock.json

View File

@@ -1,3 +1,24 @@
# wp-api-consumer
# WordPress SpaceAPI Consumer
Small WprdPress plugin to consume an API
# wp-spaceapi-consumer
Small WordPress plugin to consume an SpaceAPI endpoint and indicate on the WordPress website if the Space is Open or Closed
## Usage
### WordPress Editor Block (Gutenberg)
You can use the `Space Status` block in the WordPress editor to display the status of the SpaceAPI endpoint.
### Shortcode
You can use the shortcode `[space_status]` to display the status of the SpaceAPI endpoint on your WordPress site.
### Widget
You can also use the widget `SpaceAPI Status` to display the status of the SpaceAPI endpoint in your WordPress sidebar or footer.
## Changes
### 0.4.x
- Added WordPress Editor Block (Gutenberg) support

21
blocks-register.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
return;
}
function ssi_register_space_status_block() : void {
$asset_path = plugin_dir_path( __FILE__ ) . 'build/space-status';
register_block_type( $asset_path, [
'render_callback' => 'ssi_render_block',
] );
}
add_action( 'init', 'ssi_register_space_status_block' );
/**
* Serverside markup for the block.
*/
function ssi_render_block( array $attributes, string $content ) : string {
// Reuse existing helper & CSS class logic.
return ssi_shortcode();
}

View File

@@ -0,0 +1,15 @@
{
"apiVersion": 3,
"name": "wp-spaceapi-consumer/space-status",
"title": "Space Status",
"description": "Show whether the space is open or closed (SpaceAPI consumer).",
"category": "widgets",
"icon": "building",
"textdomain": "wp-spaceapi-consumer",
"style": "file:./style.css",
"editorStyle": "file:./editor.css",
"editorScript": "file:./index.js",
"supports": {
"html": false
}
}

View File

@@ -0,0 +1 @@
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-blocks', 'wp-i18n', 'wp-server-side-render'), 'version' => 'e81eff0b8644d0be4dac');

View File

@@ -0,0 +1 @@
(()=>{"use strict";var e={n:r=>{var s=r&&r.__esModule?()=>r.default:()=>r;return e.d(s,{a:s}),s},d:(r,s)=>{for(var t in s)e.o(s,t)&&!e.o(r,t)&&Object.defineProperty(r,t,{enumerable:!0,get:s[t]})},o:(e,r)=>Object.prototype.hasOwnProperty.call(e,r)};window.wp.i18n;const r=window.wp.blocks,s=window.wp.serverSideRender;var t=e.n(s);const o=window.ReactJSXRuntime;(0,r.registerBlockType)("wp-spaceapi-consumer/space-status",{edit:()=>(0,o.jsx)(t(),{block:"wp-spaceapi-consumer/space-status"}),save:()=>null})})();

View File

@@ -1,5 +0,0 @@
<?php
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 );

15
package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "wp-spaceapi-consumer",
"version": "0.0.0-private",
"private": true,
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start"
},
"devDependencies": {
"@wordpress/scripts": "^30.18.0"
},
"engines": {
"node": ">=18.0.0"
}
}

View File

@@ -0,0 +1,13 @@
{
"apiVersion": 3,
"name": "wp-spaceapi-consumer/space-status",
"title": "Space Status",
"description": "Show whether the space is open or closed (SpaceAPI consumer).",
"category": "widgets",
"icon": "building",
"textdomain": "wp-spaceapi-consumer",
"style": "file:./style.css",
"editorStyle": "file:./editor.css",
"editorScript": "file:./index.js",
"supports": { "html": false }
}

View File

@@ -0,0 +1,7 @@
/* Editor-only: make the pill obvious & easy to select */
.wp-block-wp-spaceapi-consumer-space-status {
display: inline-block;
padding: 4px 8px;
border: 1px dashed var(--wp-admin-theme-color, #007cba);
border-radius: 9999px;
}

12
src/space-status/index.js Normal file
View File

@@ -0,0 +1,12 @@
import { __ } from '@wordpress/i18n';
import { registerBlockType } from '@wordpress/blocks';
import ServerSideRender from '@wordpress/server-side-render';
registerBlockType( 'wp-spaceapi-consumer/space-status', {
edit: () => (
<ServerSideRender
block="wp-spaceapi-consumer/space-status"
/>
),
save: () => null, // dynamic block — markup comes from PHP
} );

View File

@@ -0,0 +1 @@
@import url('../../wp-spaceapi-consumer-style.css');

View File

@@ -1,155 +0,0 @@
<?php
/**
* Plugin Name: Door Status Indicator
* Plugin URI: https://example.com/
* Description: Lightweight, dependencyfree plugin that polls a JSON endpoint (default: https://nodered.jfig.net/api/v1/door-open), caches the value for a few seconds, and shows a realtime door open/closed indicator (🟢/🔴) via the [door_status] shortcode and the Admin Bar.
* Version: 1.1.1
* Author: J (ChatGPT helper)
* Author URI: https://example.com/
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: door-status-indicator
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/*
|--------------------------------------------------------------------------
| Configuration
|--------------------------------------------------------------------------
| Constants are expected in door-status-config.php located in the same
| directory. If that file is missing, sane defaults are used so the plugin
| still works outofthebox.
*/
$config_file = plugin_dir_path( __FILE__ ) . 'door-status-config.php';
if ( file_exists( $config_file ) ) {
require_once $config_file;
}
// Fallback defaults (only if not already defined by the config file).
! defined( 'DSI_API_URL' ) && define( 'DSI_API_URL', 'https://nodered.jfig.net/api/v1/door-open' );
! defined( 'DSI_CACHE_KEY' ) && define( 'DSI_CACHE_KEY', 'dsi_door_open_status' );
! defined( 'DSI_CACHE_TTL' ) && define( 'DSI_CACHE_TTL', 10 ); // seconds
/*
|--------------------------------------------------------------------------
| Core fetch & cache
|--------------------------------------------------------------------------
*/
/**
* Retrieves dooropen status (boolean) with transient caching.
*
* Supported JSON payloads (any case):
* true / false (bare boolean)
* {"open": true}
* {"doorOpen": true}
*
* @return bool True if open, false if closed (or on error).
*/
function dsi_get_status() : bool {
$cached = get_transient( DSI_CACHE_KEY );
if ( false !== $cached ) {
return (bool) $cached;
}
$response = wp_remote_get( DSI_API_URL, [
'timeout' => 3,
'user-agent' => 'DoorStatusIndicator/1.1.1 (+https://wordpress.org/)',
] );
if ( is_wp_error( $response ) ) {
set_transient( DSI_CACHE_KEY, false, DSI_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 ) ) {
if ( isset( $decoded['open'] ) ) {
$status = (bool) $decoded['open'];
} elseif ( isset( $decoded['doorOpen'] ) ) {
$status = (bool) $decoded['doorOpen'];
}
}
set_transient( DSI_CACHE_KEY, $status, DSI_CACHE_TTL );
return $status;
}
/*
|--------------------------------------------------------------------------
| Shortcode [door_status]
|--------------------------------------------------------------------------
*/
function dsi_shortcode() : string {
$open = dsi_get_status();
$emoji = $open ? '🟢 Open' : '🔴 Closed';
return sprintf(
'<span class="door-status-indicator" aria-label="Door is %s">%s</span>',
$open ? 'open' : 'closed',
$emoji
);
}
add_shortcode( 'door_status', 'dsi_shortcode' );
/*
|--------------------------------------------------------------------------
| Admin Bar indicator
|--------------------------------------------------------------------------
*/
function dsi_admin_bar( WP_Admin_Bar $bar ) : void {
if ( ! current_user_can( 'read' ) ) {
return; // Loggedin users only.
}
$open = dsi_get_status();
$emoji = $open ? '🟢' : '🔴';
$text = $open ? __( 'Door Open', 'door-status-indicator' ) : __( 'Door Closed', 'door-status-indicator' );
$bar->add_node( [
'id' => 'door-status-indicator',
'title' => "$emoji $text",
'href' => '#',
'meta' => [ 'title' => $text ],
] );
}
add_action( 'admin_bar_menu', 'dsi_admin_bar', 1000 );
/*
|--------------------------------------------------------------------------
| Frontend inline CSS (kept minimal)
|--------------------------------------------------------------------------
*/
function dsi_enqueue_assets() : void {
if ( is_admin() ) {
return; // Frontend only.
}
wp_add_inline_style( 'wp-block-library', '.door-status-indicator{font-size:1.2em;line-height:1}' );
}
add_action( 'wp_enqueue_scripts', 'dsi_enqueue_assets' );
/*
|--------------------------------------------------------------------------
| WPCLI command (optional)
|--------------------------------------------------------------------------
*/
if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::add_command( 'door-status', function() {
WP_CLI::success( dsi_get_status() ? 'Door is open 🟢' : 'Door is closed 🔴' );
} );
}
// End of file

View File

@@ -0,0 +1,5 @@
<?php
define( 'SSI_API_URL', 'https://lcdporto.org/api/spaceapi' );
define( 'SSI_CACHE_KEY', 'ssi_space_api_status' );
define( 'SSI_CACHE_TTL', 10 );

View File

@@ -0,0 +1,34 @@
/* space-status.css - styles the indicator as a pill-shaped button */
.space-status-indicator {
display:inline-flex;
align-items:center;
gap:0.4em;
padding:0.25em 0.75em;
border-radius:1em; /* fully-rounded corners */
font-size:0.95em;
font-weight:600;
line-height:1;
border:1px solid transparent;
user-select:none;
transition:filter .15s ease-in-out;
}
/* Open = soft green background + dark green text */
.space-status-indicator.open {
background:#e7f9ec;
color:#1e7a34;
}
/* Closed = soft red background + dark red text */
.space-status-indicator.closed {
background:#fdeeee;
color:#c03c3c;
}
/* (Optional) slight hover effect */
.space-status-indicator:hover,
.space-status-indicator:focus {
filter:brightness(1.05);
outline:none;
}

176
wp-spaceapi-consumer.php Normal file
View File

@@ -0,0 +1,176 @@
<?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.4.2
* 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 🔴' );
} );
}
// Gutenberg block support (dynamic Space Status block)
if ( function_exists( 'register_block_type' ) ) {
require_once plugin_dir_path( __FILE__ ) . 'blocks-register.php';
}
// End of file