-
Notifications
You must be signed in to change notification settings - Fork 227
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Prepare for rocket head ordering (#7304)
- Loading branch information
Showing
29 changed files
with
1,176 additions
and
235 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
<?php | ||
declare(strict_types=1); | ||
namespace WP_Rocket\Engine\Common\Head; | ||
|
||
/** | ||
* Element trait. | ||
*/ | ||
trait ElementTrait { | ||
/** | ||
* Preload link. | ||
* | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
protected function preload_link( array $args = [] ) { | ||
$args['rel'] = 'preload'; | ||
$args[] = 'data-rocket-preload'; | ||
return $this->link( $args ); | ||
} | ||
|
||
/** | ||
* Preconnect link. | ||
* | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
protected function preconnect_link( array $args = [] ) { | ||
$args['rel'] = 'preconnect'; | ||
return $this->link( $args ); | ||
} | ||
|
||
/** | ||
* Dns_prefetch link. | ||
* | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
protected function dns_prefetch_link( array $args = [] ) { | ||
$args['rel'] = 'dns-prefetch'; | ||
return $this->link( $args ); | ||
} | ||
|
||
/** | ||
* Prefetch link. | ||
* | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
protected function prefetch_link( array $args = [] ) { | ||
$args['rel'] = 'prefetch'; | ||
return $this->link( $args ); | ||
} | ||
|
||
/** | ||
* Prerender link. | ||
* | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
protected function prerender_link( array $args = [] ) { | ||
$args['rel'] = 'prerender'; | ||
return $this->link( $args ); | ||
} | ||
|
||
/** | ||
* Stylesheet link. | ||
* | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
protected function stylesheet_link( array $args = [] ) { | ||
$args['rel'] = 'stylesheet'; | ||
return $this->link( $args ); | ||
} | ||
|
||
/** | ||
* Style tag. | ||
* | ||
* @param string $css CSS content. | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
protected function style_tag( string $css = '', array $args = [] ) { | ||
$element = [ | ||
'open_tag' => '<style', | ||
]; | ||
$element += wp_parse_args( | ||
$args, | ||
[ | ||
'inner_content' => $css, | ||
] | ||
); | ||
$element['close_tag'] = '</style>'; | ||
|
||
return $element; | ||
} | ||
|
||
/** | ||
* Noscript tag. | ||
* | ||
* @param string $content Element contents. | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
protected function noscript_tag( string $content = '', array $args = [] ) { | ||
$element = [ | ||
'open_tag' => '<noscript', | ||
]; | ||
$element += wp_parse_args( | ||
$args, | ||
[ | ||
'inner_content' => $content, | ||
] | ||
); | ||
$element['close_tag'] = '</noscript>'; | ||
|
||
return $element; | ||
} | ||
|
||
/** | ||
* Generic link tag. | ||
* | ||
* @param array $args Element args. | ||
* @return array|string[] | ||
*/ | ||
private function link( array $args = [] ) { | ||
$element = [ | ||
'open_tag' => '<link', | ||
]; | ||
$element += wp_parse_args( | ||
$args, | ||
[ | ||
'href' => '', | ||
] | ||
); | ||
|
||
return $element; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<?php | ||
|
||
namespace WP_Rocket\Engine\Common\Head; | ||
|
||
use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; | ||
|
||
/** | ||
* Service provider. | ||
*/ | ||
class ServiceProvider extends AbstractServiceProvider { | ||
/** | ||
* Array of services provided by this service provider | ||
* | ||
* @var array | ||
*/ | ||
protected $provides = [ | ||
'common_head_subscriber', | ||
]; | ||
|
||
/** | ||
* Check if the service provider provides a specific service. | ||
* | ||
* @param string $id The id of the service. | ||
* | ||
* @return bool | ||
*/ | ||
public function provides( string $id ): bool { | ||
return in_array( $id, $this->provides, true ); | ||
} | ||
|
||
/** | ||
* Registers items with the container | ||
* | ||
* @return void | ||
*/ | ||
public function register(): void { | ||
$this->getContainer()->addShared( 'common_head_subscriber', Subscriber::class ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
<?php | ||
namespace WP_Rocket\Engine\Common\Head; | ||
|
||
use WP_Rocket\Event_Management\Subscriber_Interface; | ||
|
||
/** | ||
* Head subscriber class. | ||
*/ | ||
class Subscriber implements Subscriber_Interface { | ||
|
||
/** | ||
* Head elements array. | ||
* | ||
* @var array | ||
*/ | ||
private $head_items = []; | ||
|
||
/** | ||
* Returns an array of events that this subscriber wants to listen to. | ||
* | ||
* The array key is the event name. The value can be: | ||
* | ||
* * The method name | ||
* * An array with the method name and priority | ||
* * An array with the method name, priority and number of accepted arguments | ||
* | ||
* For instance: | ||
* | ||
* * array('hook_name' => 'method_name') | ||
* * array('hook_name' => array('method_name', $priority)) | ||
* * array('hook_name' => array('method_name', $priority, $accepted_args)) | ||
* * array('hook_name' => array(array('method_name_1', $priority_1, $accepted_args_1)), array('method_name_2', $priority_2, $accepted_args_2))) | ||
* | ||
* @return array | ||
*/ | ||
public static function get_subscribed_events() { | ||
return [ | ||
'rocket_buffer' => [ 'insert_rocket_head', 100000 ], | ||
'rocket_head' => 'print_head_elements', | ||
]; | ||
} | ||
|
||
/** | ||
* Print all head elements. | ||
* | ||
* @param string $content Head elements HTML. | ||
* @return string | ||
*/ | ||
public function print_head_elements( $content ) { | ||
/** | ||
* Filter Head elements array. | ||
* | ||
* @param array $head_items Elements to be added to head after closing of title tag. | ||
* | ||
* Priority 10: preconnect | ||
* Priority 30: preload | ||
* Priority 50: styles | ||
* @returns array | ||
*/ | ||
$items = wpm_apply_filters_typed( 'array', 'rocket_head_items', [] ); | ||
if ( empty( $items ) ) { | ||
return $content; | ||
} | ||
|
||
$this->head_items = []; | ||
// Combine elements. | ||
$elements = ''; | ||
foreach ( $items as $item ) { | ||
// Make sure that we don't have duplication based on `href` inside each `rel`. | ||
if ( $this->is_duplicate( $item ) ) { | ||
continue; | ||
} | ||
$elements .= "\n" . $this->prepare_element( $item ); | ||
} | ||
|
||
return $content . $elements; | ||
} | ||
|
||
/** | ||
* Check if the item is duplicate. | ||
* | ||
* @param array $item Item to check. | ||
* @return bool | ||
*/ | ||
private function is_duplicate( $item ) { | ||
if ( empty( $item['rel'] ) || empty( $item['href'] ) ) { | ||
return false; | ||
} | ||
|
||
if ( ! isset( $this->head_items[ $item['rel'] ] ) ) { | ||
$this->head_items[ $item['rel'] ] = []; | ||
} | ||
|
||
if ( ! isset( $this->head_items[ $item['rel'] ][ $item['href'] ] ) ) { | ||
$this->head_items[ $item['rel'] ][ $item['href'] ] = true; | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Prepare element HTML from the item array. | ||
* | ||
* @param array $element Item element. | ||
* @return string | ||
*/ | ||
private function prepare_element( $element ) { | ||
$open_tag = ''; | ||
if ( ! empty( $element['open_tag'] ) ) { | ||
$open_tag = $element['open_tag']; | ||
unset( $element['open_tag'] ); | ||
} | ||
|
||
$close_tag = ''; | ||
if ( ! empty( $element['close_tag'] ) ) { | ||
$close_tag = $element['close_tag']; | ||
unset( $element['close_tag'] ); | ||
} | ||
|
||
$inner_content = ''; | ||
if ( ! empty( $element['inner_content'] ) ) { | ||
$inner_content = $element['inner_content']; | ||
unset( $element['inner_content'] ); | ||
} | ||
|
||
$attributes = []; | ||
|
||
ksort( $element, SORT_NATURAL ); | ||
|
||
foreach ( $element as $key => $value ) { | ||
if ( is_int( $key ) ) { | ||
$attributes[] = $value; | ||
continue; | ||
} | ||
$attributes[] = $key . '="' . esc_attr( $value ) . '"'; | ||
} | ||
|
||
$attributes_html = ! empty( $attributes ) ? ' ' . implode( ' ', $attributes ) : ''; | ||
|
||
return $open_tag . $attributes_html . '>' . $inner_content . $close_tag; | ||
} | ||
|
||
/** | ||
* Insert rocket_head into the buffer HTML | ||
* | ||
* @param string $html Buffer HTML. | ||
* @return string | ||
*/ | ||
public function insert_rocket_head( $html ) { | ||
if ( empty( $html ) ) { | ||
return $html; | ||
} | ||
|
||
$filtered_buffer = preg_replace( | ||
'#</title>#iU', | ||
'</title>' . wpm_apply_filters_typed( 'string', 'rocket_head', '' ), | ||
$html, | ||
1 | ||
); | ||
|
||
if ( empty( $filtered_buffer ) ) { | ||
return $html; | ||
} | ||
|
||
return $filtered_buffer; | ||
} | ||
} |
Oops, something went wrong.