$data Optional. Variables exposed to the template. Default empty. */ public static function render( string $template, array $data = array() ): void { $file = self::locate( $template ); if ( '' === $file ) { return; } // phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- Scoped to the template data. extract( $data, EXTR_SKIP ); require $file; } /** * Returns a rendered template as a string. * * @param string $template Template path relative to the templates directory. * @param array $data Optional. Variables exposed to the template. Default empty. */ public static function get( string $template, array $data = array() ): string { ob_start(); self::render( $template, $data ); return (string) ob_get_clean(); } /** * Locates a template, preferring theme overrides. * * @param string $template Template path relative to the templates directory. * * @return string The absolute template path, or an empty string when missing. */ public static function locate( string $template ): string { $template = ltrim( wp_normalize_path( $template ), '/' ); if ( ! str_ends_with( $template, '.php' ) ) { $template .= '.php'; } /* * Every internal caller passes a literal, and the only ways to reach this * with something else are `formpilot_field_template` and `formpilot_template_path` — * both trusted extension points. That is an argument for not worrying, not * an argument for the check being absent: a name is a name, and one that * climbs out of the templates directory is not one. */ if ( str_contains( $template, '..' ) || str_contains( $template, "\0" ) ) { return ''; } /* * Only frontend templates may be overridden by a theme. * * `locate_template()` was asked about every template, admin ones included, * so a file at `your-theme/formpilot-builder/admin/forms/edit.php` * silently replaced the builder's own markup — an override nobody * documented, on screens whose escaping and nonce handling the plugin is * responsible for. Theme overrides are a frontend feature and now say so. */ $override = str_starts_with( $template, 'admin/' ) ? '' : locate_template( array( trailingslashit( self::THEME_DIRECTORY ) . $template, ) ); $file = '' !== $override ? $override : FORMPILOT_PLUGIN_DIR . 'templates/' . $template; /** * Filters the resolved template path. * * @since 1.0.0 * * @param string $file Absolute template path. * @param string $template Requested template, relative to the templates directory. */ $file = (string) apply_filters( 'formpilot_template_path', $file, $template ); return is_readable( $file ) ? $file : ''; } }