'form' === $kind ? [ 'default' ] : $ids, 10, 2 ); */ class StyleManager { // The form style that loads no Remaily styles: the theme styles the form const THEME = 'theme'; /** * Child theme, parent theme, plugin, then add-ons * * @return array [ [ path, url ], … ] */ public static function roots() { $relative = 'remaily/'; $roots = [ [ trailingslashit( get_stylesheet_directory() ) . $relative, trailingslashit( get_stylesheet_directory_uri() ) . $relative ] ]; if ( get_template_directory() !== get_stylesheet_directory() ) { $roots[] = [ trailingslashit( get_template_directory() ) . $relative, trailingslashit( get_template_directory_uri() ) . $relative ]; } $roots[] = [ REMAILY_PATH . 'templates/', REMAILY_URL . 'templates/' ]; /** * Template folders after the theme's and the plugin's: an add-on's own (its field types), which a theme's * remaily/ folder still overrides * * add_filter( 'remaily_template_roots', fn( $roots ) => array_merge( $roots, [ [ MY_PATH . 'templates/', MY_URL . 'templates/' ] ] ) ); * * @param array $roots [ [ path, url ], … ] */ return (array) apply_filters( 'remaily_template_roots', $roots ); } /** * Locate a file in the templates tree * * @param string $relative Path, e.g. fields/input/default/field.php * * @return array|null [ path, url ] */ public static function locate_file( $relative ) { // No way out of the tree if ( !preg_match( '#^[a-z0-9_-]+(?:/[a-z0-9_-]+)*\.(?:php|css|js|svg)$#', $relative ) ) { return null; } $found = null; foreach ( self::roots() as [ $path, $url ] ) { if ( is_file( $path . $relative ) ) { $found = [ $path . $relative, $url . $relative ]; break; } } // [ path, url ] $found = apply_filters( 'remaily_template', $found, $relative ); return is_array( $found ) && !empty( $found[0] ) && is_file( $found[0] ) ? $found : null; } /** * Render a template * * @param string $relative Path, e.g. mail/html.php * @param array $vars Variables * * @return string */ public static function render_template( $relative, array $vars ) { ob_start(); self::print_template( $relative, $vars ); return (string) ob_get_clean(); } /** * Print a template; it escapes what it prints * * @param string $relative Path in templates/ * @param array $vars Variables */ public static function print_template( $relative, array $vars ) { $template = self::locate_file( $relative ); if ( !$template ) { return; } $vars = (array) apply_filters( 'remaily_template_vars', $vars, $relative ); ( static function ( $__template, $__vars ) { extract( $__vars, EXTR_SKIP ); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract include $__template; } )( $template[0], $vars ); } /** * An icon of templates/icons/, the theme's copy first * * @param string $name File name without .svg * @param string $class Class added to the * * @return string SVG markup, hidden from screen readers ('' when there is no such icon) */ public static function icon( $name, $class = '' ) { static $cache = []; $key = $name . '|' . $class; if ( !isset( $cache[ $key ] ) ) { $file = self::locate_file( 'icons/' . sanitize_key( $name ) . '.svg' ); $svg = $file ? trim( (string) file_get_contents( $file[0] ) ) : ''; // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- a local file $svg = preg_replace( '#^.*?(?=])#s', '', $svg ); if ( $svg ) { $svg = preg_replace( '#^