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

PoC: RRM Gutenberg Blocks #10247

Draft
wants to merge 13 commits into
base: develop
Choose a base branch
from
43 changes: 43 additions & 0 deletions blocks/reader-revenue-manager/common/EditorButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Site Kit by Google, Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* External dependencies
*/
import classnames from 'classnames';

/**
* Internal dependencies
*/
import GoogleLogoIcon from '../../../assets/svg/graphics/logo-g.svg';

export default function EditorButton( { children, disabled } ) {
return (
<button
disabled={ disabled }
className={ classnames(
'googlesitekit-blocks-reader-revenue-manager-button',
{
'googlesitekit-blocks-reader-revenue-manager-button--disabled':
disabled,
}
) }
>
<GoogleLogoIcon height="18" width="18" />
{ children }
</button>
);
}
17 changes: 17 additions & 0 deletions blocks/reader-revenue-manager/common/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Site Kit by Google, Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export const CORE_EDITOR = 'core/editor';
43 changes: 43 additions & 0 deletions blocks/reader-revenue-manager/common/editor-styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Contribute/Subscribe with Google block editor styles.
*
* Site Kit by Google, Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// Styles copied over from the actual inline button.
.googlesitekit-blocks-reader-revenue-manager-button {
align-items: center;
background-color: #fff;
border: 1px solid #dadce0;
border-radius: 4px;
color: #1a73e8;
display: flex;
font-family: "Google Sans", Roboto-Regular, sans-serif, arial;
font-size: 14px;
font-weight: 500;
justify-content: center;
letter-spacing: 0.014px;
outline: 0;
padding: 12px 34px;

svg {
margin-right: 8px;
}

&.googlesitekit-blocks-reader-revenue-manager-button--disabled {
filter: grayscale(50%);
opacity: 0.5;
}
}
17 changes: 17 additions & 0 deletions blocks/reader-revenue-manager/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Site Kit by Google, Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export { default as EditorButton } from './EditorButton';
141 changes: 141 additions & 0 deletions blocks/reader-revenue-manager/contribute-with-google/Edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/**
* Site Kit by Google, Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* WordPress dependencies
*/
import { useBlockProps, InspectorControls } from '@wordpress-core/block-editor';
import { ExternalLink, Notice } from '@wordpress-core/components';
import { createInterpolateElement, Fragment } from '@wordpress-core/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { EditorButton } from '../common';
import { CORE_EDITOR } from '../common/constants';
import { CORE_MODULES } from '../../../assets/js/googlesitekit/modules/datastore/constants';
import { MODULES_READER_REVENUE_MANAGER } from '../../../assets/js/modules/reader-revenue-manager/datastore/constants';

