latest changes

This commit is contained in:
2025-06-17 08:01:10 -07:00
parent edcad561a5
commit 4c48d7ccbd
50 changed files with 1735 additions and 195 deletions

View File

@@ -4,7 +4,7 @@
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../open-function-computers-llc/rad-theme-engine/bin/getIcon)
* This file includes the referenced bin path (../open-function-computers-llc/rad-theme-engine/bin/rad)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
@@ -112,8 +112,8 @@ if (PHP_VERSION_ID < 80000) {
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/open-function-computers-llc/rad-theme-engine/bin/getIcon');
return include("phpvfscomposer://" . __DIR__ . '/..'.'/open-function-computers-llc/rad-theme-engine/bin/rad');
}
}
return include __DIR__ . '/..'.'/open-function-computers-llc/rad-theme-engine/bin/getIcon';
return include __DIR__ . '/..'.'/open-function-computers-llc/rad-theme-engine/bin/rad';

View File

@@ -54,30 +54,30 @@
},
{
"name": "open-function-computers-llc/rad-theme-engine",
"version": "v1.0.34",
"version_normalized": "1.0.34.0",
"version": "v1.0.38",
"version_normalized": "1.0.38.0",
"source": {
"type": "git",
"url": "https://github.com/open-function-computers-llc/rad-theme-engine.git",
"reference": "c0b814bdd0ee1f093a051ed2e78efdf8c1f4f94e"
"reference": "90a351370bbd5a92a2c68c226a2c0cf3f97ce8f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/open-function-computers-llc/rad-theme-engine/zipball/c0b814bdd0ee1f093a051ed2e78efdf8c1f4f94e",
"reference": "c0b814bdd0ee1f093a051ed2e78efdf8c1f4f94e",
"url": "https://api.github.com/repos/open-function-computers-llc/rad-theme-engine/zipball/90a351370bbd5a92a2c68c226a2c0cf3f97ce8f4",
"reference": "90a351370bbd5a92a2c68c226a2c0cf3f97ce8f4",
"shasum": ""
},
"require": {
"jjgrainger/posttypes": "^2.1",
"php": ">=7.4",
"php": ">=8.1",
"salesforce/handlebars-php": "^2.3"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
},
"time": "2025-05-20T21:03:45+00:00",
"time": "2025-06-13T18:23:21+00:00",
"bin": [
"bin/getIcon"
"bin/rad"
],
"type": "library",
"installation-source": "dist",
@@ -98,7 +98,7 @@
],
"support": {
"issues": "https://github.com/open-function-computers-llc/rad-theme-engine/issues",
"source": "https://github.com/open-function-computers-llc/rad-theme-engine/tree/v1.0.34"
"source": "https://github.com/open-function-computers-llc/rad-theme-engine/tree/v1.0.38"
},
"install-path": "../open-function-computers-llc/rad-theme-engine"
},

View File

