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

Implement Thank with Google tag placement infrastructure #5450

Closed
felixarntz opened this issue Jun 27, 2022 · 11 comments
Closed

Implement Thank with Google tag placement infrastructure #5450

felixarntz opened this issue Jun 27, 2022 · 11 comments
Assignees
Labels
Module: Thank with Google Thank with Google module related issues P0 High priority PHP Rollover Issues which role over to the next sprint Type: Enhancement Improvement of an existing feature

Comments

@felixarntz
Copy link
Member

felixarntz commented Jun 27, 2022

The TwG module should receive its PHP classes to place the relevant tags. Since it is currently impossible to complete the TwG module setup as the UI is not yet available, a code snippet should be used to allow testing of the tag placement (relevant e.g. for QA).

Code snippet to fake TwG module to have its setup completed:

function democode_return_completed_twg_configuration() {
    return array(
        // The first line is commented out since you can possibly already set a publication ID via the tester plugin.
        // If this is not yet available when doing QA here, you can alternatively set it via the following line.
        // 'publicationID' => 'TEST-PUBLICATION-ID',
        'colorTheme' => 'blue',
        'buttonPlacement' => 'dynamic_low',
        'buttonPostTypes' => array( 'post' ),
    );
}
add_filter( 'option_googlesitekit_thank-with-google_settings', 'democode_return_completed_twg_configuration' );
add_filter( 'default_option_googlesitekit_thank-with-google_settings', 'democode_return_completed_twg_configuration' );

Do not alter or remove anything below. The following sections will be managed by moderators only.

