Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LazyLoad CSS Background Images #5987

Closed
piotrbak opened this issue Jun 18, 2023 · 3 comments · Fixed by #6039 or #6128
Closed

LazyLoad CSS Background Images #5987

piotrbak opened this issue Jun 18, 2023 · 3 comments · Fixed by #6039 or #6128
Assignees
Labels
effort: [XL] > 10 days of estimated development time epics 🔥 needs: documentation Issues which need to create or update a documentation type: new feature Indicates the issue is a request for new functionality
Milestone

Comments

@piotrbak
Copy link
Contributor

Is your feature request related to a problem? Please describe.
This is GitHub part of the new feature described here.

Additional context
Acceptance Criteria and all details are listed in the above link.

@piotrbak piotrbak added type: new feature Indicates the issue is a request for new functionality needs: grooming needs: documentation Issues which need to create or update a documentation epics 🔥 labels Jun 18, 2023
@piotrbak piotrbak added this to the 3.15 milestone Jun 18, 2023
@CrochetFeve0251 CrochetFeve0251 added GROOMING IN PROGRESS Use this label when the issue is currently being groomed. and removed needs: grooming labels Jun 19, 2023
@CrochetFeve0251
Copy link
Contributor

CrochetFeve0251 commented Jun 19, 2023

To add this feature we will have to do the following parts:

  • Modify UIs.
  • Add actual logic to the caching logic.
  • Save data files on the file system.

UI

First we will start by modifying UIs.
For that we have two interfaces to modify.

The first one is on the settings page.
For we will have modify the class Page.

On line 1097 we will have add a new section as following:

					'container_class'   => [
						! empty( $disable_css_bg_img_lazyload ) ? 'wpr-isDisabled' : '',
						'wpr-isParent',
					],
					'type'              => 'checkbox',
					'label'             => __( 'Enable for CSS background images', 'rocket' ),
					'section'           => 'lazyload_section',
					'page'              => 'media',
					'default'           => 0,
					'sanitize_callback' => 'sanitize_checkbox',
					'input_attr'        => [
						'disabled' => ! empty( $disable_css_bg_img_lazyload ) ? 1 : 0,
					],

Then line 1023 we will have to add the following code to allow disabling the feature: 

		$disable_css_bg_img_lazyload = (array) apply_filters( 'rocket_maybe_disable_css_bg_img_lazyload_helper', $disable_css_bg_img_lazyload );
		$disable_css_bg_img_lazyload = $this->sanitize_and_format_list( $disable_css_bg_img_lazyload );

Finally we will have to change the description from the exclusion box line 1137 to "Specify keywords (e.g. image filename, CSS filename, CSS class, domain) from the image or iframe code to be excluded (one per line)"And add "background-image-style.css" to the placeholder line 1141:

'placeholder' => "example-image.jpg\nslider-image",

Then we will have to change the meta boxes.

For that we will have to add a filter into metaboxes.php at line 102 to register filters without having to modify the file.

Then inside the Admin subscriber from the lazyload bg css we will have the following logic:

public function add_meta_box(array $fields) {  
       $fields['disable_css_bg_img_lazyload'] = __('LazyLoad CSS backgrounds', 'rocket');
}

Business logic

Then we will have to add the actual logic.
First we will have to create a Subscriber WP_Rocket\Engine\Medoa\Lazyload\CSS\Subscriber that will handle all the business logic.
For that it will take as parameter the instance of the optimized filesystem we will create in the last part.
Then it will provide 4 public methods:

  • maybe_replace_css_images(string $html): string that will be linked to the rocket_buffer filter.
  • clear_generated_css that should be linked to after_rocket_clean_domain
  • clear_generate_css_post(WP_POST $post) that should be linked to after_rocket_clean_post
  • insert_lazyload_script that should be linked to wp_enqueue_scripts

Inside the method maybe_replace_css_images we will have do the following actions:

  • Check the current post ID with the filter rocket_lazyload_css_background to bail out if it excluded.
    -We will call the filter rocket_generate_lazyloaded_css that takes data as parameter which will have 5 callbacks:
  • One to extract CSS files from html that will reusable and so will be attached to a subscriber inside  the Common folder
  • One to inline CSS that will be reusable and so will be attached to a subscriber inside  the Common folder
  • One to Create Lazy files from the CSS files extracted and that will be present on the same subscriber.
  • One to create the Lazy inline CSS and that will be present on the same subscriber.
  • Finally one to create the actual tag and add it to the html content.