@@ -3,7 +3,7 @@
'name' => 'open-function-computers-llc/wp-theme',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => 'c074a5ef18d6702ae4abe09fa1289fc93726117d',
'reference' => 'edcad561a551ed7689bc2ae7fb39e1cde81aba2e',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -20,9 +20,9 @@
'dev_requirement' => false,
),
'open-function-computers-llc/rad-theme-engine' => array(
'pretty_version' => 'v1.0.34',
'version' => '1.0.34.0',
'reference' => 'c0b814bdd0ee1f093a051ed2e78efdf8c1f4f94e',
'pretty_version' => 'v1.0.38',
'version' => '1.0.38.0',
'reference' => '90a351370bbd5a92a2c68c226a2c0cf3f97ce8f4',
'type' => 'library',
'install_path' => __DIR__ . '/../open-function-computers-llc/rad-theme-engine',
'aliases' => array(),
@@ -31,7 +31,7 @@
'open-function-computers-llc/wp-theme' => array(
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => 'c074a5ef18d6702ae4abe09fa1289fc93726117d',
'reference' => 'edcad561a551ed7689bc2ae7fb39e1cde81aba2e',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),

View File

@@ -4,8 +4,8 @@
$issues = array();
if (!(PHP_VERSION_ID >= 70400)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
if (!(PHP_VERSION_ID >= 80100)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {

View File

@@ -1,37 +0,0 @@
#!/usr/bin/env php
<?php
$autoloadPaths = [
__DIR__ . '/../../../autoload.php', // typical path when symlinked in vendor/bin
__DIR__ . '/../vendor/autoload.php', // fallback if run directly from source
];
$found = false;
foreach ($autoloadPaths as $path) {
if (file_exists($path)) {
require $path;
$found = true;
break;
}
}
if (!$found) {
fwrite(STDERR, "Could not locate Composer autoloader.\n");
exit(1);
}
use ofc\IconGetter;
if ($argc !== 2) {
fwrite(STDERR, "Usage: getIcon <icon-name>\n");
exit(1);
}
$icon = trim(strtolower($argv[1]));
try {
IconGetter::get($icon);
} catch (Exception $e) {
fwrite(STDERR, "Error: ".$e->getMessage().PHP_EOL);
exit(1);
}

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env php
<?php
$autoloadPaths = [
__DIR__ . '/../../../autoload.php', // typical path when symlinked in vendor/bin
__DIR__ . '/../vendor/autoload.php', // fallback if run directly from source
];
$found = false;
foreach ($autoloadPaths as $path) {
if (file_exists($path)) {
require $path;
$found = true;
break;
}
}
if (!$found) {
fwrite(STDERR, "Could not locate Composer autoloader.\n");
exit(1);
}
if ($argc < 2) {
fwrite(STDERR, "Usage: rad <command> [options]\n");
exit(1);
}
$command = strtolower(trim($argv[1]));
$arguments = array_slice($argv, 2);
$availableCommands = [
"get-icon" => \ofc\Commands\GetIconCommand::class,
// TODO: additional commands go below
// "swap-library" => \ofc\Commands\LibrarySwap::class,
];
if (!isset($availableCommands[$command])) {
fwrite(STDERR, "Error: Unknown command '$command'\n");
exit(1);
}
// If the user requested help
if (in_array('--help', $arguments)) {
echo $availableCommands[$command]::getHelp().PHP_EOL.PHP_EOL;
exit(0);
}
$availableCommands[$command]::run($arguments);

View File

@@ -2,7 +2,7 @@
"name": "open-function-computers-llc/rad-theme-engine",
"description": "A suite of classes to make WordPress theme development cleaner",
"require": {
"php": ">=7.4",
"php": ">=8.1",
"jjgrainger/posttypes": "^2.1",
"salesforce/handlebars-php": "^2.3"
},
@@ -25,6 +25,6 @@
"post-create-project-cmd": "ofc\\RadThemeEngine::setup"
},
"bin": [
"bin/getIcon"
"bin/rad"
]
}

View File

@@ -0,0 +1,35 @@
<?php
namespace ofc\Commands;
use ofc\IconGetter;
class GetIconCommand
{
public static function run(array $args): void
{
if (count($args) !== 1) {
fwrite(STDERR, "Usage: rad get-icon <icon-name>\n");
var_dump($args);
exit(1);
}
$icon = trim(strtolower($args[0]));
IconGetter::get($icon);
}
public static function getHelp(): string
{
return <<<HELP
Usage: rad get-icon <icon-name>
Description:
Download the SVG icon from https://icons.getbootstrap.com and place it in your theme assets folder.
TODO: link to the docs page.
Example:
rad get-icon phone
HELP;
}
}

View File

@@ -85,6 +85,39 @@ class RadThemeEngine
};
}
public static function pagination()
{
return function ($template, $context, $args, $source) {
return site()->renderTemplate(<<<HTML
<nav class="pagination-links">
<ul>
{{#if older }}
<li><a href="{{ older }}">Next</a></li>
{{/if}}
{{#if newer }}
<li><a href="{{ newer }}">Previous</a></li>
{{/if}}
</ul>
</nav>
HTML, site()->getPaginationLinks());
};
}
public static function count()
{
return function ($template, $context, $args, $source) {
return count($context->get($args));
};
}
public static function queryCount()
{
global $wp_query;
return function ($template, $context, $args, $source) use ($wp_query) {
return $wp_query->found_posts;
};
}
public static function assetURL()
{
return function ($template, $context, $args, $source) {

View File

@@ -2,6 +2,7 @@
namespace ofc;
use Exception;
use PostTypes\PostType;
use Handlebars\Handlebars;
use Handlebars\Loader\FilesystemLoader;
@@ -77,7 +78,8 @@ class Site
$this->registerCPTs();
// register custom hook callbacks
$this->processHooks();
$this->processActions();
$this->processFilters(); // TODO
// add custom shortcodes
$this->registerShortcodes();
@@ -432,6 +434,10 @@ class Site
define('DISALLOW_FILE_EDIT', true);
continue;
}
if ($key === "revisions") {
add_filter('wp_revisions_to_keep', fn ($num, $post) => 0, 10, 2);
continue;
}
if ($key === "gutenberg") {
add_filter('use_block_editor_for_post', '__return_false', 10);
add_action('wp_enqueue_scripts', function () {
@@ -481,6 +487,25 @@ class Site
add_action('init', fn () => add_filter('woocommerce_show_page_title', '__return_false'));
continue;
}
if ($key === "archive_description") {
add_action('init', fn () => remove_action('woocommerce_archive_description', 'woocommerce_taxonomy_archive_description', 10));
continue;
}
if ($key === "reviews") {
add_action('init', function () {
remove_post_type_support('product', 'comments');
});
add_filter('woocommerce_product_reviews_enabled', '__return_false');
add_filter('comments_array', function ($comments, $post_id) {
if (get_post_type($post_id) === 'product') {
return [];
}
return $comments;
}, 10, 2);
continue;
}
continue;
}
@@ -541,6 +566,11 @@ class Site
add_theme_support('menus');
continue;
}
if ($key === "excerpts" || $key === "excerpt") {
add_action('init', fn () => add_post_type_support('page', ['excerpt']));
add_action('init', fn () => add_post_type_support('post', ['excerpt']));
continue;
}
if ($key === "styleselect") {
add_filter('mce_buttons_2', function ($buttons) {
return array_merge(['styleselect'], $buttons);
@@ -556,6 +586,9 @@ class Site
}
if ($key === "woocommerce") {
add_theme_support('woocommerce');
add_theme_support('wc-product-gallery-zoom');
add_theme_support('wc-product-gallery-lightbox');
add_theme_support('wc-product-gallery-slider');
continue;
}
@@ -655,6 +688,10 @@ class Site
"assetURL" => \ofc\RadThemeEngine::assetURL(),
"assetUrl" => \ofc\RadThemeEngine::assetURL(),
"assetContents" => \ofc\RadThemeEngine::assetContents(),
"count" => \ofc\RadThemeEngine::count(),
"length" => \ofc\RadThemeEngine::count(),
"paginationLinks" => \ofc\RadThemeEngine::pagination(),
"queryCount" => \ofc\RadThemeEngine::queryCount(),
];
foreach ($helpers as $name => $callback) {
$this->hb->addHelper($name, $callback);
@@ -700,7 +737,20 @@ class Site
}
return "";
}
return $this->hb->render($fileName, $data);
try {
return $this->hb->render($fileName, $data);
} catch (Exception $e) {
$template = <<<HTML
<div style="padding: 1rem; text-align: center; border: 1px solid #da3636; border-radius: 5px; margin: 1rem;">{{{ message }}}</div>
HTML;
$message = isset($this->config["debug"]) && $this->config["debug"] === true ?
"There was an error. Please see the message below:<br /><strong>" . $e->getMessage() ."</strong>":
"There was an error rendering this page. Please reach out to the site owner or try again later.";
return $this->renderTemplate($template, ["message" => $message]);
}
}
/**
@@ -1012,6 +1062,19 @@ class Site
return $output;
}
public function getQueriedObject($term = null, $fields = [])
{
if (is_null($term)) {
$term = get_queried_object();
}
if ($fields === []) {
return $term;
}
return $this->getFieldsForTerm($fields, $term);
}
public function getTerm($slug, $fields = [])
{
$args = [
@@ -1027,32 +1090,51 @@ class Site
$output = [];
foreach ($results as $term) {
$append = [];
foreach ($fields as $key) {
$oldKey = $key;
if ($key == "id") {
$key = "term_id";
}
if ($key == "title") {
$key = "name";
}
if ($oldKey != $key) {
$append[$oldKey] = $term->$key;
continue;
}
if ($key === "url" || $key === "permalink") {
$append[$key] = get_term_link($term);
continue;
}
$append[$key] = $term->$key;
}
$append = $this->getFieldsForTerm($fields, $term);
$output[] = $append;
}
return $output;
}
private function getFieldsForTerm(array $fields, $term)
{
$output = [];
foreach ($fields as $key) {
if ($key === "id" || $key === "ID" || $key === "term_id") {
$output[$key] = $term->term_id;
continue;
}
if ($key === "title" || $key === "name") {
$output[$key] = $term->name;
continue;
}
if ($key === "url" || $key === "permalink") {
$output[$key] = get_term_link($term);
continue;
}
if ($key === "thumbnail") {
$thumbnailID = get_term_meta($term->term_id, 'thumbnail_id', true);
if (!$thumbnailID) {
$output[$key] = "";
continue;
}
$output[$key] = wp_get_attachment_url($thumbnailID);
continue;
}
if (substr($key, 0, 4) === "acf.") {
$key = str_replace("acf.", "", $key);
$output[$key] = get_field($key, $term->taxonomy . "_" . $term->term_id);
continue;
}
$output[$key] = $term->$key;
}
return $output;
}
private function processArgs(array $args) : array
{
// wordpress default
@@ -1413,19 +1495,51 @@ class Site
}
}
private function processHooks()
private function processActions()
{
if (!isset($this->config["hooks"]) || !is_array($this->config["hooks"])) {
if (!isset($this->config["actions"]) || !is_array($this->config["actions"])) {
return;
}
$defaultPriorities = [
'woocommerce_before_main_content' => 5,
'woocommerce_after_main_content' => 50,
];
foreach ($this->config["hooks"] as $hookName => $callback) {
$priority = $defaultPriorities[$hookName] ?? 99;
add_action($hookName, $callback, $priority);
foreach ($this->config["actions"] as $hookName => $callback) {
if (is_array($callback) && array_is_list($callback)) {
$priority = $callback[1];
$callback = $callback[0];
add_action($hookName, $callback, $priority);
continue;
}
if (is_array($callback) && isset($callback["hook"]) && isset($callback["callback"])) {
add_action($callback["hook"], $callback["callback"], $callback["priority"] ?? 99);
continue;
}
add_action($hookName, $callback, 99);
}
}
/**
* parseArgs
* Used in conjuction with the handlebars helpers to grab all the different args
*
* @param string $args
* @return array
*/
public function parseArgs(string $args): array
{
$parsed = [];
// Match key="value", key='value', or key=value
preg_match_all('/(\w+)=(".*?"|\'.*?\'|\S+)/', $args, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$key = $match[1];
$value = $match[2];
// Strip quotes if present
$value = trim($value, "\"'");
$parsed[$key] = $value;
}
return $parsed;
}
}