diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..491f666 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +.idea/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..22c2e9b --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# Template Plumbing + +This little tool gives you an easy way to organize your page (or custom post type) templates better. By "templates" I mean the templates you can select from the "Templates" dropdown in the editor. + +## Usage + +First, install the package: + +```bash +composer require livy/plumbing-template +``` + +Then call the tool like this, somewhere where it'll be run early (i.e. `functions.php`): + +```php +Livy\Plumbing\Templates\register_template_directory('custom-templates'); +``` + +By default, the plugin assumes you're changing the template for the `page` post type, but you can specify _any_ post type by passing a second parameter: + +```php +// Define templates for the `event` post type: +Livy\Plumbing\Templates\register_template_directory('event-templates', 'event'); +``` + +## Limitations + +The tool looks in your template directory (i.e. the result of `get_template_directory()`) when looking for the directory you specify. If will silently fail if it can't find the directory, or if you try to do something clever (i.e. `../../../usr/bin`) for your template path. + +Currently this tool can only point to a single directory per post type. \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..ea67030 --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "livy/plumbing-templates", + "description": "Put your page (or custom post type) templates in better directories. Works with Sage!", + "license": "MIT", + "authors": [ + { + "name": "Ben Martinez-Bateman", + "email": "ben@alwaysblank.org" + } + ], + "autoload": { + "files": ["src/functions.php"] + }, + "require": { + "php": ">=7.0", + "symfony/finder": "^4.0" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..8033ac9 --- /dev/null +++ b/composer.lock @@ -0,0 +1,69 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "ab99e93e4579936158ab4fcfc17c9340", + "packages": [ + { + "name": "symfony/finder", + "version": "v4.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/44a796d2ecc2a16a5fc8f2956a34ee617934d55f", + "reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2018-03-05T18:28:26+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.0" + }, + "platform-dev": [] +} diff --git a/src/functions.php b/src/functions.php new file mode 100644 index 0000000..e432e82 --- /dev/null +++ b/src/functions.php @@ -0,0 +1,85 @@ +<?php + +namespace Livy\Plumbing\Templates; + +use Symfony\Component\Finder\Finder; + +function register_template_directory(string $path, $post_type = 'page') +{ + add_filter("theme_{$post_type}_templates", function($templates) use ($path, $post_type) { + return array_merge($templates, set_template_directory($path, $post_type)); + }); +} + +function set_template_directory(string $path, string $post_type = 'page') +{ + $checked_path = check_path_segment($path); + $full_path = realpath(get_wordpress_template_directory($post_type) . DIRECTORY_SEPARATOR . $checked_path) ?: ''; + + // Make sure you're not trying to go somewhere weird + if (0 !== strpos($full_path, get_wordpress_template_directory($post_type))) { + return []; + } + + $templates = []; + + if (is_dir($full_path)) { + $inline_identifier = get_inline_identifier($post_type); + $finder = new Finder(); + $finder->files()->in($full_path)->name(get_file_extenstion($post_type)); + foreach ($finder as $file) { + + // Set $name so it'll be sure to have a value. + $name = false; + + // Look in each file to find the name; leave as soon as we have it. + if ($opened_file = fopen($file->getRealPath(), 'r')) { + while (($line = fgets($opened_file)) !== false) { + if (strpos($line, $inline_identifier)) { + $name = trim(str_replace($inline_identifier, '', $line)); + break; + } + } + } + fclose($opened_file); + + // Only add to list if we have a viable $name. + if ($name) { + $templates[$checked_path . $file->getFilename()] = $name; + } + + // Don't want to accidentally pass these to the next iteration. + unset($name, $opened_file); + } + } + + return $templates; +} + +/** + * @return string + */ +function get_wordpress_template_directory($post_type) +{ + return apply_filters('template-dir/theme-directory', get_template_directory(), $post_type); +} + +function get_inline_identifier($post_type) +{ + return apply_filters('template-dir/inline-identifier', 'Template Name:', $post_type); +} + +function get_file_extenstion($post_type) +{ + return apply_filters('template-dir/file-extension', '*.php', $post_type); +} + +function check_path_segment(string $path) +{ + // Need a trailing slash. + $trailingslashed = trailingslashit($path); + + // Don't want a leading slash. + $frontchecked = ltrim($trailingslashed, '\\/'); + return $frontchecked; +} \ No newline at end of file