Order between hooks needs to be handled by priority and the order should be the following one:

  • Extract CSS file
  • Create Lazy for CSS files
  • Extract inline CSS
  • Create Lazy for CSS inline
  • Generating tag

The parameter will have the following structure:

[
   'html' => 'content',
   'css_files' => [
      'url' 
  ],
  'css_inline' => [
   'css',   
],
  'lazyloaded_images' => [
    
  ]'
]

Extract CSS

To extract CSS we gonna base ourselves on the logic present inside the RUCSS:

Once this logic extracted we will then create a subscriber that will provide two method:

  • extract_css_files_from_html that will extract all CSS files.
  • extract_inline_css_from_html that will extract all inline CSS.

Both will be registered to the rocket_generate_lazyloaded_css filter and take $data as parameter.

Create Lazy

To extract the CSS we gonna use the preg_replace_callbackinside an class Extractor with two regex:

  • (?<selector>[ \w.#]+)\s{[^}]*background(-image)?\s*:(?<property>[^;]*)[^}]*}: to find the selector and the property.
  • (?<tag>url\(['"](?<url>[^\)]*)['"]\)): to get each url and the tag to replace with the placholder.

While parsing we need to check if the file already exists using the filesystem and skip the creation from the lazyfile and reuse the old one.

Once parsed we will then create an array mapping the selector and the url value and we will swap the URL with its matching variable in the CSS file.
We wil also have to call rocket_lazyload_excluded_src and exclude each url from images that should be excluded.

Then we will save the CSS file into the filesystem using the Optimized filesystem and we will do the same for the array mapping the selector and the url that will be named same as the CSS file with .json at its end.

Finally we will replace the name for each CSS file with the one of its new generated CSS file inside the HTML and do same for the inline CSS.

Generating tag

To generate the tag we will use the lazyloaded mapping given by the $data that we will pass into rocket_css_image_lazyload_images_load filter that will be used later on.
This filter will take an empty array as parameter and will return images that would be loaded as soon as the page loads.

Then we will use an class TagGenerator to generate different tags we will have to add on the page:

  • generate_script_tag: This method will take as parameters an array mapping the selector and the url for all CSS files and inline inside the page and an id to generate a script tag with a variable storing them.
  • generate_style_tag: This method will take as parameters an array mapping the selector and the url for all CSS files and inline, an id and a boolean indicating if the tag is wrapped inside a no-script tag.

Filesystem

The last part is the filesystem.
This filesystem should implement psr16 to make it possible to potentially replacing it in the future.
This filesystem will be used to store urls inside the cache folder.
It will create a file on the filesystem based on a key that is the local url from the file.

As a class it will take two parameters:

  • The root folder which will be cache/background-css (The part background-css will be liked to the filter rocket_css_image_lazyload_saving_root_path)
  • The filesystem.

The object should provide methods from the PSR-16 convention and rely on previously implemented function for its internal processing.

To this we will add a method generate_url that will resolve the actual URL from the actual file inside the filesystem with the name of the URL we would like to save.

Logger

Most of the classes will have to use the Logger to simplify debugging.

To reduce the workload to work with it we will use an inflector.

To do this we will create an interface UseLoggerInterface with the following content:

interface UseLoggerInterface {
 public function set_logger(Logger $logger);
]

And a trait UseLogger with the following content:

trait UseLogger {
  protected $logger;

   public function set_logger(Logger $logger) {
     $this->logger = $logger;
   }
}

Then we will have to create the inflector itself.

For that we will create a service provider that we will load before every other one which gonna register the logger and the inflector inside its register method:

$container->add('logger', Logger::class');
$container
    ->inflector(UseLoggerInterface::class)
    ->invokeMethod('set_logger', ['logger']);

@CrochetFeve0251 CrochetFeve0251 added effort: [XL] > 10 days of estimated development time and removed GROOMING IN PROGRESS Use this label when the issue is currently being groomed. labels Jun 20, 2023
@Tabrisrp
Copy link
Contributor

We should be able to split this in at least 3 different sub-tasks

@CrochetFeve0251
Copy link
Contributor

We should be able to split this in at least 3 different sub-tasks

Yes I told @piotrbak I first wait for you review then I gonna split it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
effort: [XL] > 10 days of estimated development time epics 🔥 needs: documentation Issues which need to create or update a documentation type: new feature Indicates the issue is a request for new functionality
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants