You've already forked wp-fedistream
feat: Replace Twig with native PHP templates
All checks were successful
Create Release Package / build-release (push) Successful in 55s
All checks were successful
Create Release Package / build-release (push) Successful in 55s
- Remove twig/twig dependency from composer.json - Convert all 25 Twig templates to native PHP templates - New render() method in Plugin.php using PHP include with output buffering - New render_partial() helper method for including partials - Templates support theme overrides via fedistream/ directory - Reduced plugin size by eliminating Twig and its dependencies Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,7 @@ use WP_FediStream\PostTypes\Track;
|
||||
use WP_FediStream\PostTypes\Playlist;
|
||||
use WP_FediStream\Taxonomies\Genre;
|
||||
use WP_FediStream\Taxonomies\Mood;
|
||||
use WP_FediStream\Taxonomies\License;
|
||||
use WP_FediStream\Taxonomies\License as LicenseTaxonomy;
|
||||
use WP_FediStream\User\Library as UserLibrary;
|
||||
use WP_FediStream\User\LibraryPage;
|
||||
use WP_FediStream\User\Notifications;
|
||||
@@ -50,21 +50,14 @@ final class Plugin {
|
||||
private static ?Plugin $instance = null;
|
||||
|
||||
/**
|
||||
* Twig environment instance.
|
||||
*
|
||||
* @var \Twig\Environment|null
|
||||
*/
|
||||
private ?\Twig\Environment $twig = null;
|
||||
|
||||
/**
|
||||
* Current Twig render depth to prevent infinite recursion.
|
||||
* Current render depth to prevent infinite recursion.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static int $render_depth = 0;
|
||||
|
||||
/**
|
||||
* Maximum allowed Twig render depth.
|
||||
* Maximum allowed render depth.
|
||||
* Set to 2 to allow one level of nested includes but prevent deeper recursion.
|
||||
*
|
||||
* @var int
|
||||
@@ -109,7 +102,6 @@ final class Plugin {
|
||||
* Private constructor to enforce singleton pattern.
|
||||
*/
|
||||
private function __construct() {
|
||||
$this->init_twig();
|
||||
$this->init_components();
|
||||
$this->init_hooks();
|
||||
$this->load_textdomain();
|
||||
@@ -132,32 +124,6 @@ final class Plugin {
|
||||
throw new \Exception( 'Cannot unserialize singleton' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Twig template engine.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function init_twig(): void {
|
||||
$loader = new \Twig\Loader\FilesystemLoader( WP_FEDISTREAM_PATH . 'templates' );
|
||||
|
||||
$this->twig = new \Twig\Environment(
|
||||
$loader,
|
||||
array(
|
||||
'cache' => WP_FEDISTREAM_PATH . 'cache/twig',
|
||||
'auto_reload' => WP_DEBUG,
|
||||
)
|
||||
);
|
||||
|
||||
// Add WordPress escaping functions.
|
||||
$this->twig->addFunction( new \Twig\TwigFunction( 'esc_html', 'esc_html' ) );
|
||||
$this->twig->addFunction( new \Twig\TwigFunction( 'esc_attr', 'esc_attr' ) );
|
||||
$this->twig->addFunction( new \Twig\TwigFunction( 'esc_url', 'esc_url' ) );
|
||||
$this->twig->addFunction( new \Twig\TwigFunction( 'esc_js', 'esc_js' ) );
|
||||
$this->twig->addFunction( new \Twig\TwigFunction( 'wp_nonce_field', 'wp_nonce_field', array( 'is_safe' => array( 'html' ) ) ) );
|
||||
$this->twig->addFunction( new \Twig\TwigFunction( '__', '__' ) );
|
||||
$this->twig->addFunction( new \Twig\TwigFunction( '_e', '_e' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize plugin components.
|
||||
*
|
||||
@@ -173,7 +139,7 @@ final class Plugin {
|
||||
// Initialize taxonomies.
|
||||
$this->taxonomies['genre'] = new Genre();
|
||||
$this->taxonomies['mood'] = new Mood();
|
||||
$this->taxonomies['license'] = new License();
|
||||
$this->taxonomies['license'] = new LicenseTaxonomy();
|
||||
|
||||
// Initialize admin components.
|
||||
if ( is_admin() ) {
|
||||
@@ -876,19 +842,30 @@ final class Plugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Twig environment.
|
||||
* Get the path to a template file.
|
||||
*
|
||||
* @return \Twig\Environment
|
||||
* Checks theme for override first, then falls back to plugin template.
|
||||
*
|
||||
* @param string $template Template name (without extension).
|
||||
* @return string Full path to template file.
|
||||
*/
|
||||
public function get_twig(): \Twig\Environment {
|
||||
return $this->twig;
|
||||
public function get_template_path( string $template ): string {
|
||||
// Check theme for override.
|
||||
$theme_template = locate_template( "fedistream/{$template}.php" );
|
||||
if ( $theme_template ) {
|
||||
return $theme_template;
|
||||
}
|
||||
|
||||
// Use plugin template.
|
||||
return WP_FEDISTREAM_PATH . "templates/{$template}.php";
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Twig template.
|
||||
* Render a PHP template.
|
||||
*
|
||||
* @param string $template Template name (without .twig extension).
|
||||
* @param array $context Template context variables.
|
||||
* @param string $template Template name (without extension).
|
||||
* @param array $context Template context variables.
|
||||
* @param bool $is_main_template Whether this is the main page template.
|
||||
* @return string Rendered template.
|
||||
*/
|
||||
public function render( string $template, array $context = array(), bool $is_main_template = false ): string {
|
||||
@@ -897,7 +874,7 @@ final class Plugin {
|
||||
return '<!-- FediStream: blocked during main template render -->';
|
||||
}
|
||||
|
||||
// Prevent infinite recursion in Twig rendering.
|
||||
// Prevent infinite recursion in rendering.
|
||||
if ( self::$render_depth >= self::MAX_RENDER_DEPTH ) {
|
||||
return '<!-- FediStream: render depth exceeded -->';
|
||||
}
|
||||
@@ -911,7 +888,24 @@ final class Plugin {
|
||||
++self::$render_depth;
|
||||
|
||||
try {
|
||||
$result = $this->twig->render( $template . '.twig', $context );
|
||||
$template_path = $this->get_template_path( $template );
|
||||
|
||||
if ( ! file_exists( $template_path ) ) {
|
||||
throw new \Exception( "Template not found: {$template}" );
|
||||
}
|
||||
|
||||
// Extract context variables for use in template.
|
||||
// phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
extract( $context, EXTR_SKIP );
|
||||
|
||||
// Start output buffering.
|
||||
ob_start();
|
||||
|
||||
// Include the template.
|
||||
include $template_path;
|
||||
|
||||
// Get the rendered content.
|
||||
$result = ob_get_clean();
|
||||
} finally {
|
||||
--self::$render_depth;
|
||||
if ( $is_main_template ) {
|
||||
@@ -922,6 +916,17 @@ final class Plugin {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a partial template (helper for use within templates).
|
||||
*
|
||||
* @param string $partial Partial template name (without extension).
|
||||
* @param array $context Template context variables.
|
||||
* @return string Rendered partial.
|
||||
*/
|
||||
public function render_partial( string $partial, array $context = array() ): string {
|
||||
return $this->render( $partial, $context, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a post type instance.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user