WIP
This commit is contained in:
4
vendor/open-function-computers-llc/rad-theme-engine/.gitignore
vendored
Normal file
4
vendor/open-function-computers-llc/rad-theme-engine/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
.php.result.cache
|
||||
.phpunit.result.cache
|
||||
21
vendor/open-function-computers-llc/rad-theme-engine/LICENSE
vendored
Normal file
21
vendor/open-function-computers-llc/rad-theme-engine/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Open Function Computers, LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
41
vendor/open-function-computers-llc/rad-theme-engine/README.md
vendored
Normal file
41
vendor/open-function-computers-llc/rad-theme-engine/README.md
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<p align="center">
|
||||
<img src="/logo.png" alt="ofc-logo" style="max-width:500px;" />
|
||||
</p>
|
||||
A suite of utilities to deliver a faster and more consistent WordPress theme development experience.
|
||||
<br><br>
|
||||
|
||||
[](https://packagist.org/packages/open-function-computers-llc/rad-theme-engine) [](https://packagist.org/packages/open-function-computers-llc/rad-theme-engine)<br>
|
||||
📦 [View on Packagist](https://packagist.org/packages/open-function-computers-llc/rad-theme-engine) <br>
|
||||
📃 [Read the Docs](https://rad-theme-engine.ofco.cloud/)
|
||||
<br>
|
||||
|
||||
## About
|
||||
|
||||
The purpose of this package is to enable developers to use the familiar model-view-controller pattern in the creation of WordPress themes. This is accomplished by keeping HTML and PHP code as seperated as possible and adding convenient methods to organize data before it’s sent to the view controllers. Querying for posts, rendering menus, handling taxonomies and all the other essential parts of developing a WordPress theme are now easier than ever with the __RAD Theme Engine__.
|
||||
|
||||
|
||||
## Quick Start
|
||||
Inside of your site's `wp-content/themes` folder, run the following command to create a new __Rad Theme Engine__ project.
|
||||
|
||||
```
|
||||
composer create-project open-function-computers-llc/wp-theme <theme-name>
|
||||
```
|
||||
|
||||
Next, enter your new theme's folder and run `npm install` to get dependencies.
|
||||
```
|
||||
cd <theme-name>
|
||||
npm install
|
||||
```
|
||||
|
||||
And that's it! Read about advanced installations and asset bundling on [the docs](https://rad-theme-engine.ofco.cloud/).
|
||||
|
||||
## Example Projects
|
||||
- [Shirt Store](https://github.com/open-function-computers-llc/rad-theme-engine-example-theme) – Demonstrates custom post types, taxonomies, handlebars, and more.
|
||||
|
||||
## Authors
|
||||
- Kurtis Holsapple – [@lapubell](https://github.com/lapubell)
|
||||
- Escher Wright-Dykhouse – [@escherwd](https://github.com/escherwd)
|
||||
- Gabriel Johnson - [@gabriel-johnson](https://github.com/gabriel-johnson)
|
||||
|
||||
## License
|
||||
Licensed under the MIT license, see [LICENSE](https://github.com/open-function-computers-llc/rad-theme-engine/blob/main/LICENSE)
|
||||
37
vendor/open-function-computers-llc/rad-theme-engine/bin/getIcon
vendored
Executable file
37
vendor/open-function-computers-llc/rad-theme-engine/bin/getIcon
vendored
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/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);
|
||||
}
|
||||
30
vendor/open-function-computers-llc/rad-theme-engine/composer.json
vendored
Normal file
30
vendor/open-function-computers-llc/rad-theme-engine/composer.json
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "open-function-computers-llc/rad-theme-engine",
|
||||
"description": "A suite of classes to make WordPress theme development cleaner",
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"jjgrainger/posttypes": "^2.1",
|
||||
"salesforce/handlebars-php": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"wordpress",
|
||||
"handlebars",
|
||||
"theme"
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ofc\\": "src/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-create-project-cmd": "ofc\\RadThemeEngine::setup"
|
||||
},
|
||||
"bin": [
|
||||
"bin/getIcon"
|
||||
]
|
||||
}
|
||||
93
vendor/open-function-computers-llc/rad-theme-engine/config.example.php
vendored
Normal file
93
vendor/open-function-computers-llc/rad-theme-engine/config.example.php
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/**
|
||||
* excerpt-length
|
||||
* how many words should the wordpress excerpt be
|
||||
*/
|
||||
"excerpt-length" => 100,
|
||||
|
||||
/**
|
||||
* guest-class
|
||||
* if you want wordpress to automatically append a class to the body_class
|
||||
* list when users are not authenticated, put that class name here. it
|
||||
* defaults to "guest"
|
||||
*
|
||||
* to disable, set this to null
|
||||
*/
|
||||
"guest-class" => "null",
|
||||
|
||||
/**
|
||||
* menu-locations
|
||||
* register your individual menu locations here
|
||||
*/
|
||||
"menu-locations" => [
|
||||
"main-nav" => "Main Navigation",
|
||||
"footer-nav" => "Footer Navigation",
|
||||
],
|
||||
|
||||
/**
|
||||
* custom-post-types
|
||||
* here is where you can define your custom post types easily
|
||||
*
|
||||
* icons are powered by dashicons, choose one from here:
|
||||
* https://developer.wordpress.org/resource/dashicons
|
||||
*
|
||||
* additional options are enabled in the cpt options key
|
||||
* if you override "supports", be sure to include 'title' and 'editor' in
|
||||
* the list for standard wordpress functionality
|
||||
*/
|
||||
"custom-post-types" => [
|
||||
[
|
||||
"slug" => "thing",
|
||||
"icon" => "dashicons-tide",
|
||||
"options" => [
|
||||
"supports" => ['title', 'editor', 'thumbnail', 'comments']
|
||||
]
|
||||
],
|
||||
],
|
||||
|
||||
/**
|
||||
* handlebars
|
||||
*
|
||||
* We use handlebars templating extensivly in this theme and code pattern.
|
||||
* You can adjust the defaults for many attributes here.
|
||||
*
|
||||
* Set this to `false` to disable handlebars functionality completely
|
||||
*/
|
||||
"handlebars" => [
|
||||
/**
|
||||
* additional-helpers
|
||||
* if you need to register additional Handlebars Helpers, register them here
|
||||
*
|
||||
* the key is the name that you will use in your templates, and the value is
|
||||
* the callback function that is run on the template side
|
||||
*/
|
||||
"additional-helpers" => [],
|
||||
|
||||
/**
|
||||
* template-extension
|
||||
*
|
||||
* The default extention for your templates is .tpl
|
||||
* If you'd like to change that, set the vaule here, without the dot
|
||||
*/
|
||||
// "template-extension" => "tpl",
|
||||
],
|
||||
|
||||
/**
|
||||
* enable
|
||||
* enable individual wordpress features here
|
||||
*/
|
||||
"enable" => [
|
||||
"post-thumbnails",
|
||||
"menus",
|
||||
],
|
||||
|
||||
/**
|
||||
* disable
|
||||
* disable individual wordpress features here
|
||||
*/
|
||||
"disable" => [
|
||||
"editor",
|
||||
],
|
||||
];
|
||||
BIN
vendor/open-function-computers-llc/rad-theme-engine/logo.png
vendored
Normal file
BIN
vendor/open-function-computers-llc/rad-theme-engine/logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
18
vendor/open-function-computers-llc/rad-theme-engine/phpunit.xml
vendored
Normal file
18
vendor/open-function-computers-llc/rad-theme-engine/phpunit.xml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
stopOnFailure="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
</phpunit>
|
||||
849
vendor/open-function-computers-llc/rad-theme-engine/src/FieldHTML.php
vendored
Normal file
849
vendor/open-function-computers-llc/rad-theme-engine/src/FieldHTML.php
vendored
Normal file
@@ -0,0 +1,849 @@
|
||||
<?php
|
||||
|
||||
namespace ofc;
|
||||
|
||||
//build our file, wysiwig, metaboxtoggler
|
||||
//rename media to image
|
||||
|
||||
|
||||
class FieldHTML
|
||||
{
|
||||
public static function template($type, $meta, $postID, $field)
|
||||
{
|
||||
$type = self::translateToSafeMethod($type);
|
||||
return self::$type($meta, $postID, $field);
|
||||
}
|
||||
|
||||
private static function translateToSafeMethod($type)
|
||||
{
|
||||
$output = str_replace(' ', '', ucwords(str_replace('-', ' ', $type)));
|
||||
$output[0] = strtolower($output[0]);
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function wysiwyg($meta, $postID, $field)
|
||||
{
|
||||
|
||||
//create wysiwyg editor
|
||||
$settings = array(
|
||||
'textarea_name' => 'post_text',
|
||||
'default_editor' => 'TinyMce',
|
||||
);
|
||||
$wpEditor = wp_editor($meta, "rad_".$field['name']."_wysiwyg", $settings);
|
||||
|
||||
return <<<HTML
|
||||
|
||||
|
||||
<div class="wysisyg">
|
||||
|
||||
<script>
|
||||
label = '{{field.label}}'
|
||||
wysName = '{{field.name}}'
|
||||
value = "{{value}}"
|
||||
meta = '{{ meta }}'
|
||||
|
||||
|
||||
window.onload = function(){
|
||||
//find elements of the editor
|
||||
const wysiwygField = document.getElementById('rad_'+wysName+'_wysiwyg_ifr').contentWindow.document.getElementById('tinymce')
|
||||
console.log(label)
|
||||
const textareaField = document.getElementById('rad_'+wysName+'_wysiwyg')
|
||||
const inputField = document.getElementById('rad_'+wysName)
|
||||
|
||||
// We have to use js to add the label for WYSIWYG field, otherwise it is under the field
|
||||
var paragraph = document.createElement("p");
|
||||
paragraph.className = "post-attributes-label-wrapper";
|
||||
|
||||
// Create a new label element
|
||||
var labelElement = document.createElement("label");
|
||||
labelElement.className = "post-attributes-label";
|
||||
labelElement.htmlFor = "rad_"+name;
|
||||
labelElement.textContent = label;
|
||||
|
||||
// Append the label to the paragraph
|
||||
paragraph.appendChild(labelElement);
|
||||
var targetElement = document.getElementById("wp-rad_"+wysName+"_wysiwyg-wrap");
|
||||
targetElement.prepend(paragraph);
|
||||
|
||||
|
||||
//on each keystroke update the input field
|
||||
wysiwygField.addEventListener("input", function(){
|
||||
content = tinymce.activeEditor.getContent({format: "html"})
|
||||
inputField.value=content
|
||||
})
|
||||
textareaField.addEventListener("input", function(){
|
||||
inputField.value=textareaField.value
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
<!-- input field that stores data -->
|
||||
<input type="hidden" name="rad_{{ field.name }}" id="rad_{{ field.name }}" value="{{value}}"/>
|
||||
|
||||
</div>
|
||||
|
||||
HTML;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static function text($meta, $postID, $field)
|
||||
{
|
||||
return <<<HTML
|
||||
<p class="post-attributes-label-wrapper">
|
||||
<label class="post-attributes-label" for="rad_{{ field.name }}">{{ field.label }}</label>
|
||||
</p>
|
||||
<input type="text" id="rad_{{ field.name }}" name="rad_{{ field.name }}" value="{{ value }}" />
|
||||
HTML;
|
||||
// {{ template }}
|
||||
}
|
||||
|
||||
public static function number($meta, $postID, $field)
|
||||
{
|
||||
return <<<HTML
|
||||
<p class="post-attributes-label-wrapper">
|
||||
<label class="post-attributes-label" for="rad_{{ field.name }}">{{ field.label }}</label>
|
||||
</p>
|
||||
<input type="number" id="rad_{{ field.name }}" name="rad_{{ field.name }}" value="{{ value }}" />
|
||||
HTML;
|
||||
}
|
||||
|
||||
public static function textarea($meta, $postID, $field)
|
||||
{
|
||||
return <<<HTML
|
||||
<p class="post-attributes-label-wrapper">
|
||||
<label class="post-attributes-label" for="rad_{{ field.name }}">{{ field.label }}</label>
|
||||
</p>
|
||||
<textarea style="width: 100%; height: 220px;" id="rad_{{ field.name }}" name="rad_{{ field.name }}">{{ value }}</textarea>
|
||||
HTML;
|
||||
}
|
||||
|
||||
public static function repeater($meta, $postID, $field)
|
||||
{
|
||||
return <<<HTML
|
||||
<p class="post-attributes-label-wrapper">
|
||||
<label class="post-attributes-label" for="rad_{{ field.name }}">{{ field.label }}</label>
|
||||
</p>
|
||||
|
||||
<div id="repeater-{{ field.name }}">
|
||||
{{#raw}}
|
||||
<input type="hidden" :name="id" :id="id" :value="valueString" />
|
||||
|
||||
<div v-if="!value">
|
||||
<p>No elements</p>
|
||||
</div>
|
||||
<div v-else v-for="(row, i) in value" :key="'row-'+i">
|
||||
<div>{{ i+1 }}</div>
|
||||
<div v-for="(e, j) in row" :key="'e-'+j+'-row-'+i">
|
||||
<label>{{ e.label }}</label>
|
||||
|
||||
<input v-if="e.type === 'text'" type="text" v-model="e.value" @change="updateValueString" />
|
||||
<a href="#" v-if="e.type === 'media'" @click.prevent="setMediaFor(e)" class="button">Choose Media</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<a href="#" class="button" @click.prevent="addRow">Add Row</a>
|
||||
</div>
|
||||
{{/raw}}
|
||||
</div>
|
||||
<script>
|
||||
if (!window.vm) {
|
||||
var vm = [];
|
||||
}
|
||||
vm["{{ field.name }}"] = new Vue({
|
||||
el: "#repeater-{{ field.name }}",
|
||||
data: {
|
||||
value: {{#json-encode value }},
|
||||
valueString: "",
|
||||
id: 'rad_{{ field.name }}',
|
||||
newShape: {{#json-encode field.sub}},
|
||||
fileFrame: null,
|
||||
fileFrameTarget: null,
|
||||
},
|
||||
methods: {
|
||||
addRow() {
|
||||
var thingToPush = [];
|
||||
for (let index = 0; index < this.newShape.length; index++) {
|
||||
var e = this.newShape[index];
|
||||
thingToPush.push(Object.assign({value: ""}, e));
|
||||
}
|
||||
this.value.push(thingToPush);
|
||||
},
|
||||
setMediaFor(ele) {
|
||||
this.fileFrameTarget = ele;
|
||||
this.fileFrame.open();
|
||||
},
|
||||
updateValueString: function() {
|
||||
this.valueString = JSON.stringify(this.value);
|
||||
},
|
||||
},
|
||||
mounted: function() {
|
||||
if (!Array.isArray(this.value)) {
|
||||
if (this.value.length < 1) {
|
||||
this.value = [];
|
||||
} else {
|
||||
this.value = JSON.parse(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
this.updateValueString();
|
||||
|
||||
var self = this;
|
||||
jQuery(document).ready(function() {
|
||||
self.fileFrame = wp.media({
|
||||
frame: 'select',
|
||||
state: 'mystate',
|
||||
library: {type: 'image'},
|
||||
multiple: false
|
||||
});
|
||||
self.fileFrame.states.add([
|
||||
new wp.media.controller.Library({
|
||||
id: 'mystate',
|
||||
title: 'Choose Media',
|
||||
priority: 20,
|
||||
toolbar: 'select',
|
||||
filterable: 'uploaded',
|
||||
library: wp.media.query( self.fileFrame.options.library ),
|
||||
multiple: false,
|
||||
editable: true,
|
||||
displayUserSettings: false,
|
||||
displaySettings: false,
|
||||
allowLocalEdits: true
|
||||
})
|
||||
]);
|
||||
self.fileFrame.on('select', function() {
|
||||
if (self.store === 'url') {
|
||||
self.fileFrameTarget.value = self.fileFrame.state().get('selection').first().toJSON().url;
|
||||
return;
|
||||
}
|
||||
// default storage is json
|
||||
self.fileFrameTarget.value = self.fileFrame.state().get('selection').first().toJSON();
|
||||
self.fileFrameTarget = null;
|
||||
self.updateValueString();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
HTML;
|
||||
}
|
||||
|
||||
public static function image($meta, $postID, $field)
|
||||
{
|
||||
return <<<HTML
|
||||
<p class="post-attributes-label-wrapper">
|
||||
<label class="post-attributes-label" for="rad_{{ field.name }}">{{ field.label }}</label>
|
||||
<div id="media-chooser-{{ field.name }}">
|
||||
<script type="text/javascript">
|
||||
|
||||
//get all the variables associated with each image
|
||||
meta = '{{ value }}'
|
||||
postID = '{{ id }}';
|
||||
name = "{{ field.name }}";
|
||||
store = "{{ field.store }}";
|
||||
|
||||
//get container for image
|
||||
container = document.getElementById('media-chooser-'+name);
|
||||
|
||||
//create image element to display currently set image if store type is url
|
||||
if (store === 'url') {
|
||||
function createIMG(metaPassed, namePassed, containerPassed){
|
||||
image = document.createElement('img');
|
||||
image.style.maxWidth = '300px';
|
||||
image.src = metaPassed;
|
||||
image.id=namePassed;
|
||||
containerPassed.prepend(image);
|
||||
}
|
||||
if(meta){
|
||||
createIMG(meta, name, container)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//create table element to display image and other associated information if store type is json
|
||||
function createTableElements(div, table, textContent1, textContent2, idInput){
|
||||
|
||||
tr1 = document.createElement('tr');
|
||||
td1 = document.createElement('td');
|
||||
td1.style.fontWeight = 'bold';
|
||||
td1.textContent = textContent1
|
||||
|
||||
td2 = document.createElement('td');
|
||||
td2.textContent = textContent2;
|
||||
td2.id=idInput
|
||||
|
||||
tr1.appendChild(td1)
|
||||
tr1.appendChild(td2)
|
||||
|
||||
table.appendChild(tr1);
|
||||
}
|
||||
|
||||
//not done, still need more values
|
||||
if(store === 'json'){
|
||||
//get the meta to readable json
|
||||
//before this it is an ugly string, this makes js able to parse it
|
||||
//create the image div to preview
|
||||
function createTableIMG(url, name, postID, width, height, filesizeHumanReadable){
|
||||
image = document.createElement('img');
|
||||
image.style.maxWidth = '300px';
|
||||
image.src = url;
|
||||
image.id=name;
|
||||
div = document.createElement('div')
|
||||
table = document.createElement('table');
|
||||
//create each table element
|
||||
//each element displays either the post ID of the image, its URL, its dimmentisons, and its size
|
||||
createTableElements(div, table, "ID: ", postID, name+'_id')
|
||||
createTableElements(div, table, "URL: ", url, name+'_url')
|
||||
//Probably need to change the full size at some point.
|
||||
createTableElements(div, table, "Dimmensions: ",width+'x'+height, name+'_dim')
|
||||
createTableElements(div, table, "Size: ", filesizeHumanReadable, name+'_size')
|
||||
|
||||
div.appendChild(table)
|
||||
container.prepend(div)
|
||||
container.prepend(image);
|
||||
}
|
||||
if(meta){
|
||||
meta = meta.replace(/"/g, '\\"');
|
||||
meta = JSON.parse(meta)
|
||||
createTableIMG(meta.url, name, postID, meta.sizes.full.width, meta.sizes.full.height, meta.filesizeHumanReadable)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Input field for each image -->
|
||||
<input type="hidden" name="rad_{{ field.name }}" id="rad_{{ field.name }}" value="{{value}}"/>
|
||||
|
||||
<br />
|
||||
<!-- The button to press to open modal -->
|
||||
<!-- MUST PASS IN THE FIELD NAME AND STORE -->
|
||||
<a href="#" onclick="chooseMedia('{{field.name}}', '{{field.store}}')" class="button">Choose Image</a>
|
||||
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<script>
|
||||
// set up modal
|
||||
function chooseMedia(fieldName, store) {
|
||||
self.fileFrame = wp.media({
|
||||
frame: 'select',
|
||||
state: 'mystate',
|
||||
library: { type: 'image' },
|
||||
multiple: false
|
||||
});
|
||||
|
||||
fileFrame.states.add([
|
||||
new wp.media.controller.Library({
|
||||
id: 'mystate',
|
||||
title: fieldName,
|
||||
priority: 20,
|
||||
toolbar: 'select',
|
||||
filterable: 'uploaded',
|
||||
library: wp.media.query(fileFrame.options.library),
|
||||
multiple: false,
|
||||
editable: true,
|
||||
displayUserSettings: false,
|
||||
displaySettings: false,
|
||||
allowLocalEdits: true
|
||||
})
|
||||
|
||||
]);
|
||||
|
||||
//If image is selected update the input field value
|
||||
|
||||
fileFrame.on('select', function() {
|
||||
inputField = document.getElementById('rad_'+fieldName)
|
||||
|
||||
attachment = fileFrame.state().get('selection').first().toJSON();
|
||||
|
||||
//check how we are to store the img
|
||||
if(store == 'url')
|
||||
{
|
||||
//get image element
|
||||
imgSrc = document.getElementById(fieldName)
|
||||
|
||||
//if it doesn't exist on the frontend make it and display so the user can see the image
|
||||
if(imgSrc == null){
|
||||
container = document.getElementById('media-chooser-'+fieldName)
|
||||
createIMG(attachment.url, attachment.name, container)
|
||||
}
|
||||
|
||||
//otherwise just updated the image
|
||||
else{
|
||||
imgSrc.src = attachment.url
|
||||
}
|
||||
//save it to the backend
|
||||
inputField.value = attachment.url
|
||||
|
||||
} else //if store is json
|
||||
{
|
||||
//update the display immediatly
|
||||
//Does NOT write anything to backend, only shows the user what it will look like.
|
||||
imgSrc = document.getElementById(fieldName)
|
||||
id = document.getElementById(fieldName+'_id')
|
||||
|
||||
if(id==null){
|
||||
createTableIMG(attachment.url, attachment.name, attachment.id, attachment.sizes.full.width, attachment.sizes.full.height, attachment.filesizeHumanReadable)
|
||||
}
|
||||
else{
|
||||
id = document.getElementById(fieldName+'_id')
|
||||
url = document.getElementById(fieldName+'_url')
|
||||
size = document.getElementById(fieldName+'_size')
|
||||
dim = document.getElementById(fieldName+'_dim')
|
||||
dim.textContent=attachment.sizes.full.width+'x'+attachment.sizes.full.height
|
||||
size.textContent=attachment.filesizeHumanReadable
|
||||
url.textContent=attachment.url
|
||||
id.textContent=attachment.id
|
||||
imgSrc.src = attachment.url
|
||||
|
||||
}
|
||||
//this writes everything to backend
|
||||
inputField.value = JSON.stringify(attachment)
|
||||
}
|
||||
});
|
||||
|
||||
//open the modal when button is pressed
|
||||
fileFrame.open();
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
HTML;
|
||||
}
|
||||
|
||||
|
||||
public static function file($meta, $postID, $field)
|
||||
{
|
||||
return <<<HTML
|
||||
<p class="post-attributes-label-wrapper">
|
||||
<label class="post-attributes-label" for="rad_{{ field.name }}">{{ field.label }}</label>
|
||||
<div id="media-chooser-{{ field.name }}">
|
||||
<script type="text/javascript">
|
||||
|
||||
//get all the variables associated with each file
|
||||
meta = '{{ value }}'
|
||||
postID = '{{ id }}';
|
||||
name = "{{ field.name }}";
|
||||
|
||||
//get container for file information
|
||||
container = document.getElementById('media-chooser-'+name);
|
||||
|
||||
//function to create table elements for file info
|
||||
|
||||
function createTableElements(div, table, textContent1, textContent2, idInput){
|
||||
|
||||
tr1 = document.createElement('tr');
|
||||
td1 = document.createElement('td');
|
||||
td1.style.fontWeight = 'bold';
|
||||
td1.textContent = textContent1
|
||||
|
||||
td2 = document.createElement('td');
|
||||
td2.textContent = textContent2;
|
||||
td2.id=idInput
|
||||
|
||||
tr1.appendChild(td1)
|
||||
tr1.appendChild(td2)
|
||||
|
||||
table.appendChild(tr1);
|
||||
}
|
||||
|
||||
|
||||
//instantiate the table itself
|
||||
|
||||
function createTable(postID, url, title, filename, filesizeHumanReadable){
|
||||
|
||||
div = document.createElement('div')
|
||||
table = document.createElement('table');
|
||||
//create each table element
|
||||
//each element displays either the post ID of the image, its URL, its dimmentisons, and its size
|
||||
createTableElements(div, table, "URL: ", url, name+'_url')
|
||||
//Probably need to change the full size at some point.
|
||||
createTableElements(div, table, "Name: ", title, name+'_name')
|
||||
createTableElements(div, table, "File Name: ", filename, name+'_fname')
|
||||
createTableElements(div, table, "Size: ", filesizeHumanReadable, name+'_size')
|
||||
|
||||
div.appendChild(table)
|
||||
container.appendChild(div)
|
||||
|
||||
}
|
||||
|
||||
//check if meta is already populated
|
||||
|
||||
if(meta){
|
||||
//get the meta to readable json
|
||||
//before this it is an ugly string, this makes js able to parse it
|
||||
meta = meta.replace(/"/g, '\\"');
|
||||
meta = JSON.parse(meta)
|
||||
createTable(postID, meta.url, meta.title, meta.filename, meta.filesizeHumanReadable)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- Input field for each image -->
|
||||
<input type="hidden" name="rad_{{ field.name }}" id="rad_{{ field.name }}" value="{{value}}"/>
|
||||
|
||||
<br />
|
||||
<!-- The button to press to open modal -->
|
||||
<!-- MUST PASS IN THE FIELD NAME AND STORE -->
|
||||
<a href="#" onclick="chooseFile('{{field.name}}')" class="button">Choose File</a>
|
||||
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<script>
|
||||
// set up modal
|
||||
function chooseFile(fieldName) {
|
||||
self.fileFrame = wp.media({
|
||||
frame: 'select',
|
||||
state: 'mystate',
|
||||
library: { type: 'application' },
|
||||
multiple: false
|
||||
});
|
||||
|
||||
fileFrame.states.add([
|
||||
new wp.media.controller.Library({
|
||||
id: 'mystate',
|
||||
title: fieldName,
|
||||
priority: 20,
|
||||
toolbar: 'select',
|
||||
filterable: 'uploaded',
|
||||
library: wp.media.query(fileFrame.options.library),
|
||||
multiple: false,
|
||||
editable: true,
|
||||
displayUserSettings: false,
|
||||
displaySettings: false,
|
||||
allowLocalEdits: true
|
||||
})
|
||||
|
||||
]);
|
||||
|
||||
//If file is selected update the input field value
|
||||
|
||||
fileFrame.on('select', function() {
|
||||
inputField = document.getElementById('rad_'+fieldName)
|
||||
attachment = fileFrame.state().get('selection').first().toJSON();
|
||||
fileName = document.getElementById(fieldName+'_fname')
|
||||
|
||||
//if there isn't already the filename element
|
||||
//(i.e. this is the first time uploading a file and we need to create the table to display the data)
|
||||
//create the table and populate it with the recently uploaded information
|
||||
|
||||
if(fileName == null){
|
||||
console.log("null")
|
||||
createTable(attachment.postID, attachment.url, attachment.title, attachment.filename, attachment.filesizeHumanReadable)
|
||||
}
|
||||
//otherwise we can update the existing info
|
||||
else{
|
||||
fileName = document.getElementById(fieldName+'_fname')
|
||||
url = document.getElementById(fieldName+'_url')
|
||||
newName = document.getElementById(fieldName+'_name')
|
||||
size = document.getElementById(fieldName+'_size')
|
||||
|
||||
size.textContent=attachment.filesizeHumanReadable
|
||||
newName.textContent=attachment.title
|
||||
url.textContent=attachment.url
|
||||
fileName.textContent = attachment.filename
|
||||
}
|
||||
|
||||
//this writes everything to backend
|
||||
inputField.value = JSON.stringify(attachment)
|
||||
|
||||
|
||||
});
|
||||
|
||||
//open the modal when button is pressed
|
||||
fileFrame.open();
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
HTML;
|
||||
}
|
||||
|
||||
|
||||
public static function flexRepeater()
|
||||
{
|
||||
return <<<HTML
|
||||
<p class="post-attributes-label-wrapper">
|
||||
<label class="post-attributes-label" for="rad_{{ field.name }}">{{ field.label }}</label>
|
||||
<div id="media-chooser-{{ field.name }}">
|
||||
{{#raw}}
|
||||
<input type="hidden" :name="id" :id="id" :value="valueString" />
|
||||
|
||||
<div v-if="!value">
|
||||
<p>You don't have any content variations. Start adding some with the "Add Variation" button below.</p>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div v-for="(v, i) in value" :key="'variation-'+i">
|
||||
<div class="variation-wrapper">
|
||||
<div class="title">
|
||||
<h3>{{ v.name }}</h3>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<a v-if="i > 0" class="button button-small" style="font-family: dashicons" href="#" @click.prevent="moveUp(i)"></a>
|
||||
<a v-if="i < (value.length - 1)" class="button button-small" style="font-family: dashicons" href="#" @click.prevent="moveDown(i)"></a>
|
||||
<a class="button button-small" style="font-family: dashicons" href="#" @click.prevent="removeVariation(i)"></a>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div v-for="(f, j) in v.fields" :key="'variation-'+i+'-field-'+j" />
|
||||
<label>{{ f.label }}</label>
|
||||
|
||||
<!-- simple fields -->
|
||||
<input type="text" v-if="f.type === 'text'" v-model="f.value" @change="updateValueString" />
|
||||
<textarea v-if="f.type === 'textarea'" v-model="f.value" style="width: 100%; height: 220px;" @change="updateValueString"></textarea>
|
||||
|
||||
<!-- ajax fields -->
|
||||
<div v-if="f.type === 'media'" style="position: relative">
|
||||
<table v-if="chosenMediaParse(f.value)">
|
||||
<tr>
|
||||
<td style="font-weight: bold">ID:</td><td>{{ chosenMediaParse(f.value).id }}</td>
|
||||
</tr>
|
||||
<td style="font-weight: bold">Size:</td><td>{{ chosenMediaParse(f.value).filesizeHumanReadable }}</td>
|
||||
</tr>
|
||||
<td style="font-weight: bold">Dimensions:</td><td>{{ chosenMediaParse(f.value).width }}x{{ chosenMediaParse(f.value).height }}</td>
|
||||
</tr>
|
||||
<td style="font-weight: bold">URL:</td><td>{{ chosenMediaParse(f.value).url }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div v-if="!f.value" style="border: 1px solid #666; padding: 1rem; margin-bottom: 1rem;">No media chosen</div>
|
||||
<a href="#" @click.prevent="chooseMedia(f)" class="button">Choose Media</a>
|
||||
</div>
|
||||
|
||||
<!-- ajax fields -->
|
||||
<div v-if="f.type === 'related'" style="position: relative">
|
||||
<input type="text" @keyup="relatedTypeAhead(\$event)" v-model="ajaxSearches[f.name]" placeholder="Type to choose..." />
|
||||
<ul class="pop-open-box">
|
||||
<li v-for="(r, k) in ajaxResults" :key="'ajax-result-'+k" @click="setValueFor(r, f)">{{ r.title }}</li>
|
||||
</ul>
|
||||
<p v-if="f.value">{{ f.value.url }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="addingVariation">
|
||||
<p>Type:</p>
|
||||
<select v-model="newVariation">
|
||||
<option v-for="(v, i) in variations" :value="v" :key="'variation-'+i">{{ v.name }}</option>
|
||||
</select>
|
||||
<a href="#" @click.prevent="addVariation" class="button button-small">Add</a>
|
||||
<a href="#" @click.prevent="addingVariation = false; newVariation = null;" class="button button-small">Cancel</a>
|
||||
</div>
|
||||
<a
|
||||
v-else
|
||||
class="button button-small"
|
||||
href="#"
|
||||
@click.prevent="addingVariation = true"
|
||||
>Add Variation</a>
|
||||
|
||||
{{/raw}}
|
||||
</div>
|
||||
<style>
|
||||
.pop-open-box {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
background-color: white;
|
||||
padding: 3px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.pop-open-box li {
|
||||
padding: 3px;
|
||||
}
|
||||
.pop-open-box li:hover {
|
||||
cursor: pointer;
|
||||
background-color: grey;
|
||||
}
|
||||
.variation-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.variation-wrapper h3 {
|
||||
margin: 0;
|
||||
}
|
||||
.variation-wrapper .title {
|
||||
flex: 1;
|
||||
}
|
||||
.variation-wrapper .content {
|
||||
width: 100%;
|
||||
}
|
||||
.variation-wrapper label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
if (!window.vm) {
|
||||
var vm = [];
|
||||
}
|
||||
vm["{{ field.name }}"] = new Vue({
|
||||
el: "#media-chooser-{{ field.name }}",
|
||||
data: {
|
||||
id: 'rad_{{ field.name }}',
|
||||
value: {{#json-encode value}},
|
||||
variations: {{#json-encode field.variations}},
|
||||
addingVariation: false,
|
||||
newVariation: null,
|
||||
valueString: "",
|
||||
ajaxResults: [],
|
||||
ajaxSearches: {},
|
||||
fileFrame: null,
|
||||
fileFrameTarget: null,
|
||||
},
|
||||
methods: {
|
||||
addVariation: function(v) {
|
||||
this.value.push(Object.assign({value: ""}, this.newVariation));
|
||||
this.newVariation = null;
|
||||
this.addingVariation = false;
|
||||
},
|
||||
moveUp: function(index) {
|
||||
this.value.splice(index-1, 0, this.value.splice(index, 1)[0]);
|
||||
},
|
||||
moveDown: function(index) {
|
||||
this.value.splice(index+1, 0, this.value.splice(index, 1)[0]);
|
||||
},
|
||||
removeVariation: function(index) {
|
||||
this.value.splice(index, 1);
|
||||
},
|
||||
relatedTypeAhead: function(\$event) {
|
||||
var self = this;
|
||||
jQuery.post(ajaxurl, {action: "betterwordpress_related", q: \$event.target.value}, function(res) {
|
||||
self.ajaxResults = JSON.parse(res);
|
||||
});
|
||||
},
|
||||
setValueFor: function(r, f) {
|
||||
f.value = r;
|
||||
this.updateValueString();
|
||||
this.ajaxResults = [];
|
||||
this.ajaxSearches = {};
|
||||
},
|
||||
updateValueString: function() {
|
||||
this.valueString = JSON.stringify(this.value);
|
||||
},
|
||||
chooseMedia: function(f) {
|
||||
this.fileFrameTarget = f;
|
||||
this.fileFrame.open();
|
||||
},
|
||||
chosenMediaParse(data) {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
// console.log(data);
|
||||
return JSON.parse(data);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: function() {
|
||||
this.valueString = JSON.stringify(this.value);
|
||||
}
|
||||
},
|
||||
mounted: function() {
|
||||
if (!Array.isArray(this.value)) {
|
||||
if (this.value.length < 1) {
|
||||
this.value = [];
|
||||
} else {
|
||||
this.value = JSON.parse(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
var self = this;
|
||||
jQuery(document).ready(function() {
|
||||
self.fileFrame = wp.media({
|
||||
frame: 'select',
|
||||
state: 'mystate',
|
||||
library: {type: 'image'},
|
||||
multiple: false
|
||||
});
|
||||
self.fileFrame.states.add([
|
||||
new wp.media.controller.Library({
|
||||
id: 'mystate',
|
||||
title: 'Choose your media',
|
||||
priority: 20,
|
||||
toolbar: 'select',
|
||||
filterable: 'uploaded',
|
||||
library: wp.media.query( self.fileFrame.options.library ),
|
||||
multiple: false,
|
||||
editable: true,
|
||||
displayUserSettings: false,
|
||||
displaySettings: false,
|
||||
allowLocalEdits: true
|
||||
})
|
||||
]);
|
||||
self.fileFrame.on('select', function() {
|
||||
if (self.store === 'url') {
|
||||
self.fileFrameTarget.value = self.fileFrame.state().get('selection').first().toJSON().url;
|
||||
self.updateValueString();
|
||||
return;
|
||||
}
|
||||
|
||||
// default storage is json
|
||||
self.fileFrameTarget.value = JSON.stringify(self.fileFrame.state().get('selection').first().toJSON());
|
||||
|
||||
self.updateValueString();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
HTML;
|
||||
}
|
||||
|
||||
public static function metaBoxToggler($hidden)
|
||||
{
|
||||
// die(var_dump($hidden));
|
||||
return <<<HTML
|
||||
<style>#{{group-name}} {display: none;}</style>
|
||||
<div id="rad-metabox-toggler-{{group-name}}"></div>
|
||||
<script>
|
||||
|
||||
const elementsToHide = {{#json-encode hidden}}
|
||||
|
||||
|
||||
document.getElementById("metaBoxToggler{{group-name}}")
|
||||
function hideStuff(state, elementsToHide) {
|
||||
// Store references to DOM elements
|
||||
for (var i = 0; i < elementsToHide.length; i++) {
|
||||
var element = elementsToHide[i];
|
||||
if (element === "WYSIWYG") {
|
||||
jQuery("#postdivrich").css("visibility", "hidden");
|
||||
jQuery("#postdivrich").height(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
jQuery(document).ready(function() {
|
||||
jQuery("#{{group-name}}").show();
|
||||
jQuery("#{{group-name}} input, #{{group-name}} textarea").each(function() {
|
||||
jQuery(this).removeAttr("disabled");
|
||||
});
|
||||
hideStuff(true, elementsToHide);
|
||||
return;
|
||||
|
||||
jQuery("#{{group-name}} input, #{{group-name}} textarea").each(function() {
|
||||
jQuery(this).attr("disabled", "disabled");
|
||||
});
|
||||
jQuery("#{{group-name}}").hide();
|
||||
// bind event to this vue app
|
||||
jQuery("#page_template").on("change", function() {
|
||||
self.selectedTemplate = jQuery("#page_template option:selected").text();
|
||||
});
|
||||
// initial state hydration
|
||||
self.selectedTemplate = jQuery("#page_template option:selected").text();
|
||||
// hideStuff(elementsToHide)
|
||||
});
|
||||
|
||||
|
||||
// Initialize the module
|
||||
</script>
|
||||
HTML;
|
||||
|
||||
}
|
||||
}
|
||||
2115
vendor/open-function-computers-llc/rad-theme-engine/src/IconGetter.php
vendored
Normal file
2115
vendor/open-function-computers-llc/rad-theme-engine/src/IconGetter.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
84
vendor/open-function-computers-llc/rad-theme-engine/src/RadField.php
vendored
Normal file
84
vendor/open-function-computers-llc/rad-theme-engine/src/RadField.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace ofc;
|
||||
|
||||
class RadField
|
||||
{
|
||||
public static function image($label, $name = null, $store = "url") : array
|
||||
{
|
||||
if (is_null($name)) {
|
||||
$name = Util::snakeify($label);
|
||||
}
|
||||
|
||||
return [
|
||||
"type" => "image",
|
||||
"label" => $label,
|
||||
"name" => $name,
|
||||
"store" => $store,
|
||||
];
|
||||
}
|
||||
|
||||
public static function text($label, $name = null) : array
|
||||
{
|
||||
if (is_null($name)) {
|
||||
$name = Util::snakeify($label);
|
||||
}
|
||||
|
||||
return [
|
||||
"type" => "text",
|
||||
"label" => $label,
|
||||
"name" => $name,
|
||||
];
|
||||
}
|
||||
|
||||
public static function textarea($label, $name = null) : array
|
||||
{
|
||||
if (is_null($name)) {
|
||||
$name = Util::snakeify($label);
|
||||
}
|
||||
|
||||
return [
|
||||
"type" => "textarea",
|
||||
"label" => $label,
|
||||
"name" => $name,
|
||||
];
|
||||
}
|
||||
|
||||
public static function file($label, $name = null) : array
|
||||
{
|
||||
if (is_null($name)) {
|
||||
$name = Util::snakeify($label);
|
||||
}
|
||||
|
||||
return [
|
||||
"type" => "file",
|
||||
"label" => $label,
|
||||
"name" => $name,
|
||||
];
|
||||
}
|
||||
|
||||
public static function wysiwyg($label, $name = null) : array
|
||||
{
|
||||
if (is_null($name)) {
|
||||
$name = Util::snakeify($label);
|
||||
}
|
||||
|
||||
return [
|
||||
"type" => "wysiwyg",
|
||||
"label" => $label,
|
||||
"name" => $name,
|
||||
];
|
||||
}
|
||||
|
||||
public static function getFields($fields): array
|
||||
{
|
||||
$tpl_fields = [];
|
||||
|
||||
foreach($fields as $field){
|
||||
$tpl_fields[] = 'rad.'.$field['name'];
|
||||
}
|
||||
|
||||
return $tpl_fields;
|
||||
}
|
||||
|
||||
}
|
||||
109
vendor/open-function-computers-llc/rad-theme-engine/src/RadThemeEngine.php
vendored
Normal file
109
vendor/open-function-computers-llc/rad-theme-engine/src/RadThemeEngine.php
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace ofc;
|
||||
|
||||
class RadThemeEngine
|
||||
{
|
||||
public static function wpHeader()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
return self::getFromBuffer("wp_head");
|
||||
};
|
||||
}
|
||||
|
||||
public static function wpTitle()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
return wp_title('|', false, 'right') . get_bloginfo("name");
|
||||
};
|
||||
}
|
||||
|
||||
public static function wpFooter()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
return self::getFromBuffer("wp_footer");
|
||||
};
|
||||
}
|
||||
|
||||
public static function bodyClasses()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
return self::getFromBuffer("body_class");
|
||||
};
|
||||
}
|
||||
|
||||
public static function jsonEncode()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
return json_encode($context->get($args));
|
||||
};
|
||||
}
|
||||
|
||||
public static function jsonAccess()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
$parts = explode(".", $args);
|
||||
if (count($parts) != 2) {
|
||||
return "Invalid use of json-access";
|
||||
}
|
||||
$data = json_decode($context->get($parts[0]), true);
|
||||
return $data[$parts[1]];
|
||||
};
|
||||
}
|
||||
|
||||
public static function processFlex()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
$output = "";
|
||||
|
||||
if (!is_iterable($context->get($args))) {
|
||||
return "Sorry, the item you passed to the flex helper is not iterable.";
|
||||
}
|
||||
|
||||
$groups = $context->get($args);
|
||||
foreach ($groups as $g) {
|
||||
if (!is_array($g)) {
|
||||
$output .= "Sorry, one of your items is not compatible with the flex helper. Here is the details:<br /><br />".print_r($g, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($g["acf_fc_layout"])) {
|
||||
$output .= "Sorry, one of your items is missing the `acf_fc_layout` key:<br /><br />".print_r($g, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output .= site()->render(site()->getFlexFilePrefix().$g["acf_fc_layout"], $g);
|
||||
}
|
||||
return $output;
|
||||
};
|
||||
}
|
||||
|
||||
public static function nl2br()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
return nl2br($context->get($args));
|
||||
};
|
||||
}
|
||||
|
||||
public static function assetURL()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
return site()->getAssetURL($args);
|
||||
};
|
||||
}
|
||||
|
||||
public static function assetContents()
|
||||
{
|
||||
return function ($template, $context, $args, $source) {
|
||||
return site()->getAssetContents($args);
|
||||
};
|
||||
}
|
||||
|
||||
private static function getFromBuffer($func)
|
||||
{
|
||||
ob_start();
|
||||
$func();
|
||||
$output = ob_get_clean();
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
1431
vendor/open-function-computers-llc/rad-theme-engine/src/Site.php
vendored
Normal file
1431
vendor/open-function-computers-llc/rad-theme-engine/src/Site.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
103
vendor/open-function-computers-llc/rad-theme-engine/src/Util.php
vendored
Normal file
103
vendor/open-function-computers-llc/rad-theme-engine/src/Util.php
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace ofc;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* slugify
|
||||
* modified from https://lucidar.me/en/web-dev/how-to-slugify-a-string-in-php/
|
||||
*
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
public static function slugify(string $str) : string
|
||||
{
|
||||
$text = strip_tags($str);
|
||||
$text = str_replace(" & ", " and ", $text);
|
||||
$text = preg_replace('~[^\pL\d]+~u', '-', $text);
|
||||
setlocale(LC_ALL, 'en_US.utf8');
|
||||
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
|
||||
$text = preg_replace('~[^-\w]+~', '', $text);
|
||||
$text = trim(strtolower($text), '-');
|
||||
$text = preg_replace('~-+~', '-', $text);
|
||||
if (empty($text)) {
|
||||
return 'n-a';
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* snakify
|
||||
* basically the same as slugify but with _ instead of -
|
||||
*
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public static function snakeify(string $string) :string
|
||||
{
|
||||
return str_replace("-", "_", self::slugify($string));
|
||||
}
|
||||
|
||||
public static function processFieldGroup($fieldGroup)
|
||||
{
|
||||
add_action('admin_head-post.php', function () use ($fieldGroup) {
|
||||
global $post;
|
||||
if ($fieldGroup) {
|
||||
echo site()->renderTemplate(FieldHTML::metaBoxToggler(["WYSIWYG"]), [
|
||||
"group-name" => self::slugify($fieldGroup[0]),
|
||||
"for" => "page",
|
||||
"hidden" => ["WYSIWYG"],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
add_action('add_meta_boxes', function () use ($fieldGroup) {
|
||||
if (count($fieldGroup) < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $fieldGroup[0];
|
||||
array_shift($fieldGroup);
|
||||
foreach ($fieldGroup as $group) {
|
||||
// conditionally show/hide the box
|
||||
$slugName = self::slugify($name);
|
||||
|
||||
add_meta_box(
|
||||
$slugName,
|
||||
$name,
|
||||
function ($post) use ($fieldGroup, $group) {
|
||||
foreach ($fieldGroup as $field) {
|
||||
// sanatize media fields
|
||||
if ($field["type"] === "image") {
|
||||
if (!isset($field["store"])) {
|
||||
$field["store"] = "json";
|
||||
}
|
||||
}
|
||||
|
||||
echo site()->renderTemplate(FieldHTML::template($field["type"], get_post_meta($post->ID, "rad_".$field['name'], true), $post->ID, $field), [
|
||||
"value" => get_post_meta($post->ID, "rad_".$field['name'], true),
|
||||
"id" => $post->ID,
|
||||
"field" => $field,
|
||||
])."<hr />";
|
||||
}
|
||||
},
|
||||
'page',
|
||||
'advanced',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
add_action('save_post', function ($post_id) use ($fieldGroup) {
|
||||
if (!isset($fieldGroup['fields'])) {
|
||||
return;
|
||||
}
|
||||
foreach ($fieldGroup['fields'] as $field) {
|
||||
if (!isset($_POST['rad_'.$field['name']])) {
|
||||
continue;
|
||||
}
|
||||
update_post_meta($post_id, 'rad_'.$field['name'], wp_kses_post($_POST['rad_'.$field['name']]));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
22
vendor/open-function-computers-llc/rad-theme-engine/tests/UtilTest.php
vendored
Normal file
22
vendor/open-function-computers-llc/rad-theme-engine/tests/UtilTest.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace ofc\tests;
|
||||
|
||||
use ofc\Util;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class UtilTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function weCanSlugifyAString()
|
||||
{
|
||||
$cases = [
|
||||
"This is a string" => "this-is-a-string",
|
||||
"String with nÓn ASCII chars & stuff!" => "string-with-non-ascii-chars-and-stuff",
|
||||
];
|
||||
|
||||
foreach ($cases as $input => $expected) {
|
||||
$this->assertEquals($expected, Util::slugify($input));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user