Remove all plugins / install base theme

This commit is contained in:
Tony Volpe
2024-06-18 16:14:48 -04:00
parent ecc33d62f0
commit 95cb30b884
7455 changed files with 0 additions and 1722920 deletions

View File

@@ -1 +0,0 @@
{"version":1,"defects":{"ofc\\tests\\UtilTest::weCanSlugifyAString":3},"times":{"ofc\\tests\\UtilTest::weCanSlugifyAString":0.002}}

View File

@@ -1,21 +0,0 @@
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.

View File

@@ -1,11 +0,0 @@
<p align="center">
<img src="https://avatars.githubusercontent.com/u/48373648?s=400&u=710b810ea6c2896a1ed8f67dc13e58fab1a5846d" alt="ofc-logo" style="max-width: 150px" />
</p>
# better-wordpress
A composer package to make WordPress theme development cleaner
## More info to come soon...
I'll write more documentation about this package soon, but for now it's something that you can include and make your theme dev easier.
For now, I'll just describe the system's behavior.

View File

@@ -1,23 +0,0 @@
{
"name": "open-function-computers-llc/better-wordpress",
"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\\BetterWordpress::setup"
}
}

View File

@@ -1,93 +0,0 @@
<?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",
],
];

View File

@@ -1,18 +0,0 @@
<?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>

View File

@@ -1,907 +0,0 @@
<?php
namespace ofc;
use PostTypes\PostType;
use Handlebars\Handlebars;
use Handlebars\Loader\FilesystemLoader;
use PostTypes\Taxonomy;
use WP_Post;
class Site
{
private $config;
private $hb;
private $partialsDir;
private $fileExtension;
private $templateDirectory;
public function __construct($config = [])
{
if ($config == [] && file_exists(TEMPLATEPATH . "/config.php")) {
$config = include(TEMPLATEPATH . "/config.php");
}
$this->config = $config;
$this->bootstrap();
}
private function bootstrap()
{
// disable various things
if (isset($this->config["disable"])) {
$this->disable($this->config["disable"]);
}
// enable various things, starting with TinyMCE
if (isset($this->config["tinyMCEAdditions"]) || isset($this->config["tiny-mce-additions"])) {
$this->addEditorStyles();
}
if (isset($this->config["enable"])) {
$this->enable($this->config["enable"]);
}
// adjust wordpress filters
$this->processFilters();
// create wordpress menu locations
$this->registerMenuLocations();
// initialize handlebars
$this->setUpHandlebars();
// register custom post types
$this->registerCPTs();
// add mix static assets
$this->includeManifestFiles();
// register ACF options pages
$this->addOptionsPages();
}
private function addEditorStyles()
{
$formats = [];
if (isset($this->config["tinyMCEAdditions"])) {
$formats = $this->config["tinyMCEAdditions"];
}
if (isset($this->config["tiny-mce-additions"])) {
$formats = $this->config["tiny-mce-additions"];
}
$defaults = [
[
'title' => 'Headings',
'items' => [
[
'title' => 'Heading 1',
'format' => 'h1',
],
[
'title' => 'Heading 2',
'format' => 'h2',
],
[
'title' => 'Heading 3',
'format' => 'h3',
],
[
'title' => 'Heading 4',
'format' => 'h4',
],
[
'title' => 'Heading 5',
'format' => 'h5',
],
[
'title' => 'Heading 6',
'format' => 'h6',
],
],
],
[
'title' => 'Inline',
'items' => [
[
'title' => 'Bold',
'format' => 'bold',
'icon' => 'bold',
],
[
'title' => 'Italic',
'format' => 'italic',
'icon' => 'italic',
],
[
'title' => 'Underline',
'format' => 'underline',
'icon' => 'underline',
],
[
'title' => 'Strikethrough',
'format' => 'strikethrough',
'icon' => 'strikethrough',
],
[
'title' => 'Superscript',
'format' => 'superscript',
'icon' => 'superscript',
],
[
'title' => 'Subscript',
'format' => 'subscript',
'icon' => 'subscript',
],
[
'title' => 'Code',
'format' => 'code',
'icon' => 'code',
],
],
],
[
'title' => 'Blocks',
'items' => [
[
'title' => 'Paragraph',
'format' => 'p',
],
[
'title' => 'Blockquote',
'format' => 'blockquote',
],
[
'title' => 'Div',
'format' => 'div',
],
[
'title' => 'Pre',
'format' => 'pre',
],
],
],
[
'title' => 'Alignment',
'items' => [
[
'title' => 'Left',
'format' => 'alignleft',
'icon' => 'alignleft',
],
[
'title' => 'Center',
'format' => 'aligncenter',
'icon' => 'aligncenter',
],
[
'title' => 'Right',
'format' => 'alignright',
'icon' => 'alignright',
],
[
'title' => 'Justify',
'format' => 'alignjustify',
'icon' => 'alignjustify',
],
],
],
];
add_filter('tiny_mce_before_init', function ($settings) use ($formats, $defaults) {
$settings['style_formats'] = json_encode(array_merge($defaults, [
[
"title" => "Custom",
"items" => $formats
]
]));
return $settings;
});
}
private function includeManifestFiles()
{
$manifestFile = get_template_directory() . "/dist/mix-manifest.json";
if (!file_exists($manifestFile)) {
return;
}
$items = json_decode(file_get_contents($manifestFile), true);
foreach ($items as $file => $version) {
$extension = end(explode(".", $file));
$tag = $this->stringify($file);
if ($extension === "js") {
add_action('wp_enqueue_scripts', function () use ($file, $version, $tag) {
wp_register_script($tag, get_template_directory_uri() . '/dist/' . $version, [], '', false);
wp_enqueue_script($tag);
});
continue;
}
if ($extension === "css") {
add_action('wp_enqueue_scripts', function () use ($version, $tag) {
wp_enqueue_style($tag, get_template_directory_uri() . '/dist/' . $version);
});
continue;
}
}
}
private function registerCPTs()
{
if (!array_key_exists('custom-post-types', $this->config)) {
return;
}
$cptTaxonomies = [];
foreach ($this->config['custom-post-types'] as $cpt) {
if (!isset($cpt['slug'])) {
$this->adminError("To register a new custom post type, you must set the `slug` key.");
continue;
}
$options = $cpt['options'] ?? [];
$names = $this->generateLabels($cpt['slug']);
$newCpt = new PostType($cpt['slug'], $options, $names);
if (isset($cpt['icon'])) {
$newCpt->icon($cpt['icon']);
}
if (isset($cpt["taxonomies"])) {
foreach ($cpt["taxonomies"] as $customTaxonomy) {
$cptTaxonomies[] = $customTaxonomy;
$newCpt->taxonomy($customTaxonomy);
}
}
$newCpt->register();
// disable post type things here
if (isset($cpt["disable"]) && is_array($cpt["disable"])) {
foreach ($cpt["disable"] as $feature) {
if (strtolower($feature) === "yoast") {
add_action('add_meta_boxes', fn () => remove_meta_box('wpseo_meta', $cpt['slug'], 'normal'), 100);
continue;
}
}
}
// set up any ACF CPT options pages here
if (isset($cpt["options-pages"])) {
if (!function_exists("acf_add_options_page")) {
$this->adminError("You can't register options pages without the Pro version of Advanced Custom Fields.");
continue;
}
foreach ($cpt["options-pages"] as $optionsPageTitle) {
acf_add_options_page([
"page_title" => $optionsPageTitle,
"menu_title" => $optionsPageTitle,
"menu_slug" => $this->stringify($optionsPageTitle),
'capability' => 'edit_posts',
"position" => 100,
"parent_slug" => "edit.php?post_type=" . $cpt["slug"]
]);
}
}
}
if (count($cptTaxonomies)) {
foreach ($cptTaxonomies as $customTaxonomy) {
$tax = new Taxonomy($customTaxonomy);
$tax->options([
'hierarchical' => false,
]);
$tax->register();
}
}
}
private function disable(array $keys)
{
foreach ($keys as $key) {
if ($key === "editor") {
define('DISALLOW_FILE_EDIT', true);
continue;
}
}
}
private function addOptionsPages()
{
if (!array_key_exists('options-pages', $this->config)) {
return;
}
if (!function_exists("acf_add_options_page")) {
$this->adminError("You can't register options pages without the Pro version of Advanced Custom Fields.");
}
$i = 100;
foreach ($this->config["options-pages"] as $pageTitle) {
acf_add_options_page([
"page_title" => $pageTitle,
"menu_title" => $pageTitle,
"menu_slug" => $this->stringify($pageTitle),
'capability' => 'edit_posts',
"position" => $i,
]);
$i++;
}
}
private function enable(array $keys)
{
foreach ($keys as $key) {
if ($key === "post-thumbnails") {
add_theme_support('post-thumbnails');
continue;
}
if ($key === "menus") {
add_theme_support('menus');
continue;
}
if ($key === "styleselect") {
add_filter('mce_buttons_2', function ($buttons) {
return array_merge(['styleselect'], $buttons);
});
continue;
}
$this->adminError("Couldn't enable feature `$key`");
}
}
private function processFilters()
{
// handle "guest" html body class
$guestClass = "guest";
if (array_key_exists("guest-class", $this->config)) {
$guestClass = $this->config["guest-class"];
}
if (!is_null($guestClass)) {
add_filter('body_class', function ($classes) use ($guestClass) {
return in_array('logged-in', $classes) ? $classes : [$guestClass, ...$classes];
});
}
}
private function registerMenuLocations()
{
if (!array_key_exists("menu-locations", $this->config)) {
return;
}
if (!is_array($this->config["menu-locations"])) {
// TODO: show a helpful error message that notifies the developer this is set up wrong
return;
}
$menus = $this->config["menu-locations"];
add_action('after_setup_theme', function () use ($menus) {
register_nav_menus($menus);
});
}
private function setUpHandlebars()
{
if ($this->config["handlebars"] === false) {
return;
}
$this->fileExtension = "tpl";
if (is_array($this->config["handlebars"]) &&
array_key_exists("template-extension", $this->config["handlebars"])
) {
$this->fileExtension = $this->config["handlebars"]["template-extension"];
}
$this->templateDirectory = "tpl";
if (is_array($this->config["handlebars"]) &&
array_key_exists("template-directory", $this->config["handlebars"])
) {
$this->templateDirectory = $this->config["handlebars"]["template-directory"];
}
$this->partialsDir = get_template_directory()."/".$this->templateDirectory;
if (!file_exists($this->partialsDir) && !is_dir($this->partialsDir)) {
$this->adminError("Your Handlebars directory is not setup correctly or doesn't exist.");
return;
}
$partialsLoader = new FilesystemLoader($this->partialsDir, ["extension" => $this->fileExtension]);
$this->hb = new Handlebars([
"loader" => $partialsLoader,
"partials_loader" => $partialsLoader,
"enableDataVariables" => true,
]);
if (isset($this->config["handlebars"]["additional-helpers"])) {
foreach ($this->config["handlebars"]["additional-helpers"] as $name => $callback) {
$this->hb->addHelper($name, $callback);
}
}
}
/**
* render
* See $this->view()
*
* @param string $fileName
* @param array $data
* @return string
*/
public function render(string $fileName, array $data = []) : string
{
return $this->view($fileName, $data);
}
/**
* view
* Invoke handlebar rendering engine for a given template file and data array
*
* @param string $fileName
* @param array $data
* @return string
*/
public function view(string $fileName, array $data = []) : string
{
$filePath = $this->partialsDir."/".$fileName.".".$this->fileExtension;
if (!file_exists($filePath)) {
if ($this->config["debug"] === true) {
return "<pre>View {$fileName}.{$this->fileExtension} does not exist.\nData:\n"
.print_r($data, true)
."</pre>";
}
return "";
}
return $this->hb->render($fileName, $data);
}
public function getPost($idOrPost, $fields = [])
{
if (is_numeric($idOrPost)) {
$p = get_post($idOrPost);
} elseif ($idOrPost instanceof WP_Post) {
$p = $idOrPost;
} else {
return [
"error" => "You must pass an ID or WP_Post to this method"
];
}
if ($fields == []) {
return [
'post' => $p,
'meta' => get_post_meta($p->ID),
];
}
$output = [];
$categories = [];
$taxonomies = [];
foreach ($fields as $key) {
// handle url/permalink
if ($key === "url" || $key === "permalink") {
$output[$key] = get_permalink($p->ID);
continue;
}
// handle post content
if ($key === "content") {
$output["content"] = apply_filters('the_content', get_the_content($p->ID));
continue;
}
// handle post excerpt
if ($key === "excerpt") {
$output["excerpt"] = get_the_excerpt($p->ID);
continue;
}
// handle meta keys
if (substr($key, 0, 5) === "meta.") {
$output[substr($key, 5)] = get_post_meta($p->ID, substr($key, 5), true);
continue;
}
if (substr($key, 0, 4) === "acf.") {
$output[substr($key, 4)] = get_field(substr($key, 4), $p->ID);
continue;
}
if (substr($key, 0, 11) === "categories.") {
if (count($categories) == 0) {
$categories = wp_get_post_categories($p->ID, ["fields" => "all"]);
$attrs = explode(",", substr($key, 11));
foreach ($categories as $cat) {
$dataToAppend = [];
foreach ($attrs as $key) {
$oldKey = $key;
if ($key == "id") {
$key = "term_id";
}
if (isset($cat->$key)) {
$dataToAppend[$oldKey] = $cat->$key;
}
}
$output["categories"][] = $dataToAppend;
}
}
continue;
}
if (substr($key, 0, 9) === "taxonomy.") {
$taxonomyKey = $this->parseTaxKey($key);
$values = explode(",", $this->parseTaxValues($key));
if (!isset($taxonomies[$taxonomyKey])) {
$taxonomies[$taxonomyKey] = $this->getPostTaxonomy($p, $taxonomyKey);
$output[$taxonomyKey] = [];
}
if (!is_array($taxonomies[$taxonomyKey])) {
continue;
}
foreach ($taxonomies[$taxonomyKey] as $tax) {
$taxonomyDTO = [];
foreach ($values as $val) {
if ($val === "id" || $val === "term_id") {
$taxonomyDTO["id"] = $tax->term_id;
continue;
}
if ($val === "link") {
$taxonomyDTO["link"] = get_term_link($tax);
continue;
}
if ($val === "name") {
$taxonomyDTO["name"] = $tax->name;
continue;
}
if ($val === "title") {
$taxonomyDTO["title"] = $tax->name;
continue;
}
if ($val === "slug") {
$taxonomyDTO["slug"] = $tax->slug;
continue;
}
if ($val === "description") {
$taxonomyDTO["description"] = $tax->description;
continue;
}
}
$output[$taxonomyKey][] = $taxonomyDTO;
}
continue;
}
// let's keep our sanity here...
// the following keys are here for convienance. WP names things so weirdly!
if ($key === "id") {
$output[$key] = $p->ID;
continue;
}
if ($key === "title" || $key === "name") {
$output[$key] = $p->post_title;
continue;
}
if ($key === "thumbnail") {
$output[$key] = get_the_post_thumbnail_url($p->ID);
continue;
}
$output[$key] = $p->$key;
}
return $output;
}
public function getPosts($args = [], $fields = [])
{
$args = $this->processArgs($args);
$posts = get_posts($args);
if ($fields == []) {
return [
'posts' => $posts,
];
}
$output = [];
foreach ($posts as $p) {
$output[] = $this->getPost($p, $fields);
}
return $output;
}
/**
* getCurrentPosts
* see getDefaultPosts
*
* @deprecated 1.0.15
*
* @param array $fields
* @return array
*/
public function getCurrentPosts($fields = []) : array
{
return $this->getDefaultPosts($fields);
}
/**
* getDefaultPosts
* get all the posts for the current page as defined by wordpress' weird rules for archive pages
*
* @param array $fields
* @return array
*/
public function getDefaultPosts($fields = []) : array
{
$output = [];
if (!have_posts()) {
return $output;
}
while (have_posts()) {
the_post();
global $post;
$output[] = $this->getPost($post, $fields);
}
return $output;
}
public function getTerm($slug, $fields = [])
{
$args = [
'taxonomy' => $slug,
'hide_empty' => false,
'suppress_filter' => true,
];
$results = get_terms($args);
if ($fields == []) {
return $results;
}
$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;
}
$output[] = $append;
}
return $output;
}
private function processArgs(array $args) : array
{
// wordpress default
$args = array_merge(
[
'numberposts' => 5,
'category' => 0,
'orderby' => 'date',
'order' => 'DESC',
'include' => array(),
'exclude' => array(),
'meta_key' => '',
'meta_value' => '',
'post_type' => 'post',
'suppress_filters' => true,
],
$args
);
if (isset($args["type"])) {
$args["post_type"] = $args["type"];
}
if (isset($args["title"])) {
$args["title"] = urldecode($args["title"]);
}
if (isset($args["s"])) {
$args["s"] = urldecode($args["s"]);
}
// process custom taxonomy
$taxQuery = [];
foreach ($args as $paramKey => $paramValue) {
if (!(substr($paramKey, 0, 4) === "tax." || substr($paramKey, 0, 9) === "taxonomy.")) {
continue;
}
if (substr($paramKey, 0, 4) === "tax.") {
$tax = substr($paramKey, 4);
}
if (substr($paramKey, 0, 9) === "taxonomy.") {
$tax = substr($paramKey, 9);
}
$field = "slug";
$values = explode(",", $paramValue);
$allValuesAreNumeric = false;
foreach ($values as $v) {
if (is_numeric($v)) {
$allValuesAreNumeric = true;
}
}
if ($allValuesAreNumeric) {
$field = "term_id";
}
$taxQuery[] = [
"taxonomy" => $tax,
"field" => $field,
"terms" => $values,
];
}
if ($taxQuery != []) {
$args['tax_query'] = $taxQuery;
}
return $args;
}
private function parseTaxKey(string $paramater) : string
{
$parts = explode(".", $paramater);
if (count($parts) != 3) {
return $paramater;
}
return $parts[1];
}
private function parseTaxValues(string $paramater) : string
{
$parts = explode(".", $paramater);
if (count($parts) != 3) {
return $paramater;
}
return $parts[2];
}
public function getPostTaxonomy($post, $taxonomyKey)
{
return get_the_terms($post->ID, $taxonomyKey);
}
public function setPostMeta($postID, $data)
{
foreach ($data as $metaKey => $metaValue) {
update_post_meta($postID, $metaKey, $metaValue);
}
}
/**
* add an error to the wordpress backend
*
* @param string $message
*/
private function adminError(string $message)
{
$key = $this->stringify($message);
add_action('admin_notices', function ($messages) use ($message, $key) {
add_settings_error($key, '', "OFC Site Error: $message", 'error');
settings_errors($key);
return $messages;
});
}
public function renderMenu($menuLocation)
{
return wp_nav_menu([
"theme_location" => $menuLocation,
"echo" => false,
]);
}
private function stringify(string $thing) : string
{
$bad = [" ", "/"];
$good = ["_", ""];
return strtolower(str_replace($bad, $good, $thing));
}
public function getAssetURL(string $filename) : string
{
if (!file_exists(get_template_directory()."/assets/$filename")) {
$this->adminError("Requested asset $filename doesn't exist.");
return "";
}
return get_template_directory_uri()."/assets/$filename";
}
private function generateLabels(string $slug) : array
{
return [
'name' => $this->humanize($slug, true),
'singular_name' => $this->humanize($slug, false),
'menu_name' => $this->humanize($slug, true),
'all_items' => "All " . $this->humanize($slug, true),
'add_new' => "Add New {$this->humanize($slug, false)}",
'add_new_item' => "Add New {$this->humanize($slug, false)}",
'edit_item' => "Edit {$this->humanize($slug, false)}",
'new_item' => "New {$this->humanize($slug, false)}",
'view_item' => "View {$this->humanize($slug, false)}",
'search_items' => "Search {$this->humanize($slug, true)}",
'not_found' => "No {$this->humanize($slug, true)} found",
'not_found_in_trash' => "No {$this->humanize($slug, true)} found in Trash",
'parent_item_colon' => "Parent {$this->humanize($slug, false)}:",
];
}
private function humanize(string $word, bool $makePlural = false) : string
{
$humanized = ucwords(strtolower(str_replace(['-', '_'], ' ', $word)));
if (!$makePlural) {
return $humanized;
}
if (strtolower(substr($humanized, strlen($humanized)-1, 1)) == "s") {
return $humanized . "es";
}
if (strtolower(substr($humanized, strlen($humanized)-1, 1)) == "y") {
return substr($humanized, 0, strlen($humanized)-1) . "ies";
}
return $humanized . "s";
}
public function getPaginationLinks() : array
{
global $wp_query;
$output = [
"older" => false,
"newer" => false,
"totalPages" => 0,
"currentPage" => 0,
];
if (is_singular()) {
return $output;
}
$max_num_pages = (int) $wp_query->max_num_pages;
$paged = get_query_var('paged');
if (($paged + 1) < $max_num_pages) {
$output["older"] = next_posts(0, false);
}
if ($max_num_pages > 1 && $paged <= $max_num_pages && $paged > 0) {
$output["newer"] = previous_posts(false);
}
$output["totalPages"] = $max_num_pages;
$output["currentPage"] = $paged;
return $output;
}
}

View File

@@ -1,29 +0,0 @@
<?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;
}
}

View File

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