Basic settings page with configurables

This commit is contained in:
j 2025-06-18 13:47:55 +10:00
parent 1cd9fa3c29
commit ff5a382856
6 changed files with 351 additions and 2 deletions

View file

@ -0,0 +1,94 @@
# Building and releasing Wordpress plugins is pretty simple
# It's just zipping up some PHP. This doesn't contain any unit tests
# this is just zipping and shipping.
#
# Generally speaking your directory structure would be:
# .
# ├── README.md
# └── src
# └── wordpress-plugin.php
#
# With the repository name being the name of your plugin to make it easier
# to Google for. Up to you though; you can configure the source dir below.
#
# When you tag a commit and the tag stats with 'v', this workflow will
# zip and ship the Wordpress plugin to the 'releases' tab of Github or Forgejo
name: Build & Release WordPress Plugin
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: docker
container: debian:12
env:
SOURCE_DIR: "src"
steps:
- name: Prepare Build Environment
run: |
apt update && apt -y install zip unzip nodejs curl jq
- name: Checkout repo
uses: actions/checkout@v4
- name: Package plugin
run: |
# Set plugin name like this because it's easier than inline
PLUGIN_NAME=$(echo $GITHUB_REPOSITORY | awk -F'/' '{ print $2 }')
# Create a build directory to ensure that we're correctly creating
# a single child directory in the zip.
mkdir -p build
cp -r ${SOURCE_DIR} "build/${PLUGIN_NAME}"
# Zip it up for shipping
cd build
zip -r "../${PLUGIN_NAME}.zip" "${PLUGIN_NAME}"
cd -
unzip -l "${PLUGIN_NAME}.zip"
- name: Create Release if not exists
run: |
# Curl request that uses the repos token & Forgejo's built-in variables
# to create a new release based on the tag that you have pushed
#
# It doesn't care if the release exists or not.
curl -X POST "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases" \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{
"tag_name": "'"${GITHUB_REF##*/}"'",
"target_commitish": "main",
"name": "'"${GITHUB_REF##*/}"'",
"body": "Auto release",
"draft": false,
"prerelease": false
}' || true
- name: Upload Plugin Zip to Release
run: |
# Set some variables because it's cleaner than in-line
TAG_NAME="${GITHUB_REF##*/}"
REPO_NAME="$(basename $GITHUB_REPOSITORY)"
PLUGIN_NAME=$(echo $GITHUB_REPOSITORY | awk -F'/' '{ print $2 }')
# Get the release ID created in the last step
RELEASE_ID=$(curl -s \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG_NAME}" \
| jq -r '.id')
# Pushes he zip file to be shown in the "Releases" tab under this release.
curl -X POST "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets" \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-F "name=${PLUGIN_NAME}.zip" \
-F "attachment=@${PLUGIN_NAME}.zip"

View file

@ -1,3 +1,42 @@
# fwp-recaptcha
# fwp-calendar
Provides basic Google Recaptcha protections for your Wordpress blog.
Originally created for a customer, I imagine that this would help some people
wanting to avoid Wordpresses increasing "pay to use" direction.
Accepts a list of iCal URLs (without auth) and publishes to a page.
Almost entirely generated with ChatGPT. I lay no claim that I have manually
written this entire thing myself. I just need something working and fast.
## MVP
The MVP has very basic functionality. We leverage two external libraries however
have included them within the plugin:
1. [FullCalendar](https://github.com/fullcalendar/fullcalendar)
2. [ics-parser](https://github.com/u01jmg3/ics-parser)
We pull from a public iCal/ICS URL via the server. We then process and display
this information when a shortcode (`[event-calendar]`) is called.
We store a list/array of URLs to pull from, so you should be able to add a
couple.
## Usage
Just install then look in "Settings" for the "FWP Calendar" section.
You can add a simple list of ICS/iCal URLs there however they must be publicly
accessible. I tested and it works with Google calendars.
I created this for a customer who had a list of upcoming events displayed on
their website. They were manually updating the events calendar entirely through
Wordpress, which seemed clunky.
This plugin allows you to maintain a community events calendar from within your
Orgs typical public calendar. Visitors can see events spread out on a calendar
and upcoming events below.
This is good because you can provide the calendar for people to add to their
phones or import into their own calendars. Your options are endless when you
don't use shitty proprietary standards!

34
docker-compose.yaml Normal file
View file

@ -0,0 +1,34 @@
services:
db:
image: mysql:8.0
container_name: wp_test_db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
container_name: wp_test_app
depends_on:
- db
ports:
- "8080:80"
restart: unless-stopped
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DEBUG: 'true'
WORDPRESS_DEBUG_LOG: 'true'
WORDPRESS_DEBUG_DISPLAY: 'false'
volumes:
- ./src:/var/www/html/wp-content/plugins/fwp-recaptcha
volumes:
db_data:

74
src/funcs/settings.php Normal file
View file

@ -0,0 +1,74 @@
<?php
defined('ABSPATH') or exit;
// === Add FWP Settings Menu + Recaptcha Page ===
add_action('admin_menu', 'fwp_add_settings_pages');
function fwp_add_settings_pages() {
// Create top-level "FWP Settings" if not already present
if (!isset($GLOBALS['admin_page_hooks']['fwp-settings'])) {
add_menu_page(
'FWP Settings',
'FWP Settings',
'manage_options',
'fwp-settings',
'__return_null',
'dashicons-admin-generic',
80
);
}
// Add FWP Recaptcha submenu
add_submenu_page(
'fwp-settings',
'FWP reCAPTCHA',
'FWP reCAPTCHA',
'manage_options',
'fwp-recaptcha',
'fwp_render_recaptcha_settings_page'
);
remove_submenu_page('fwp-settings', 'fwp-settings');
}
// === Register Settings ===
add_action('admin_init', 'fwp_register_recaptcha_settings');
function fwp_register_recaptcha_settings() {
register_setting('fwp_recaptcha_settings_group', 'fwp_recaptcha_enabled_forms');
register_setting('fwp_recaptcha_settings_group', 'fwp_recaptcha_site_key');
register_setting('fwp_recaptcha_settings_group', 'fwp_recaptcha_secret_key');
}
// === Render Settings Page ===
function fwp_render_recaptcha_settings_page() {
$enabled = get_option('fwp_recaptcha_enabled_forms', ['login', 'register', 'comment']);
$site_key = get_option('fwp_recaptcha_site_key', '');
$secret_key = get_option('fwp_recaptcha_secret_key', '');
?>
<div class="wrap">
<h1>FWP reCAPTCHA Settings</h1>
<form method="post" action="options.php">
<?php settings_fields('fwp_recaptcha_settings_group'); ?>
<table class="form-table" role="presentation">
<tr>
<th scope="row">Enable reCAPTCHA on:</th>
<td>
<label><input type="checkbox" name="fwp_recaptcha_enabled_forms[]" value="login" <?php checked(in_array('login', $enabled)); ?>> Login Form</label><br>
<label><input type="checkbox" name="fwp_recaptcha_enabled_forms[]" value="register" <?php checked(in_array('register', $enabled)); ?>> Registration Form</label><br>
<label><input type="checkbox" name="fwp_recaptcha_enabled_forms[]" value="comment" <?php checked(in_array('comment', $enabled)); ?>> Comment Form</label>
</td>
</tr>
<tr>
<th scope="row"><label for="fwp_recaptcha_site_key">Site Key</label></th>
<td><input type="text" name="fwp_recaptcha_site_key" id="fwp_recaptcha_site_key" value="<?php echo esc_attr($site_key); ?>" class="regular-text" /></td>
</tr>
<tr>
<th scope="row"><label for="fwp_recaptcha_secret_key">Secret Key</label></th>
<td><input type="text" name="fwp_recaptcha_secret_key" id="fwp_recaptcha_secret_key" value="<?php echo esc_attr($secret_key); ?>" class="regular-text" /></td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
<?php
}

90
src/fwp-calendar.php Normal file
View file

@ -0,0 +1,90 @@
<?php
/**
* Plugin Name: Free WordPress Google Recaptcha
* Plugin URI: https://repobase.net/free-wordpress/fwp-recaptcha/
* Description: Protect your Wordpress forms with Googles Recaptcha.
* Version: 0.0.1
* Author: Jacob Brown
* License: GPL2
* Text Domain: fwp-recaptcha
*/
<?php
/**
* Plugin Name: Universal reCAPTCHA
* Description: Adds Google reCAPTCHA to login, register, comment, and other forms via hooks.
* Version: 1.0
* Author: OpenAI
* License: GPL2
*/
defined('ABSPATH') or die('No script kiddies please.');
define('URC_SITE_KEY', 'your-site-key-here');
define('URC_SECRET_KEY', 'your-secret-key-here');
// Enqueue reCAPTCHA script globally
add_action('wp_enqueue_scripts', 'urc_enqueue_recaptcha');
add_action('login_enqueue_scripts', 'urc_enqueue_recaptcha');
function urc_enqueue_recaptcha() {
wp_enqueue_script('google-recaptcha', 'https://www.google.com/recaptcha/api.js', [], null, true);
}
// Add reCAPTCHA field to login, register, and comment forms
add_action('login_form', 'urc_display_recaptcha');
add_action('register_form', 'urc_display_recaptcha');
add_action('comment_form_after_fields', 'urc_display_recaptcha');
add_action('comment_form_logged_in_after', 'urc_display_recaptcha');
function urc_display_recaptcha() {
echo '<div class="g-recaptcha" data-sitekey="' . esc_attr(URC_SITE_KEY) . '"></div>';
}
// Validate login form
add_filter('authenticate', 'urc_verify_recaptcha_on_login', 30, 3);
function urc_verify_recaptcha_on_login($user, $username, $password) {
if (!urc_is_recaptcha_valid()) {
return new WP_Error('recaptcha_invalid', __('<strong>ERROR</strong>: Please complete the reCAPTCHA.'));
}
return $user;
}
// Validate registration
add_action('registration_errors', 'urc_verify_recaptcha_on_register', 10, 3);
function urc_verify_recaptcha_on_register($errors, $sanitized_user_login, $user_email) {
if (!urc_is_recaptcha_valid()) {
$errors->add('recaptcha_invalid', __('ERROR: Please complete the reCAPTCHA.'));
}
return $errors;
}
// Validate comment form
add_filter('preprocess_comment', 'urc_verify_recaptcha_on_comment');
function urc_verify_recaptcha_on_comment($commentdata) {
if (!urc_is_recaptcha_valid()) {
wp_die(__('ERROR: Please complete the reCAPTCHA.'));
}
return $commentdata;
}
// reCAPTCHA validation helper
function urc_is_recaptcha_valid() {
if (isset($_POST['g-recaptcha-response'])) {
$response = wp_remote_post('https://www.google.com/recaptcha/api/siteverify', [
'body' => [
'secret' => URC_SECRET_KEY,
'response' => sanitize_text_field($_POST['g-recaptcha-response']),
'remoteip' => $_SERVER['REMOTE_ADDR'],
]
]);
if (!is_wp_error($response)) {
$data = json_decode(wp_remote_retrieve_body($response), true);
return isset($data['success']) && $data['success'] === true;
}
}
return false;
}

18
src/fwp-recaptcha.php Normal file
View file

@ -0,0 +1,18 @@
<?php
/**
* Plugin Name: Free WordPress Google Recaptcha
* Plugin URI: https://repobase.net/free-wordpress/fwp-recaptcha/
* Description: Protect your Wordpress forms with Googles Recaptcha.
* Version: 0.0.1
* Author: Free Wordpress
* License: GPL2
* Text Domain: fwp-recaptcha
*/
defined('ABSPATH') or exit;
// Load settings and admin menu
require_once plugin_dir_path(__FILE__) . 'funcs/settings.php';
// Your future frontend logic (hook into forms) would go here