Acceptance criteria

  • A new Web_Tag class for the Thank with Google should be implemented, extending Module_Web_Tag.
  • In its register method:
    • It should add a wp_enqueue_scripts action in which the main script is registered. See corresponding section below the main ACs for details on that script. The script should only be actually enqueued if the current template is for a singular entity of one of the post types from the TwG buttonPostTypes option.
    • It should add a the_content filter some time after Gutenberg blocks have been parsed in which the inline TwG button placeholder is conditionally added to the content only if the current template is for a singular entity of one of the post types from the TwG buttonPostTypes option and if the TwG buttonPlacement option starts with static_. See corresponding section below the main ACs for details on that placeholder.
      • If static_auto or static_below-content: Append the placeholder to the content
      • If static_above-content: Prepend the placeholder to the content
      • If static_below-first-paragraph: Parse content to detect end of first p tag and inject the placeholder right after.
  • Its render method could either be used to render the placeholder or left empty if preferred from an engineering perspective.
  • It needs to be ensured that the button placeholder is never added to the content in a situation where the JS script is not enqueued also. However, the JS script should not be tied to the button placeholder being present in the content, since it will also be used in other cases (e.g. if button placement is dynamic or for the widget from Implement Thank with Google supporter wall widget #5451).
  • Since the tag will need access to all of the TwG colorTheme, buttonPlacement, and buttonPostTypes settings, the class will need to provide a way to get the values of those (e.g. setter methods).
  • A register_tag method should be added to the Thank_With_Google class and hooked into template_redirect. In this method, the new Web_Tag instance should be conditionally registered only if not AMP (if AMP, silently bail early as TwG does not support AMP), if the tag is not blocked, and based on the following tag guards:
    • Tag_Verify_Guard
    • Tag_Environment_Type_Guard

TwG JS snippet

  • The script handle should be google_thankjs.
  • The script should be registered version-less and in the footer, with URL: https://news.google.com/thank/js/v1/thank.js
  • It should also be prepended with an inline script as follows (without the comments of course, those are only for these ACs):
(self.SWG_BASIC = self.SWG_BASIC || []).push(subscriptions => {
  subscriptions.init({
    type: 'Blog',
    isPartOfType: ['Blog', 'Product'],
    isPartOfProductId: 'PUBLICATION-ID:default', // Replace PUBLICATION-ID with the actual publication ID.
    buttonPosition: 'inline', // If 'buttonPlacement' starts with 'static_', this should say 'inline'. Otherwise (i.e. it starts with 'dynamic_', this should say 'floating'.
    permalink: 'https://example.com/my-post/', // Replace this with the current permalink, or empty string if not a singular entity.
    pluginVersion: '1.80.0', // Replace this with the Site Kit plugin version.
    postTitle: 'My Post' // Replace this with the current post title, or empty string if not a singular entity.
  });
});

TwG button placeholder

  • The button placeholder snippet should be exactly as follows:
<div counter-button style="height: 34px; visibility: hidden; box-sizing: content-box; padding: 12px 0; display: inline-block; overflow: hidden;"></div>
<button twg-button style="height: 42px; visibility: hidden; margin: 12px 0;"></button>

Implementation Brief

  • Implement as per the AC. As the AC is already going into some implementation specifics, this IB will serve to provide some notes and clarify a few aspects of it that could use a bit of extra detail.

In file includes/Modules/Thank_With_Google/Web_Tag.php:

  • Create a new Web_Tag class that extends Module_Web_Tag.
    • See existing Web_Tag classes for examples, e.g. includes/Modules/Analytics/Web_Tag.php.
  • Add instance variables and setter methods for buttonPlacement and buttonPostTypes, as these values are explictly referenced in the AC. An instance variable and setter for colorTheme can be added as and when it's needed.
  • Create the register method. Within this method:
    • Add a wp_enqueue_scripts action hook.
    • The handler for wp_enqueue_scripts should be the enqueue_gtag_script method.
    • Add a the_content filter hook with a value above 9 for the priority, with the method update_the_content as the handler.
      • Note: This is necessary in order to add the filter after the Gutenberg blocks have been parsed. As can be seen here, the do_blocks function is added as a filter hook with priority 9, so any the_content hook with a higher priority will be executed after the blocks are parsed. It's worth adding a comment to the code to clarify this when it comes to implementation.
    • Invoke the do_init_tag_action() method to initialise the tag.
  • Create the enqueue_gtag_script method. Within this method.
    • Register the script using wp_register_script, with script details as listed under TwG JS snippet in the AC.
    • To check the current template is for a singular entity of one of the post types from the TwG buttonPostTypes option, use is_singular( $buttonPostTypes ). Note that $buttonPostTypes should be an array of post types.
    • If the current template is for a singular entity of one of the buttonPostTypes then enqueue the script using wp_enqueue_script specifying only the script handle and no other arguments.
    • Call wp_add_inline_script to prepend the inline script as specified under TwG JS snippet in the AC:
      • Use the $position parameter of wp_add_inline_script with value 'before' to prepend the inlined script.
      • Use GOOGLESITEKIT_VERSION for the current plugin version.
      • Use is_singular() to check if the current entity is a singular entity.
      • Use get_permalink() to retrieve the current permalink.
      • Use get_the_title() to retrieve the current post title.
  • Create the update_the_content method with a single parameter, $content. Within this method:
    • If the current template is not for a singular entity of one of the buttonPostTypes (i.e. ! is_singular( $buttonPostTypes )) bail out early.
    • Refer to the TwG button placeholder section in the AC for the placeholder content.
    • If the buttonPlacement TwG setting is static_auto or static_below-content, return $content appended with the placeholder.
    • If buttonPlacement is static_above-content, return $content prepended with the placeholder.
    • If buttonPlacement is static_below-first-paragraph:
      • Determine the location of the end of the first paragraph, by searching for the substring </p> in the content (this should be sufficient - it should not be necessary to use an HTML parser).
      • Using substring manipulation, return the content with the placeholder inserted immediately after the end of the </p>.
  • Feel free to create a render method to return the actual placeholder content, or simply create the placeholder directly within update_the_content.

In file includes/Modules/Thank_With_Google.php:

  • Within the register method:
    • Add a template_redirect action hook, with the method register_tag as the handler.
  • Create the register_tag method. Within this method:
    • See existing module classes for examples of register_tag for example includes/Modules/Analytics.php.
    • Bail out early under the following conditions:
      • If in AMP mode (check $this->context->is_amp() to determine AMP status).
      • If the tag is blocked (check the is_tag_blocked() method).
    • Following the example seen in Modules::Analytics::register_tag:
      • Set up the Tag_Verify_Guard and Tag_Environment_Type_Guard tag guards.
      • Check if the tag can be registered with the can_register method, and if so:
      • Set up the settings via their setter methods.
      • Register the tag via the register method.

Test Coverage

  • Add tests to the existing Thank_With_Google PHPUnit integration tests to check the scripts are enqueued & inlined.

QA Brief

Setup

  • To connect the TwG Module:
  • Add the PHP snippet to a mu-plugin or themes function.php.
function democode_return_completed_twg_configuration(  ) {
  return array(
      'publicationID' => 'TEST-PUBLICATION-ID',
      'colorTheme' => 'blue',
      'buttonPlacement' => 'dynamic_low',
      'buttonPostTypes' => array( 'post' ),
  );
}
add_filter( 'option_googlesitekit_thank-with-google_settings', 'democode_return_completed_twg_configuration' );
  • Go to Settings > Connect More Services > Setup Thank with Google.
  • At this point, we have no way to continue.
  • Go to Settings > Connected Services. The TwG module should show 'Thank with Google is not connected'.
  • Paste the following snippet to browser console.
googlesitekit.data
	.dispatch( 'modules/thank-with-google' )
	.setPublicationID( 'Test-Pub_id' )
	.then( () =>
		googlesitekit.data
			.dispatch( 'modules/thank-with-google' )
			.saveSettings()
	)
	.then( () => window.location.reload() );
  • Page should refresh and TwG module should now be on connected status.

QA

  • See the source code of the Single Post url fot the JS Snippet.
    • The Tag will be near the closing of the body tag and wrapped by Thank with Google snippet added by Site Kit html comments.
  • See the source code for the button placeholder code.
    • Check with 'buttonPlacement' => 'static_auto',: The snippet will be after the post content.
    • Check with 'buttonPlacement' => 'static_below-content',: The snippet will be after the post content.
    • Check with 'buttonPlacement' => 'static_above-content',: The snippet will be before the post content.
    • Check with 'buttonPlacement' => 'static_below-first-paragraph',: The snippet will be after first paragraph of the content.
    • To change the buttonPlacement just change it in the mu-plugin in the first PHP snippet after setup.

Changelog entry

  • Implement Thank with Google tag placement infrastructure.
@felixarntz felixarntz added P0 High priority Type: Enhancement Improvement of an existing feature Module: Thank with Google Thank with Google module related issues labels Jun 27, 2022
@felixarntz felixarntz self-assigned this Jun 27, 2022
@felixarntz felixarntz removed their assignment Jun 27, 2022
@kuasha420 kuasha420 self-assigned this Jun 29, 2022
@techanvil techanvil assigned techanvil and unassigned techanvil Jul 6, 2022
@eugene-manuilov eugene-manuilov self-assigned this Jul 11, 2022
@eugene-manuilov
Copy link
Collaborator

eugene-manuilov commented Jul 11, 2022

Thanks, @techanvil. Added a few comments for you. In general, I would like to ask you to use more verbose IB in the future because this one is hard to follow. I was needed to jump back and forth between IB and AC to figure out what exactly needs to be done and which section in AC IB refers to. When you write an IB think of an engineer that has never worked with this module/code before, they need to be able to understand what needs to be done by reading IB only.

  • Use the $in_footer parameter of wp_enqueue_script with value true to place the script in the footer.
  • Use the $position parameter of wp_add_inline_script with value 'before' to prepend the inlined script

The script should be registered by default and enqueued only if the current page type is allowed.

  • For access to the TwG settings, ensure the TwG module settings are passed into the Web_Tag constructor and retained as an instance variable. Then add getters for the individual settings.

We should better use setters and getters for settings that are required only instead of passing all settings to the tag. This will make phpunit testing simpler. See how we do it for the Web_Tag class in the Analytics module.

  • As to the question of whether to make use of the render method, it looks like not doing so would be consistent with existing code where the script is enqueued - e.g. see the comment in render in the Analytics Web_Tag class.

We need to use the render method (which should render the TwG button placeholder) as a hook for the the_content filter. The Web_Tag class for Analytics is more of an edge case, see how Web_Tag is implemented for Tag Manager where we use `render as a hook for an action.

@techanvil
Copy link
Collaborator

techanvil commented Jul 11, 2022

Hi @eugene-manuilov, thanks for your review. I hope you don't mind, in response to your feedback about this being hard to follow I've rewritten the IB a bit to be more verbose and hopefully easier to follow.

  • Use the $in_footer parameter of wp_enqueue_script with value true to place the script in the footer.
  • Use the $position parameter of wp_add_inline_script with value 'before' to prepend the inlined script

The script should be registered by default and enqueued only if the current page type is allowed.

Thanks for pointing this out! I've amended the IB to be specific about this point, using wp_register_script to unconditionally register the script.

  • For access to the TwG settings, ensure the TwG module settings are passed into the Web_Tag constructor and retained as an instance variable. Then add getters for the individual settings.

We should better use setters and getters for settings that are required only instead of passing all settings to the tag. This will make phpunit testing simpler. See how we do it for the Web_Tag class in the Analytics module.

Thanks for this too, I have updated the IB accordingly.

  • As to the question of whether to make use of the render method, it looks like not doing so would be consistent with existing code where the script is enqueued - e.g. see the comment in render in the Analytics Web_Tag class.

We need to use the render method (which should render the TwG button placeholder) as a hook for the the_content filter. The Web_Tag class for Analytics is more of an edge case, see how Web_Tag is implemented for Tag Manager where we use `render as a hook for an action.

Having looked into this I don't see render being appropriate here, as the hook for the_content needs to takes a $content parameter, but the abstract render method has no params and PHP complains when trying to implement it with a different signature. I've left a point in the IB about leaving it up to the implementer to potentially use render for the placeholder, but it would still need to be invoked from the the_content handler.

@eugene-manuilov
Copy link
Collaborator

Hi @eugene-manuilov, thanks for your review. I hope you don't mind, in response to your feedback about this being hard to follow I've rewritten the IB a bit to be more verbose and hopefully easier to follow.

Thanks, @techanvil. IB is excellent now 🙌. IB ✔️

  • As to the question of whether to make use of the render method, it looks like not doing so would be consistent with existing code where the script is enqueued - e.g. see the comment in render in the Analytics Web_Tag class.

We need to use the render method (which should render the TwG button placeholder) as a hook for the the_content filter. The Web_Tag class for Analytics is more of an edge case, see how Web_Tag is implemented for Tag Manager where we use `render as a hook for an action.

Having looked into this I don't see render being appropriate here, as the hook for the_content needs to takes a $content parameter, but the abstract render method has no params and PHP complains when trying to implement it with a different signature. I've left a point in the IB about leaving it up to the implementer to potentially use render for the placeholder, but it would still need to be invoked from the the_content handler.

Ah... you are definitely right. I forgot about the content parameter 🤦... Looks good then! 👍

@eugene-manuilov eugene-manuilov removed their assignment Jul 11, 2022
@eugene-manuilov
Copy link
Collaborator

@techanvil, fyi I have updated IB a little bit to satisfy requirements for the #5451 ticket.

@kuasha420 kuasha420 self-assigned this Jul 12, 2022
@eclarke1 eclarke1 added the Rollover Issues which role over to the next sprint label Jul 18, 2022
@kuasha420 kuasha420 removed their assignment Jul 19, 2022
@kuasha420 kuasha420 removed their assignment Jul 19, 2022
@eugene-manuilov eugene-manuilov removed their assignment Jul 21, 2022
@wpdarren wpdarren self-assigned this Jul 21, 2022
@wpdarren
Copy link
Collaborator

@kuasha420 are you able to provide additional information on the code in the ticket description to complete TwG setup.

Within the console I have pasted this code:

function democode_return_completed_twg_configuration() {
    return array( 'publicationID' => 'abc12345',
        'colorTheme' => 'blue',
        'buttonPlacement' => 'dynamic_low',
        'buttonPostTypes' => array( 'post' ),
    );
}
add_filter( 'option_googlesitekit_thank-with-google_settings', 'democode_return_completed_twg_configuration' );
add_filter( 'default_option_googlesitekit_thank-with-google_settings', 'democode_return_completed_twg_configuration' );

Since we are unable to set a publicationID within the tester plugin (all we can do is force a status) I removed the comments and made sure that the publicationID was included. Looking at the design documentation the publicationID can be any string at the moment so just added abc12345.

I pasted the code within the settings and also various other places. Every time the error appears:

Uncaught SyntaxError: Malformed arrow function parameter list

This is the first time we're testing the set up of TwG so need a little direction. Please could you provide instructions for us to complete the TwG setup? Thank you.

@kuasha420
Copy link
Contributor

Oh crap, Did I say console? You have to add the code in a mu-plugin or the themes 'function.php'. Apologies!!!

@kuasha420 kuasha420 removed their assignment Jul 21, 2022
@wpdarren
Copy link
Collaborator

wpdarren commented Jul 21, 2022

@kuasha420 to be fair that was just my assumption 🤦‍♂️ Now you've said this, it totally helps. Thank you!

@wpdarren
Copy link
Collaborator

wpdarren commented Jul 22, 2022

QA Update: ⚠️

@kuasha420 as per our conversation on Slack. I am not seeing the snippet in the source code.

I've assigned it back to you to investigate.

@wpdarren wpdarren assigned kuasha420 and unassigned wpdarren Jul 22, 2022
@kuasha420 kuasha420 assigned wpdarren and unassigned kuasha420 Jul 22, 2022
@wpdarren
Copy link
Collaborator

QA Update: ✅

Verified:

  • I can see the source code of the Single Post url for the JS Snippet.
  • The Tag is near the closing of the body tag and wrapped by Thank with Google snippet added by Site Kit

image

  • I can see the source code for the button placeholder code.
    Check with 'buttonPlacement' => 'static_auto',: The snippet will be after the post content.
    Check with 'buttonPlacement' => 'static_below-content',: The snippet will be after the post content.
    Check with 'buttonPlacement' => 'static_above-content',: The snippet will be before the post content.
    Check with 'buttonPlacement' => 'static_below-first-paragraph',: The snippet will be after first paragraph of the content.

  • I was able to change the code above in the functions.php to see the snippet.

image
image

@wpdarren wpdarren removed their assignment Jul 25, 2022
@felixarntz
Copy link
Member Author

@kuasha420 @eugene-manuilov Minor nit-pick here in terms of approval: #5565 (review)

This is not a bug or anything critical, but something to clean up. If you could address it in a quick follow-up PR against main, that would be great.

@eugene-manuilov
Copy link
Collaborator

Good catch, @felixarntz. I have created a follow up PR #5616, do you mind reviewing it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Module: Thank with Google Thank with Google module related issues P0 High priority PHP Rollover Issues which role over to the next sprint Type: Enhancement Improvement of an existing feature
Projects
None yet
Development

No branches or pull requests

6 participants