/**
* Contribute with Google Block Edit component.
*
* @since n.e.x.t
*
* @param {Object} props Component props.
* @param {Object} props.select Data store select function.
* @return {Element} Element to render.
*/
export default function Edit( { select } ) {
const blockProps = useBlockProps();

const hasModuleAccess = select( CORE_MODULES ).hasModuleOwnershipOrAccess(
'reader-revenue-manager'
);

const settings = select( MODULES_READER_REVENUE_MANAGER ).getSettings();

const { publicationID, paymentOption, snippetMode, postTypes } = settings;

const serviceURL = select( MODULES_READER_REVENUE_MANAGER ).getServiceURL( {
path: 'reader-revenue-manager',
query: {
publication: publicationID,
},
} );

const metaKey = `googlesitekit_rrm_${ publicationID }:productID`;

const postProductID =
select( CORE_EDITOR ).getEditedPostAttribute( 'meta' )?.[ metaKey ] ||
'';
const postType = select( CORE_EDITOR ).getCurrentPostType();

let notice = '';
let disabled = false;

if ( paymentOption !== 'contributions' ) {
disabled = true;

if ( hasModuleAccess ) {
notice = createInterpolateElement(
__(
'You need to set up a contributions request in Reader Revenue Manager to use this block. <a>Go to Reader Revenue Manager</a>',
'google-site-kit'
),
{
a: <ExternalLink href={ serviceURL } />,
}
);
} else {
notice = __(
'You need to set up a contributions request in Reader Revenue Manager to use this block. Contact your administrator.',
'google-site-kit'
);
}
}

if (
postProductID === 'none' ||
( ! postProductID && snippetMode === 'per_post' ) ||
( ! postProductID &&
snippetMode === 'post_types' &&
! postTypes.includes( postType ) )
) {
disabled = true;

if ( hasModuleAccess ) {
notice = createInterpolateElement(
__(
'This post does not include the Reader Revenue Manager snippet. Configure the snippet for this post in the post settings sidebar.',
'google-site-kit'
),
{
a: <ExternalLink href={ serviceURL } />,
}
);
} else {
notice = __(
'This post does not include the Reader Revenue Manager snippet. Contact your administrator',
'google-site-kit'
);
}
}

return (
<Fragment>
{ notice && (
<InspectorControls>
<div className="block-editor-block-card">
<Notice status="warning" isDismissible={ false }>
{ notice }
</Notice>
</div>
</InspectorControls>
) }
<div { ...blockProps }>
<div className="googlesitekit-blocks-reader-revenue-manager">
<EditorButton disabled={ disabled }>
{
/* translators: Button label for Contribute with Google. See: https://github.com/subscriptions-project/swg-js/blob/05af2d45cfcaf831a6b4d35c28f2c7b5c2e39308/src/i18n/swg-strings.ts#L58-L91 (see latest version) */
__( 'Contribute with Google', 'google-site-kit' )
}
</EditorButton>
</div>
</div>
</Fragment>
);
}
12 changes: 12 additions & 0 deletions blocks/reader-revenue-manager/contribute-with-google/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "google-site-kit/rrm-contribute-with-google",
"version": "n.e.x.t",
"title": "Contribute with Google",
"category": "widgets",
"icon": "google",
"description": "Allow users to make voluntary contributions using Reader Revenue Manager.",
"textdomain": "google-site-kit",
"editorStyle": "blocks-reader-revenue-manager-editor-styles"
}
48 changes: 48 additions & 0 deletions blocks/reader-revenue-manager/contribute-with-google/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Site Kit by Google, Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* WordPress dependencies
*/
import { registerBlockType } from '@wordpress-core/blocks';

/**
* Internal dependencies
*/
import Data, { select, resolveSelect } from 'googlesitekit-data';
// We need to import `registerStore` from `./modules/reader-revenue-manager/datastore` rather than `./modules/reader-revenue-manager`
// to avoid pulling in all the other modules imported in the top-level RRM module.
import { registerStore } from '../../../assets/js/modules/reader-revenue-manager/datastore';
import { CORE_MODULES } from '../../../assets/js/googlesitekit/modules/datastore/constants';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having to reach into assets like this makes me think blocks should have been a subdirectory of assets/js, after all these are still JS assets... And, it would be more closely aligned with the workspace structure.

Maybe one to discuss with the team and/or at the next eng leads sync...

Cc @tofumatt @eugene-manuilov @aaemnnosttv

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@techanvil @nfmohit CORE_MODULES and registerStore should be imported from googlesitekit-* package like we do it with googlesitekit-data. If we can't do it right now, then we need to update our assets to be able to do that. Then we will need to add the rrm module script as a dependency to this block script.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eugene-manuilov, I'm not sure we want to include the full googlesitekit-modules-reader-revenue-manager JS asset on the posts page, as it will contain code and components that we don't want to and indeed can't use due to the differing React versions between our NPM-installed @wordpress/element and that of the external @wordpress-core/element (and possibly some other dependency version clashes).

It could arguably be worthwhile though, either if the commonalities between the RRM block editor asset and the main RRM module grow large enough, or we just figure that browser-side caching of the asset makes it efficient to reuse on the posts page anyway.

If so, we'll need to restructure the asset to avoid unwanted initialisation that is not relevant to the posts page.

If we decide to keep the two separate, it would still be nice to figure out a way to import from googlesitekit-* packages, but we'd probably need to introduce packages and entry points for shared RRM and other relevant module code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the input here, folks!

As we have a working PoC with the assets not restructured, let's go ahead and use them as they are now. Let's revisit this on our next engineering leads sync. Thanks!

import { MODULES_READER_REVENUE_MANAGER } from '../../../assets/js/modules/reader-revenue-manager/datastore/constants';
import metadata from './block.json';
import Edit from './Edit';

registerStore( Data );

// Since we aren't currently able to use `useSelect()` in the components,
// we need to resolve selectors before registering the block
// to ensure the data is available when the block is rendered.
Promise.all( [
resolveSelect( CORE_MODULES ).getModule( 'reader-revenue-manager' ),
resolveSelect( MODULES_READER_REVENUE_MANAGER ).getSettings(),
] ).then( () => {
registerBlockType( metadata.name, {
edit() {
return <Edit select={ select } />;
},
} );
} );
Loading