- PHP 66.7%
- Shell 19.8%
- JavaScript 13.5%
|
All checks were successful
release / build_release (release) Successful in 1m19s
|
||
|---|---|---|
| .forgejo/workflows | ||
| assets | ||
| wp-camera-snapshots | ||
| .gitignore | ||
| build-plugin.sh | ||
| BUILD.md | ||
| README.md | ||
| TEST.md | ||
| test.sh | ||
WP Camera Snapshots
WP Camera Snapshots is a WordPress plugin that accepts periodic snapshot uploads from network cameras via the REST API and displays the latest image on the frontend via shortcode and Gutenberg block. Images are stored on the filesystem inside the plugin’s storage directory and are rendered on the frontend as inline base64‑encoded images (data URIs) rather than direct file URLs. This avoids server‑side errors caused by webserver rules that block access to plugin directories. The display can fall back to a global or per‑camera image (or the bundled offline image) when the latest snapshot is unavailable or stale.
1. Requirements
- WordPress 6.9 or newer
- PHP 8.1 or newer
- Node.js + npm (for building the Gutenberg block in development)
2. Building the plugin
For detailed build instructions, see BUILD.md. In short:
cd /path/to/wp_camera_plugin
chmod +x build-plugin.sh
./build-plugin.sh # debug build → wp-camera-snapshots-dev.zip
# For a release build (e.g. 1.0.0):
export RELEASE_VERSION=1.0.0
./build-plugin.sh # release build → wp-camera-snapshots-1.0.0.zip
This will:
- Install the JS build tooling in
wp-camera-snapshots/if missing - Build the block assets into
wp-camera-snapshots/build/ - Copy
assets/camera_offline.pngintowp-camera-snapshots/assets/ - Compile translations (
.po→.mo) usingmsgfmt - Update plugin metadata (header,
WPCS_VERSION, andopenapi.json) to the chosen version (0.0.0-devfor debug builds orRELEASE_VERSIONfor releases) - Create
wp-camera-snapshots-dev.ziporwp-camera-snapshots-<version>.zipin the project root, ready to upload
3. Installing in WordPress
- Log in to your WordPress admin.
- Navigate to Plugins → Add New → Upload Plugin.
- Upload
wp-camera-snapshots.zipand click Install Now. - Click Activate Plugin.
You can re‑upload a new zip with the same folder name to replace the existing plugin (WordPress will show a “replace current with uploaded” prompt).
4. Configuring cameras
- In the WP admin, go to Settings → Camera Snapshots.
- Global fallback image:
- Click Select image to pick a global fallback from the Media Library.
- A small preview shows the current selection.
- Cameras table:
- Camera ID: a unique identifier (e.g.
camera_entrance). This is used in the REST endpoint URL and shortcode/block attributes. - Filename (optional): base name for the snapshot file. When left empty,
the camera ID is used as the base name. The plugin will automatically look
for
base.jpg,base.jpegorbase.pngin its storage directory. - Fallback Attachment:
- Click Select image to choose a per‑camera fallback from the Media Library.
- The global fallback is used when no per‑camera fallback is set.
- Camera ID: a unique identifier (e.g.
The plugin also ships a bundled offline image (assets/camera_offline.png)
which is used as an ultimate fallback when no valid attachment fallback is
available.
4.1 Rate limiting
Under Rate limiting in the settings you can configure a global rate limit window per camera:
- Rate limit window per camera (seconds, 0 = disabled):
- Default is
60seconds. - If a camera sends snapshots more frequently than this window, additional
requests will be rejected with HTTP
429 Too Many Requests. - Set to
0to disable rate limiting entirely.
- Default is
5. Data flow overview
The high‑level data flow from camera upload to browser rendering is illustrated in the following diagram:
6. Uploading snapshots (for camera developers)
-
REST endpoint:
POST /wp-json/wp-camera-snapshots/v1/cameras/{camera_id} -
Authentication:
- Use a dedicated WordPress user with an Application Password.
- Send HTTP Basic Auth over HTTPS.
-
Request:
- Raw binary body (
image/jpegorimage/png). {camera_id}must match a configured camera ID in the settings.
- Raw binary body (
-
Responses (examples):
201 Created: snapshot stored successfully.400 Bad Request: missing/invalid payload.401 Unauthorized: invalid credentials.404 Not Found: unknowncamera_id.429 Too Many Requests: rate limit exceeded for this camera.
6.1 Required user role / capability
The upload endpoint uses a permission check:
- The authenticated user must have the
upload_filescapability. - In a default WordPress installation this means:
- Allowed: Author, Editor, Administrator (and any custom role that can upload files).
- Not allowed: Subscriber, Contributor.
For production use, it is recommended to create a dedicated low‑privilege user
role with only the capabilities needed for this plugin (including upload_files)
and use that account for Application Passwords.
See wp-camera-snapshots/openapi.json for a machine‑readable API description.
7. Displaying snapshots
7.1 Shortcode
Use the shortcode in posts, pages, or widgets:
[camera id="camera_entrance" refresh="600" show_fallback="0"]
With automatic frontend updates enabled:
[camera id="camera_entrance" refresh="60" auto_update="1"]
id(required): camera ID as configured in the settings.refresh(optional): freshness window in seconds (default 600).show_fallback(optional): reserved for UI variations; currently affects only internal state, not markup.auto_update(optional, defaultfalse): when truthy (1,true,yes, etc.), the snapshot is automatically refreshed on the frontend without reloading the entire page.auto_update_interval(optional, default0): interval in seconds for automatic frontend refreshes. When set to0or omitted whileauto_updateis enabled, the plugin reuses therefreshvalue as the auto‑update interval.
What is the freshness window?
Each camera snapshot is stored as a single image file on disk. The plugin checks how old this file is using its modification time:
- If the file is younger than the freshness window, it is considered “fresh” and will be shown.
- If the file is older than the freshness window, the plugin assumes the camera may be offline or not updating and will show the fallback image instead (per‑camera fallback, then global fallback, then the bundled offline image).
Examples:
refresh="60"→ If no new snapshot arrives within 60 seconds, the frontend will switch to the fallback image.refresh="0"or a very large value effectively disables staleness detection and will keep showing the last snapshot until it is replaced.
A short freshness window makes stale cameras visible quickly but may show the fallback image more often. A longer window is more tolerant of irregular uploads.
7.2 Gutenberg block
In the block editor:
- Add the “Camera Snapshot” block.
- In the block sidebar:
- Set Camera ID to the configured camera ID.
- Optionally adjust Refresh interval (seconds) (same meaning as the
shortcode
refreshattribute). - Optionally enable Automatically update image to refresh the snapshot on an interval without reloading the page.
- Optionally set Auto‑update interval (seconds). When this is
0, the block reuses the Refresh interval (seconds) as the auto‑update interval. - Optionally enable Show fallback indicator when stale (used internally).
The block uses the same rendering logic as the shortcode, including freshness and fallback behavior.
8. Uninstall behavior
When the plugin is uninstalled via the WordPress Plugins screen:
- The
wpcs_settingsoption and storage configuration options are removed. - The snapshot storage directory (either under the plugin or under
uploads/, depending on environment) and all stored snapshot files are deleted. - Media Library attachments used as fallbacks are not deleted.
9. How images are served (base64 data URIs)
On the frontend the plugin always embeds camera snapshots and fallback images as
base64‑encoded data: URLs in the <img src="..."> attribute. This has two
important consequences:
- No direct HTTP access to the snapshot files is required. Even if the
webserver forbids access to
wp-content/plugins/wp-camera-snapshots/storage/, the page still renders correctly because the browser only sees an inline image. - Fewer server‑side configuration surprises: you do not need to adjust
.htaccessor webserver rules to allow public access to the storage directory; only PHP needs read access to the files.
The freshness window and fallback logic described above apply exactly the same way; only the transport from disk to browser changes (file → base64 in HTML).