From ff86e4c9654a36c2e8de3b45eb18965836cb818b Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 19 Jun 2018 17:16:50 +0200 Subject: [PATCH 01/63] Initial code from wpcom --- .../memberships/class-jetpack-memberships.php | 304 ++++++++++++++++++ modules/memberships/memberships.css | 12 + modules/memberships/memberships.js | 33 ++ modules/module-extras.php | 1 + 4 files changed, 350 insertions(+) create mode 100644 modules/memberships/class-jetpack-memberships.php create mode 100644 modules/memberships/memberships.css create mode 100644 modules/memberships/memberships.js diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php new file mode 100644 index 0000000000000..57eeca5bb05c6 --- /dev/null +++ b/modules/memberships/class-jetpack-memberships.php @@ -0,0 +1,304 @@ +register_init_hook(); + } + + return self::$instance; + } + /** + * Get the map that defines the shape of CPT post. keys are names of fields and + * 'meta' is the name of actual WP post meta field that corresponds. + * + * @return array + */ + private static function get_plan_property_mapping() { + $meta_prefix = 'mem_'; + $properties = array( + 'price' => array( + 'meta' => $meta_prefix . 'price', + ), + 'currency' => array( + 'meta' => $meta_prefix . 'currency', + ), + ); + return $properties; + } + + /** + * Transform WP CPT post into array representing a memberships product. + * + * @param WP_Post $product_post - CPT representing the product. + * @return array + */ + public static function product_post_to_array( $product_post ) { + $data = array(); + $mapping = self::get_plan_property_mapping(); + foreach ( $mapping as $key => $map ) { + $data[ $key ] = get_post_meta( $product_post->ID, $map['meta'], true ); + } + $data['title'] = $product_post->post_title; + $data['description'] = $product_post->post_content; + $data['id'] = $product_post->ID; + return $data; + } + + /** + * Inits further hooks on init hook. + */ + private function register_init_hook() { + add_action( 'init', array( $this, 'init_hook_action' ) ); + } + + /** + * Actual hooks initializing on init. + */ + public function init_hook_action() { + add_filter( 'rest_api_allowed_post_types', array( $this, 'allow_rest_api_types' ) ); + add_filter( 'jetpack_sync_post_meta_whitelist', array( $this, 'allow_sync_post_meta' ) ); + $this->register_scripts(); + $this->setup_cpts(); + $this->register_shortcode(); + } + + /** + * Registers JS scripts. + */ + private function register_scripts() { + // According to docs, Stripe should be loaded from their CDN. + + wp_register_script( + 'memberships', plugins_url( '/memberships.js', __FILE__ ), array( + 'jquery', + ), self::$version + ); + } + + /** + * Sets up the custom post types for the module. + */ + private function setup_cpts() { + /* + * PLAN data structure. + */ + $capabilities = array( + 'edit_post' => 'edit_posts', + 'read_post' => 'read_private_posts', + 'delete_post' => 'delete_posts', + 'edit_posts' => 'edit_posts', + 'edit_others_posts' => 'edit_others_posts', + 'publish_posts' => 'publish_posts', + 'read_private_posts' => 'read_private_posts', + ); + $order_args = array( + 'label' => esc_html__( 'Plan', 'jetpack' ), + 'description' => esc_html__( 'Memberships plans', 'jetpack' ), + 'supports' => array( 'title', 'custom-fields', 'excerpt' ), + 'hierarchical' => false, + 'public' => false, + 'show_ui' => true, + 'show_in_menu' => true, + 'show_in_admin_bar' => false, + 'show_in_nav_menus' => false, + 'can_export' => true, + 'has_archive' => false, + 'exclude_from_search' => true, + 'publicly_queryable' => false, + 'rewrite' => false, + 'capabilities' => $capabilities, + 'show_in_rest' => true, + ); + register_post_type( self::$post_type_plan, $order_args ); + } + + /** + * Allows custom post types to be used by REST API. + * + * @param array $post_types - other post types. + * + * @see hook 'rest_api_allowed_post_types' + * @return array + */ + public function allow_rest_api_types( $post_types ) { + $post_types[] = self::$post_type_plan; + + return $post_types; + } + + /** + * Allows custom meta fields to sync. + * + * @param array $post_meta - previously changet post meta. + * + * @return array + */ + public function allow_sync_post_meta( $post_meta ) { + $meta_keys = array_map( + function( $map ) { + return $map['meta']; + }, $this->get_plan_property_mapping() + ); + return array_merge( $post_meta, array_values( $meta_keys ) ); + } + + /** + * Initializes the shortcode. + */ + private function register_shortcode() { + add_shortcode( self::$shortcode, array( $this, 'parse_shortcode' ) ); + } + + /** + * Callback that parses the membership purchase shortcode. + * + * @param array $attrs - attributes in the shortcode. `id` here is the CPT id of the plan. + * @param string|bool $content - needed for the callback. + * + * @return string|void + */ + public function parse_shortcode( $attrs, $content = false ) { + if ( empty( $attrs['id'] ) ) { + return; + } + $product = get_post( $attrs['id'] ); + if ( ! $product || is_wp_error( $product ) ) { + return; + } + if ( $product->post_type !== self::$post_type_plan || 'trash' === $product->post_status ) { + return; + } + $plan = self::product_post_to_array( $product ); + // We allow for overriding the presentation labels. + $data = shortcode_atts( + array_merge( + array( + 'blog_id' => get_current_blog_id(), + 'dom_id' => uniqid( self::$css_classname_prefix . '-' . $plan['id'] . '_', true ), + 'class' => self::$css_classname_prefix . '-' . $plan['id'], + ), $plan + ), $attrs + ); + + $data['price'] = $this->format_price( $plan ); + + $data['id'] = $attrs['id']; + + return $this->output_purchase_modal_button( $data ); + } + + /** + * Outputs the shortcode to the page. + * + * @param array $data - plan data array. + * + * @return string + */ + private function output_purchase_modal_button( $data ) { + $css_prefix = self::$css_classname_prefix; + if ( ! wp_script_is( 'memberships', 'enqueued' ) ) { + wp_enqueue_script( 'memberships' ); + } + if ( ! wp_style_is( 'memberships', 'enqueued' ) ) { + wp_enqueue_style( 'memberships', plugins_url( 'memberships.css', __FILE__ ), array( 'dashicons' ), self::$version ); + } + + wp_add_inline_script( + 'memberships', sprintf( + "try{JetpackMemberships.initPurchaseButton( '%d', '%d', '%s' );}catch(e){}", + esc_js( get_current_blog_id() ), + esc_js( $data['id'] ), + esc_js( $data['class'] ) + ) + ); + + add_thickbox(); + return " +
+
+
+

{$data['title']}

+

{$data['description']}

+

{$data['price']}

+
+
+
+ +
+
+
+
+
+ "; + } + + /** + * Formats the price. + * + * @param array $plan - array representing the plan. + * + * @return string + */ + private function format_price( $plan ) { + if ( $plan['formatted_price'] ) { + return $plan['formatted_price']; + } + return "{$plan['price']} {$plan['currency']}"; + } +} + +Jetpack_Memberships::get_instance(); diff --git a/modules/memberships/memberships.css b/modules/memberships/memberships.css new file mode 100644 index 0000000000000..88ebd5483430e --- /dev/null +++ b/modules/memberships/memberships.css @@ -0,0 +1,12 @@ +.jetpack-memberships_success { + background-color: #4BB543; + color: #ffffff; + padding:12px; +} +.jetpack-memberships-product { + padding:12px; + border: 1px solid black; +} +.jetpack-memberships-purchase-box { + text-align: center; +} diff --git a/modules/memberships/memberships.js b/modules/memberships/memberships.js new file mode 100644 index 0000000000000..b3dd8b0291627 --- /dev/null +++ b/modules/memberships/memberships.js @@ -0,0 +1,33 @@ +/* exported JetpackMemberships */ +/* jshint unused:false, es3:false, esversion:5 */ + +var JetpackMemberships = { + listener: null, + wrapper: null, + success: function() {}, + iframeResult: function( evt ) { + if ( evt.origin === 'https://subscribe.wordpress.com' ) { + window.removeEventListener( 'message', JetpackMemberships.iframeResult ); + console.log( 'JSON', evt ); + var data = JSON.parse( evt.data ); + if ( data.success ) { + JetpackMemberships.success( data ); + } + tb_remove(); + } + }, + initPurchaseButton: function ( blogId, planId, cssClass ) { + var wrapper = jQuery( '.' + cssClass ); + wrapper.find( '.jetpack-memberships_purchase_button' ).click( function() { + JetpackMemberships.success = function( data ) { + wrapper.append( "
" + + "

Success!

" + + "

You have purchased subscription and now can enjoy all the benefits.

" + + "

Your subscription is valid until '" + data.end_date + "'

" + + "
" ); + }; + JetpackMemberships.listener = window.addEventListener( 'message', JetpackMemberships.iframeResult, false ); + tb_show(null, 'https://subscribe.wordpress.com/memberships/?blog=' + blogId + '&plan=' + planId + 'TB_iframe=true&height=400&width=500', null); + } ); + } +}; diff --git a/modules/module-extras.php b/modules/module-extras.php index 989512dcbf516..11642e2988586 100644 --- a/modules/module-extras.php +++ b/modules/module-extras.php @@ -42,6 +42,7 @@ $connected_tools = array( 'calypsoify/class.jetpack-calypsoify.php', 'plugin-search.php', + 'memberships/class-jectpack-memberships.php', 'simple-payments/simple-payments.php', 'woocommerce-analytics/wp-woocommerce-analytics.php', 'wpcom-block-editor/class-jetpack-wpcom-block-editor.php', From e6a4187c21a217d15a985af20658d121226c15c7 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 19 Jun 2018 18:02:33 +0200 Subject: [PATCH 02/63] fix blog id --- modules/memberships/class-jetpack-memberships.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 57eeca5bb05c6..b0e2702c3e957 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -227,7 +227,7 @@ public function parse_shortcode( $attrs, $content = false ) { $data = shortcode_atts( array_merge( array( - 'blog_id' => get_current_blog_id(), + 'blog_id' => $this->get_blog_id(), 'dom_id' => uniqid( self::$css_classname_prefix . '-' . $plan['id'] . '_', true ), 'class' => self::$css_classname_prefix . '-' . $plan['id'], ), $plan @@ -241,6 +241,14 @@ public function parse_shortcode( $attrs, $content = false ) { return $this->output_purchase_modal_button( $data ); } + private function get_blog_id() { + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + return get_current_blog_id(); + } + + return Jetpack_Options::get_option( 'id' ); + } + /** * Outputs the shortcode to the page. * @@ -260,7 +268,7 @@ private function output_purchase_modal_button( $data ) { wp_add_inline_script( 'memberships', sprintf( "try{JetpackMemberships.initPurchaseButton( '%d', '%d', '%s' );}catch(e){}", - esc_js( get_current_blog_id() ), + esc_js( $this ->get_blog_id() ), esc_js( $data['id'] ), esc_js( $data['class'] ) ) From 801ed05ae0410e363a57beea1152aa8929bd503a Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 20 Jun 2018 17:49:49 +0200 Subject: [PATCH 03/63] Fix content --- modules/memberships/class-jetpack-memberships.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index b0e2702c3e957..e1c2286ff30da 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -148,7 +148,7 @@ private function setup_cpts() { $order_args = array( 'label' => esc_html__( 'Plan', 'jetpack' ), 'description' => esc_html__( 'Memberships plans', 'jetpack' ), - 'supports' => array( 'title', 'custom-fields', 'excerpt' ), + 'supports' => array( 'title', 'custom-fields', 'content' ), 'hierarchical' => false, 'public' => false, 'show_ui' => true, From 94f6f20ce276d91b6e017834bca96d90f8fb39dd Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 29 Jun 2018 16:27:05 +0200 Subject: [PATCH 04/63] Linter --- modules/memberships/memberships.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/memberships/memberships.js b/modules/memberships/memberships.js index b3dd8b0291627..04e7ed52b7846 100644 --- a/modules/memberships/memberships.js +++ b/modules/memberships/memberships.js @@ -1,5 +1,6 @@ /* exported JetpackMemberships */ /* jshint unused:false, es3:false, esversion:5 */ +/* global tb_show, tb_remove */ var JetpackMemberships = { listener: null, @@ -8,7 +9,6 @@ var JetpackMemberships = { iframeResult: function( evt ) { if ( evt.origin === 'https://subscribe.wordpress.com' ) { window.removeEventListener( 'message', JetpackMemberships.iframeResult ); - console.log( 'JSON', evt ); var data = JSON.parse( evt.data ); if ( data.success ) { JetpackMemberships.success( data ); @@ -16,18 +16,18 @@ var JetpackMemberships = { tb_remove(); } }, - initPurchaseButton: function ( blogId, planId, cssClass ) { + initPurchaseButton: function( blogId, planId, cssClass ) { var wrapper = jQuery( '.' + cssClass ); wrapper.find( '.jetpack-memberships_purchase_button' ).click( function() { JetpackMemberships.success = function( data ) { wrapper.append( "
" + - "

Success!

" + - "

You have purchased subscription and now can enjoy all the benefits.

" + - "

Your subscription is valid until '" + data.end_date + "'

" + - "
" ); + '

Success!

' + + '

You have purchased subscription and now can enjoy all the benefits.

' + + '

Your subscription is valid until "' + data.end_date + '"

' + + '' ); }; JetpackMemberships.listener = window.addEventListener( 'message', JetpackMemberships.iframeResult, false ); - tb_show(null, 'https://subscribe.wordpress.com/memberships/?blog=' + blogId + '&plan=' + planId + 'TB_iframe=true&height=400&width=500', null); + tb_show( null, 'https://subscribe.wordpress.com/memberships/?blog=' + blogId + '&plan=' + planId + 'TB_iframe=true&height=400&width=500', null ); } ); } }; From c1e86d08f938f299c129884a8cf78d43b91f70fb Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 29 Jun 2018 16:40:25 +0200 Subject: [PATCH 05/63] again - lint --- modules/memberships/memberships.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/memberships/memberships.js b/modules/memberships/memberships.js index 04e7ed52b7846..c5e2d6b35477d 100644 --- a/modules/memberships/memberships.js +++ b/modules/memberships/memberships.js @@ -20,7 +20,7 @@ var JetpackMemberships = { var wrapper = jQuery( '.' + cssClass ); wrapper.find( '.jetpack-memberships_purchase_button' ).click( function() { JetpackMemberships.success = function( data ) { - wrapper.append( "
" + + wrapper.append( '
' + '

Success!

' + '

You have purchased subscription and now can enjoy all the benefits.

' + '

Your subscription is valid until "' + data.end_date + '"

' + From b3126cb3061bdabe53cb6381748ce52879f9433a Mon Sep 17 00:00:00 2001 From: artpi Date: Mon, 18 Mar 2019 17:09:45 +0100 Subject: [PATCH 06/63] Rework into a block part 1 --- .../membership-button/membership-button.php | 18 +++ .../memberships/class-jetpack-memberships.php | 124 +++++------------- 2 files changed, 54 insertions(+), 88 deletions(-) create mode 100644 extensions/blocks/membership-button/membership-button.php diff --git a/extensions/blocks/membership-button/membership-button.php b/extensions/blocks/membership-button/membership-button.php new file mode 100644 index 0000000000000..beb8241dabd3b --- /dev/null +++ b/extensions/blocks/membership-button/membership-button.php @@ -0,0 +1,18 @@ + array( Jetpack_Memberships::get_instance(), 'render_button' ), + ) + ); +} diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index e1c2286ff30da..bb4994f712dab 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -31,11 +31,11 @@ class Jetpack_Memberships { */ static public $post_type_plan = 'jp_mem_plan'; /** - * Shortcode to use. + * Button block type to use. * * @var string */ - static private $shortcode = 'membership'; + static private $button_block_name = 'membership-button'; /** * Classic singleton pattern * @@ -111,22 +111,7 @@ private function register_init_hook() { public function init_hook_action() { add_filter( 'rest_api_allowed_post_types', array( $this, 'allow_rest_api_types' ) ); add_filter( 'jetpack_sync_post_meta_whitelist', array( $this, 'allow_sync_post_meta' ) ); - $this->register_scripts(); $this->setup_cpts(); - $this->register_shortcode(); - } - - /** - * Registers JS scripts. - */ - private function register_scripts() { - // According to docs, Stripe should be loaded from their CDN. - - wp_register_script( - 'memberships', plugins_url( '/memberships.js', __FILE__ ), array( - 'jquery', - ), self::$version - ); } /** @@ -151,8 +136,8 @@ private function setup_cpts() { 'supports' => array( 'title', 'custom-fields', 'content' ), 'hierarchical' => false, 'public' => false, - 'show_ui' => true, - 'show_in_menu' => true, + 'show_ui' => false, + 'show_in_menu' => false, 'show_in_admin_bar' => false, 'show_in_nav_menus' => false, 'can_export' => true, @@ -161,7 +146,7 @@ private function setup_cpts() { 'publicly_queryable' => false, 'rewrite' => false, 'capabilities' => $capabilities, - 'show_in_rest' => true, + 'show_in_rest' => false, ); register_post_type( self::$post_type_plan, $order_args ); } @@ -190,19 +175,12 @@ public function allow_rest_api_types( $post_types ) { public function allow_sync_post_meta( $post_meta ) { $meta_keys = array_map( function( $map ) { - return $map['meta']; + return $map['meta']; }, $this->get_plan_property_mapping() ); return array_merge( $post_meta, array_values( $meta_keys ) ); } - /** - * Initializes the shortcode. - */ - private function register_shortcode() { - add_shortcode( self::$shortcode, array( $this, 'parse_shortcode' ) ); - } - /** * Callback that parses the membership purchase shortcode. * @@ -211,7 +189,9 @@ private function register_shortcode() { * * @return string|void */ - public function parse_shortcode( $attrs, $content = false ) { + public function render_button( $attrs ) { + Jetpack_Gutenberg::load_assets_as_required( self::$button_block_name); + if ( empty( $attrs['id'] ) ) { return; } @@ -223,22 +203,36 @@ public function parse_shortcode( $attrs, $content = false ) { return; } $plan = self::product_post_to_array( $product ); - // We allow for overriding the presentation labels. - $data = shortcode_atts( - array_merge( - array( - 'blog_id' => $this->get_blog_id(), - 'dom_id' => uniqid( self::$css_classname_prefix . '-' . $plan['id'] . '_', true ), - 'class' => self::$css_classname_prefix . '-' . $plan['id'], - ), $plan - ), $attrs + $data = array( + 'blog_id' => $this->get_blog_id(), + 'id' => $attrs['id'], + 'button_label' => sprintf( __sprintf( '$s Contribution' ),$this->format_price( $plan ) ), + 'powered_text' => sprintf( __( 'Powered by WordPress.com' ), 'https://wordpress.com' ), ); - $data['price'] = $this->format_price( $plan ); - - $data['id'] = $attrs['id']; + $classes = array( + 'components-button', + 'is-primary', + 'is-button', + 'wp-block-jetpack-' . self::$button_block_name, + self::$css_classname_prefix . '-' . $data['id'], + ); + if ( isset( $attrs['className'] ) ) { + array_push( $classes, $attrs['className'] ); + } + if ( isset( $attrs['submitButtonText'] ) ) { + $data['button_label'] = $attrs['submitButtonText']; + } - return $this->output_purchase_modal_button( $data ); + return sprintf( + '', + $data['blog_id'], + $data['powered_text'], + $data['id'], + implode( $classes, ' ' ), + $data['button_label'] + ); + return "{$data['content']}"; } private function get_blog_id() { @@ -249,50 +243,6 @@ private function get_blog_id() { return Jetpack_Options::get_option( 'id' ); } - /** - * Outputs the shortcode to the page. - * - * @param array $data - plan data array. - * - * @return string - */ - private function output_purchase_modal_button( $data ) { - $css_prefix = self::$css_classname_prefix; - if ( ! wp_script_is( 'memberships', 'enqueued' ) ) { - wp_enqueue_script( 'memberships' ); - } - if ( ! wp_style_is( 'memberships', 'enqueued' ) ) { - wp_enqueue_style( 'memberships', plugins_url( 'memberships.css', __FILE__ ), array( 'dashicons' ), self::$version ); - } - - wp_add_inline_script( - 'memberships', sprintf( - "try{JetpackMemberships.initPurchaseButton( '%d', '%d', '%s' );}catch(e){}", - esc_js( $this ->get_blog_id() ), - esc_js( $data['id'] ), - esc_js( $data['class'] ) - ) - ); - - add_thickbox(); - return " -
-
-
-

{$data['title']}

-

{$data['description']}

-

{$data['price']}

-
-
-
- -
-
-
-
-
- "; - } /** * Formats the price. @@ -308,5 +258,3 @@ private function format_price( $plan ) { return "{$plan['price']} {$plan['currency']}"; } } - -Jetpack_Memberships::get_instance(); From 04843dfe7b0df5e5908c10b2ce85fc2eadfd10b9 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 19 Mar 2019 16:25:03 +0100 Subject: [PATCH 07/63] memberships changes --- modules/memberships/class-jetpack-memberships.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index bb4994f712dab..24aaf28abc795 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -174,13 +174,15 @@ public function allow_rest_api_types( $post_types ) { */ public function allow_sync_post_meta( $post_meta ) { $meta_keys = array_map( - function( $map ) { - return $map['meta']; - }, $this->get_plan_property_mapping() + array( $this, 'return_meta' ), + $this->get_plan_property_mapping() ); return array_merge( $post_meta, array_values( $meta_keys ) ); } + public function return_meta( $map ) { + return $map['meta']; + } /** * Callback that parses the membership purchase shortcode. * @@ -232,7 +234,6 @@ public function render_button( $attrs ) { implode( $classes, ' ' ), $data['button_label'] ); - return "{$data['content']}"; } private function get_blog_id() { From 8d1ff7965554dc2d9428fef05893e22baa5765de Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 20 Mar 2019 16:43:44 +0100 Subject: [PATCH 08/63] Memberships status endpoint --- .../core-api/wpcom-endpoints/memberships.php | 61 +++++++++++++++++++ .../memberships/class-jetpack-memberships.php | 1 + 2 files changed, 62 insertions(+) create mode 100644 _inc/lib/core-api/wpcom-endpoints/memberships.php diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php new file mode 100644 index 0000000000000..2a6c20253493f --- /dev/null +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -0,0 +1,61 @@ +namespace = 'wpcom/v2'; + $this->rest_base = 'memberships'; + $this->wpcom_is_wpcom_only_endpoint = true; + $this->wpcom_is_site_specific_endpoint = true; + add_action( 'rest_api_init', array( $this, 'register_routes' ) ); + } + + /** + * Called automatically on `rest_api_init()`. + */ + public function register_routes() { + register_rest_route( + $this->namespace, + $this->rest_base . '/status', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_status' ), + ), + ) + ); + } + public function get_status() { + if( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { + require_lib( 'memberships' ); + $blog_id = get_current_blog_id(); + $connect_url = get_memberships_connected_account_redirect( get_current_user_id() ); + $products = get_memberships_plans( $blog_id ); + } else { + $blog_id = Jetpack_Options::get_option( 'id' ); + $response = Jetpack_Client::wpcom_json_api_request_as_user( + "/sites/$blog_id/{$this->rest_base}/status", + 'v2', + array(), + null + ); + if ( is_wp_error( $response ) ) { + return new WP_Error( 'wpcom_connection_error', 'Could not connect to WP.com', 404 ); + } + $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; + $connect_url = $data['connect_url']; + $products = $data['products']; + } + return array( + 'connect_url' => $connect_url, + 'products' => $products, + ); + } +} +wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Memberships' ); diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 24aaf28abc795..b178d0803f36c 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -259,3 +259,4 @@ private function format_price( $plan ) { return "{$plan['price']} {$plan['currency']}"; } } +Jetpack_Memberships::get_instance(); \ No newline at end of file From 2feeb2b05e229f7345b930c5892a4cfe19b35114 Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 20 Mar 2019 18:23:57 +0100 Subject: [PATCH 09/63] endpoint enhancements --- _inc/lib/core-api/wpcom-endpoints/memberships.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index 2a6c20253493f..66f8da319df97 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -32,10 +32,14 @@ public function register_routes() { ); } public function get_status() { - if( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { + $connected_account_id = Jetpack_Memberships::get_connected_account_id(); + $connect_url = ''; + if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { require_lib( 'memberships' ); $blog_id = get_current_blog_id(); - $connect_url = get_memberships_connected_account_redirect( get_current_user_id() ); + if ( ! $connected_account_id ) { + $connect_url = get_memberships_connected_account_redirect( get_current_user_id() ); + } $products = get_memberships_plans( $blog_id ); } else { $blog_id = Jetpack_Options::get_option( 'id' ); @@ -49,10 +53,13 @@ public function get_status() { return new WP_Error( 'wpcom_connection_error', 'Could not connect to WP.com', 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; - $connect_url = $data['connect_url']; + if ( ! $connected_account_id ) { + $connect_url = $data['connect_url']; + } $products = $data['products']; } return array( + 'connected_account_id' => $connected_account_id, 'connect_url' => $connect_url, 'products' => $products, ); From 600bc9303954511c01982d82b3c60cdab4b20293 Mon Sep 17 00:00:00 2001 From: artpi Date: Mon, 25 Mar 2019 11:07:48 +0100 Subject: [PATCH 10/63] Something memberships --- modules/memberships/class-jetpack-memberships.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index b178d0803f36c..f7ac7fb20c312 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -30,6 +30,10 @@ class Jetpack_Memberships { * @var string */ static public $post_type_plan = 'jp_mem_plan'; + /** + * @var string Option that will store currently set up account (Stripe etc) id for memberships + */ + static public $connected_account_id_option_name = 'jetpack-memberships-connected-account-id'; /** * Button block type to use. * @@ -244,6 +248,9 @@ private function get_blog_id() { return Jetpack_Options::get_option( 'id' ); } + static function get_connected_account_id() { + return get_option( self::$connected_account_id_option_name ); + } /** * Formats the price. From 641bd51a7c1b574b2167561eefb2c253869655dc Mon Sep 17 00:00:00 2001 From: artpi Date: Mon, 25 Mar 2019 16:15:03 +0100 Subject: [PATCH 11/63] whitelist the option --- sync/class.jetpack-sync-defaults.php | 1 + 1 file changed, 1 insertion(+) diff --git a/sync/class.jetpack-sync-defaults.php b/sync/class.jetpack-sync-defaults.php index 1440682319833..0ce3747b4de03 100644 --- a/sync/class.jetpack-sync-defaults.php +++ b/sync/class.jetpack-sync-defaults.php @@ -74,6 +74,7 @@ class Jetpack_Sync_Defaults { 'disabled_reblogs', 'jetpack_comment_likes_enabled', 'twitter_via', + 'jetpack-memberships-connected-account-id', 'jetpack-twitter-cards-site-tag', 'wpcom_publish_posts_with_markdown', 'wpcom_publish_comments_with_markdown', From 5c8e88dddeb5f76d77d4ca7e7635a8e0f425037e Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 26 Mar 2019 11:22:10 +0100 Subject: [PATCH 12/63] Thickbox is working --- modules/memberships/class-jetpack-memberships.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index f7ac7fb20c312..5709bf8f347c3 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -198,10 +198,11 @@ public function return_meta( $map ) { public function render_button( $attrs ) { Jetpack_Gutenberg::load_assets_as_required( self::$button_block_name); - if ( empty( $attrs['id'] ) ) { + if ( empty( $attrs['planId'] ) ) { return; } - $product = get_post( $attrs['id'] ); + $id = $attrs['planId']; + $product = get_post( $id ); if ( ! $product || is_wp_error( $product ) ) { return; } @@ -211,9 +212,9 @@ public function render_button( $attrs ) { $plan = self::product_post_to_array( $product ); $data = array( 'blog_id' => $this->get_blog_id(), - 'id' => $attrs['id'], - 'button_label' => sprintf( __sprintf( '$s Contribution' ),$this->format_price( $plan ) ), - 'powered_text' => sprintf( __( 'Powered by WordPress.com' ), 'https://wordpress.com' ), + 'id' => $id, + 'button_label' => sprintf( __( '$%s Contribution' ),$this->format_price( $plan ) ), + 'powered_text' => __( 'Powered by WordPress.com' ), ); $classes = array( @@ -229,9 +230,9 @@ public function render_button( $attrs ) { if ( isset( $attrs['submitButtonText'] ) ) { $data['button_label'] = $attrs['submitButtonText']; } - + add_thickbox(); return sprintf( - '', + '', $data['blog_id'], $data['powered_text'], $data['id'], From 7c9af415e19e1c597f2abee469525ccacae5cb52 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 26 Mar 2019 13:53:32 +0100 Subject: [PATCH 13/63] Pass button color --- .../memberships/class-jetpack-memberships.php | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 5709bf8f347c3..75b1e814ac880 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -230,13 +230,34 @@ public function render_button( $attrs ) { if ( isset( $attrs['submitButtonText'] ) ) { $data['button_label'] = $attrs['submitButtonText']; } + $button_styles = array(); + if ( ! empty( $attrs['customBackgroundButtonColor'] ) ) { + array_push( + $button_styles, + sprintf( + 'background-color: %s', + sanitize_hex_color( $attrs['customBackgroundButtonColor'] ) + ) + ); + } + if ( ! empty( $attrs['customTextButtonColor'] ) ) { + array_push( + $button_styles, + sprintf( + 'color: %s', + sanitize_hex_color( $attr['customTextButtonColor'] ) + ) + ); + } + $button_styles = implode( $button_styles, ';' ); add_thickbox(); return sprintf( - '', + '', $data['blog_id'], $data['powered_text'], $data['id'], implode( $classes, ' ' ), + $button_styles, $data['button_label'] ); } From 4b061e96f58edc700a289dc6b1ddccb008758ee1 Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 27 Mar 2019 14:41:27 +0100 Subject: [PATCH 14/63] Endpoint changes because I have to rebase --- .../core-api/wpcom-endpoints/memberships.php | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index 66f8da319df97..00b3536cc6386 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -30,6 +30,74 @@ public function register_routes() { ), ) ); + register_rest_route( + $this->namespace, + $this->rest_base . '/product', + array( + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'create_product' ), + 'args' => array( + 'title' => array( + 'type' => 'string', + 'required' => true, + ), + 'price' => array( + 'type' => 'float', + 'required' => true, + ), + 'currency' => array( + 'type' => 'string', + 'required' => true, + ), + 'interval' => array( + 'type' => 'string', + 'required' => true, + ), + ), + ), + ) + ); + } + + public function create_product( $request ) { + if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { + require_lib( 'memberships' ); + $connected_destination_account_id = Jetpack_Memberships::get_connected_account_id(); + if ( ! $connected_destination_account_id ) { + return new WP_Error( 'no-destination-account', __( 'Please set up Stripe account for this site first' ) ); + } + $product = Memberships_Product::create( get_current_blog_id(), array( + 'title' => $request['title'], + 'price' => $request['price'], + 'currency' => $request['currency'], + 'interval' => $request['interval'], + 'connected_destination_account_id' => $connected_destination_account_id, + ) ); + return $product->to_array(); + } else { + $blog_id = Jetpack_Options::get_option( 'id' ); + $response = Jetpack_Client::wpcom_json_api_request_as_blog( + "/sites/$blog_id/{$this->rest_base}/product", + 'v2', + array( + 'method' => 'POST', + ), + array( + 'title' => $request['title'], + 'price' => $request['price'], + 'currency' => $request['currency'], + 'interval' => $request['interval'], + ) + ); + if ( is_wp_error( $response ) ) { + return new WP_Error( 'wpcom_connection_error', 'Could not connect to WP.com', 404 ); + } + $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; + return $data; + } + + return $request; } public function get_status() { $connected_account_id = Jetpack_Memberships::get_connected_account_id(); @@ -38,7 +106,7 @@ public function get_status() { require_lib( 'memberships' ); $blog_id = get_current_blog_id(); if ( ! $connected_account_id ) { - $connect_url = get_memberships_connected_account_redirect( get_current_user_id() ); + $connect_url = get_memberships_connected_account_redirect( get_current_user_id(), $blog_id ); } $products = get_memberships_plans( $blog_id ); } else { From 675be9ce3f72a9a1e1d5c3d1083d48d6ce15dedc Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 27 Mar 2019 14:59:19 +0100 Subject: [PATCH 15/63] Port work from calypso --- extensions/blocks/membership-button/edit.jsx | 313 ++++++++++++++++++ extensions/blocks/membership-button/editor.js | 7 + .../blocks/membership-button/editor.scss | 24 ++ extensions/blocks/membership-button/index.js | 79 +++++ extensions/blocks/membership-button/view.js | 57 ++++ extensions/blocks/membership-button/view.scss | 50 +++ extensions/index.json | 2 +- 7 files changed, 531 insertions(+), 1 deletion(-) create mode 100644 extensions/blocks/membership-button/edit.jsx create mode 100644 extensions/blocks/membership-button/editor.js create mode 100644 extensions/blocks/membership-button/editor.scss create mode 100644 extensions/blocks/membership-button/index.js create mode 100644 extensions/blocks/membership-button/view.js create mode 100644 extensions/blocks/membership-button/view.scss diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx new file mode 100644 index 0000000000000..b345a55d7af08 --- /dev/null +++ b/extensions/blocks/membership-button/edit.jsx @@ -0,0 +1,313 @@ +/** + * External dependencies + */ + +import classnames from 'classnames'; +import SubmitButton from '../../utils/submit-button'; +import apiFetch from '@wordpress/api-fetch'; +import { __ } from '../../utils/i18n'; +import { trimEnd } from 'lodash'; +import { getCurrencyDefaults } from '@automattic/format-currency'; + +import { + Button, + PanelBody, + Placeholder, + Spinner, + TextControl, + withNotices, + SelectControl, +} from '@wordpress/components'; +import { InspectorControls } from '@wordpress/editor'; +import { Fragment, Component } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { icon, SUPPORTED_CURRENCY_LIST } from '.'; +import { formatPrice } from '../simple-payments/utils'; + +const API_STATE_LOADING = 0; +const API_STATE_CONNECTED = 1; +const API_STATE_NOTCONNECTED = 2; + +class MembershipsButtonEdit extends Component { + constructor() { + super( ...arguments ); + this.state = { + connected: API_STATE_LOADING, + connectURL: null, + addingMembershipAmount: false, + products: [], + editedProductCurrency: 'USD', + editedProductPrice: 5, + editedProductTitle: '', + editedProductRenewInterval: '1 month', + }; + this.timeout = null; + } + + componentDidMount = () => { + this.apiCall(); + }; + + onError = message => { + const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + }; + + apiCall = () => { + const path = '/wpcom/v2/memberships/status'; + const method = 'GET'; + const fetch = { path, method }; + apiFetch( fetch ).then( + result => { + this.setState( { + products: this.state.products.concat( [ + { + id: result.id, + title: result.title, + interval: result.interval, + price: result.price, + }, + ] ), + } ); + } + // result => { + // const connectURL = null; + // const connected = API_STATE_NOTCONNECTED; + // this.setState( { connected, connectURL } ); + // this.onError( result.message ); + // } + ); + }; + getCurrencyList = SUPPORTED_CURRENCY_LIST.map( value => { + const { symbol } = getCurrencyDefaults( value ); + // if symbol is equal to the code (e.g., 'CHF' === 'CHF'), don't duplicate it. + // trim the dot at the end, e.g., 'kr.' becomes 'kr' + const label = symbol === value ? value : `${ value } ${ trimEnd( symbol, '.' ) }`; + return { value, label }; + } ); + + handleCurrencyChange = editedProductCurrency => this.setState( { editedProductCurrency } ); + handleRenewIntervalChange = editedProductRenewInterval => + this.setState( { editedProductRenewInterval } ); + + handlePriceChange = price => { + price = parseFloat( price ); + if ( ! isNaN( price ) ) { + this.setState( { editedProductPrice: price } ); + } else { + this.setState( { editedProductPrice: undefined } ); + } + }; + + handleTitleChange = editedProductTitle => this.setState( { editedProductTitle } ); + // eslint-disable-next-line + saveProduct = () => { + const path = '/wpcom/v2/memberships/product'; + const method = 'POST'; + const data = { + currency: this.state.editedProductCurrency, + price: this.state.editedProductPrice, + title: this.state.editedProductTitle, + interval: this.state.editedProductRenewInterval, + }; + const fetch = { path, method, data }; + apiFetch( fetch ).then( + result => { + const connectURL = result.connect_url; + const products = result.products; + const connected = result.connected_account_id + ? API_STATE_CONNECTED + : API_STATE_NOTCONNECTED; + this.setState( { connected, connectURL, products } ); + } + // result => { + // const connectURL = null; + // const connected = API_STATE_NOTCONNECTED; + // this.setState( { connected, connectURL } ); + // this.onError( result.message ); + // } + ); + }; + + renderAddMembershipAmount = () => { + if ( ! this.state.addingMembershipAmount ) { + return ( + + ); + } + + return ( +
+
+
+ + +
+ + +
+ + +
+ ); + }; + getFormattedPriceByProductId = id => { + const product = this.state.products.filter( prod => prod.id === id ).pop(); + return formatPrice( parseFloat( product.price ), product.currency ); + }; + + setMembershipAmount = id => + this.props.setAttributes( { + planId: id, + submitButtonText: this.getFormattedPriceByProductId( id ) + __( ' Contribution' ), + } ); + + renderMembershipAmounts = () => ( +
+ {' '} + { this.state.products.map( product => ( + + ) ) }{' '} +
+ ); + + render = () => { + const { className, notices } = this.props; + const { connected, connectURL, products } = this.state; + + const inspectorControls = ( + + + ( { + label: formatPrice( parseFloat( product.price ), product.currency ), + value: product.id, + key: product.id, + } ) ) } + /> + + + ); + const blockClasses = classnames( className, [ + 'components-button', + 'is-primary', + 'is-button', + ] ); + const blockContent = ( + + ); + return ( + + { connected === API_STATE_LOADING && ( + + + + ) } + { ! this.props.attributes.planId && connected === API_STATE_NOTCONNECTED && ( + +
+ { __( 'In order to start selling Membership plans, you have to connect to Stripe:' ) } +
+
+ +
+
+ +
+
+ ) } + { ! this.props.attributes.planId && + connected === API_STATE_CONNECTED && + products.length === 0 && ( + +
+ { __( 'Add your first Membership amount:' ) } +
+
+ { this.renderAddMembershipAmount() } +
+
+ ) } + { ! this.props.attributes.planId && + connected === API_STATE_CONNECTED && + products.length > 0 && ( + +
+ { __( 'Select payment amount:' ) } + { this.renderMembershipAmounts() } + { __( 'Or add another membership amount:' ) } +
+ { this.renderAddMembershipAmount() } +
+
+ ) } + { connected !== API_STATE_LOADING && this.props.attributes.planId && inspectorControls } + { connected !== API_STATE_LOADING && this.props.attributes.planId && blockContent } +
+ ); + }; +} + +export default withNotices( MembershipsButtonEdit ); diff --git a/extensions/blocks/membership-button/editor.js b/extensions/blocks/membership-button/editor.js new file mode 100644 index 0000000000000..babee275335fe --- /dev/null +++ b/extensions/blocks/membership-button/editor.js @@ -0,0 +1,7 @@ +/** + * Internal dependencies + */ +import registerJetpackBlock from '../../utils/register-jetpack-block'; +import { name, settings } from '.'; + +registerJetpackBlock( name, settings ); diff --git a/extensions/blocks/membership-button/editor.scss b/extensions/blocks/membership-button/editor.scss new file mode 100644 index 0000000000000..fb898a96f6648 --- /dev/null +++ b/extensions/blocks/membership-button/editor.scss @@ -0,0 +1,24 @@ +@import './view.scss'; + +.wp-block-jetpack-membership-button { + + .wp-block-jetpack-membership-button_notification { + display: block; + } + + .editor-rich-text__inline-toolbar { + pointer-events: none; + .components-toolbar { + pointer-events: all; + } + } + + .wp-block-jetpack-membership-button_text-input, .jetpack-submit-button { + margin-bottom: 1.5rem; + } + + .wp-block-button .wp-block-button__link { + margin-top: 0; + } + +} diff --git a/extensions/blocks/membership-button/index.js b/extensions/blocks/membership-button/index.js new file mode 100644 index 0000000000000..4a1ff96484c5f --- /dev/null +++ b/extensions/blocks/membership-button/index.js @@ -0,0 +1,79 @@ +/** + * External dependencies + */ +import { Path, Rect, SVG, G } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { __, _x } from '../../utils/i18n'; +import edit from './edit'; +import './editor.scss'; +import { DEFAULT_CURRENCY } from '../simple-payments/constants'; + +export const name = 'membership-button'; + +export const icon = ( + + + + + + +); + +export const settings = { + title: __( 'Membership Button' ), + icon, + description: __( 'Button allowing you to sell subscription products.' ), + category: 'jetpack', + keywords: [ + _x( 'sell', 'block search term' ), + _x( 'subscription', 'block search term' ), + _x( 'stripe', 'block search term' ), + ], + attributes: { + planId: { + type: 'integer', + }, + submitButtonText: { + type: 'string', + default: __( 'Your donation' ), + }, + customBackgroundButtonColor: { + type: 'string', + }, + customTextButtonColor: { + type: 'string', + }, + }, + edit, + save: () => null, +}; + +export const SUPPORTED_CURRENCY_LIST = [ + DEFAULT_CURRENCY, + 'EUR', + 'AUD', + 'BRL', + 'CAD', + 'CZK', + 'DKK', + 'HKD', + 'HUF', + 'ILS', + 'JPY', + 'MYR', + 'MXN', + 'TWD', + 'NZD', + 'NOK', + 'PHP', + 'PLN', + 'GBP', + 'RUB', + 'SGD', + 'SEK', + 'CHF', + 'THB', +]; diff --git a/extensions/blocks/membership-button/view.js b/extensions/blocks/membership-button/view.js new file mode 100644 index 0000000000000..8af7b7fd65770 --- /dev/null +++ b/extensions/blocks/membership-button/view.js @@ -0,0 +1,57 @@ +/* global tb_show */ + +/** + * Internal dependencies + */ +import './view.scss'; +const name = 'membership-button'; +const blockClassName = 'wp-block-jetpack-' + name; + +function activateSubscription( block, blogId, planId, poweredText ) { + block.addEventListener( 'click', () => { + tb_show( + null, + 'https://subscribe.wordpress.com/memberships/?blog=' + + blogId + + '&plan=' + + planId + + 'TB_iframe=true&height=600&width=400', + null + ); + const tbWindow = document.querySelector( '#TB_window' ); + tbWindow.classList.add( 'jetpack-memberships-modal' ); + const footer = document.createElement( 'DIV' ); + footer.classList.add( 'TB_footer' ); + footer.innerHTML = poweredText; + tbWindow.appendChild( footer ); + } ); +} + +const initializeMembershipButtonBlocks = () => { + const mailchimpBlocks = Array.from( document.querySelectorAll( '.' + blockClassName ) ); + mailchimpBlocks.forEach( block => { + const blog_id = block.getAttribute( 'data-blog-id' ); + const plan_id = block.getAttribute( 'data-plan-id' ); + const powered_text = block + .getAttribute( 'data-powered-text' ) + .replace( + 'WordPress.com', + 'WordPress.com' + ); + try { + activateSubscription( block, blog_id, plan_id, powered_text ); + } catch ( err ) { + // eslint-disable-next-line no-console + console.error( 'Problem activating Membership Button ' + plan_id, err ); + } + } ); +}; + +if ( typeof window !== 'undefined' && typeof document !== 'undefined' ) { + // `DOMContentLoaded` may fire before the script has a chance to run + if ( document.readyState === 'loading' ) { + document.addEventListener( 'DOMContentLoaded', initializeMembershipButtonBlocks ); + } else { + initializeMembershipButtonBlocks(); + } +} diff --git a/extensions/blocks/membership-button/view.scss b/extensions/blocks/membership-button/view.scss new file mode 100644 index 0000000000000..e87b124a1eaac --- /dev/null +++ b/extensions/blocks/membership-button/view.scss @@ -0,0 +1,50 @@ +/* Additional styling to thickbox that displays modal */ +/* stylelint-disable selector-max-id */ + +.jetpack-memberships-modal #TB_title { + border-radius: 4px 4px 0 0; +} +#TB_window.jetpack-memberships-modal { + border-radius: 4px; + background-color: #f9f9f9; + background-image: url( 'https://s0.wp.com/i/loading/loading-64.gif' ); + background-repeat: no-repeat; + background-position: center; + bottom: 10%; + margin-top: 0 !important; + top: 10%; +} + +.jetpack-memberships-modal #TB_iframeContent { + height: calc( 100% - 50px ) !important; +} +@media only screen and ( max-width: 480px ) { + #TB_window.jetpack-memberships-modal { + bottom: 0; + left: 0; + margin-left: 0 !important; + right: 0; + top: 0; + width: 100% !important; + } + .jetpack-memberships-modal #TB_iframeContent { + width: 100% !important; + } +} + +.jetpack-memberships-modal #TB_iframeContent { + height: calc( 100% - 80px ) !important; +} +.jetpack-memberships-modal .TB_footer { + border-top: 1px solid #ddd; + color: #a5b2bd; + font-family: 'Lato', sans-serif; + font-size: 13px; + padding: 4px 0; + text-align: center; +} +.jetpack-memberships-modal .TB_footer a, +.jetpack-memberships-modal .TB_footer a:hover, +.jetpack-memberships-modal .TB_footer a:visited { + color: #33bbe3; +} diff --git a/extensions/index.json b/extensions/index.json index b544a5e9fac38..e8cdcfed049bf 100644 --- a/extensions/index.json +++ b/extensions/index.json @@ -20,5 +20,5 @@ "videopress", "wordads" ], - "beta": [ "seo" ] + "beta": [ "seo", "membership-button" ] } From a20c69c059a32bafe9a4e795685f41ed7c917c79 Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 27 Mar 2019 16:41:39 +0100 Subject: [PATCH 16/63] Make it work --- .../core-api/wpcom-endpoints/memberships.php | 5 +-- extensions/blocks/membership-button/edit.jsx | 32 +++++++++---------- .../memberships/class-jetpack-memberships.php | 4 +-- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index 00b3536cc6386..9aa6232df98f3 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -79,7 +79,7 @@ public function create_product( $request ) { $blog_id = Jetpack_Options::get_option( 'id' ); $response = Jetpack_Client::wpcom_json_api_request_as_blog( "/sites/$blog_id/{$this->rest_base}/product", - 'v2', + '2', array( 'method' => 'POST', ), @@ -88,7 +88,8 @@ public function create_product( $request ) { 'price' => $request['price'], 'currency' => $request['currency'], 'interval' => $request['interval'], - ) + ), + 'wpcom' ); if ( is_wp_error( $response ) ) { return new WP_Error( 'wpcom_connection_error', 'Could not connect to WP.com', 404 ); diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index b345a55d7af08..d72df86989046 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -63,16 +63,12 @@ class MembershipsButtonEdit extends Component { const fetch = { path, method }; apiFetch( fetch ).then( result => { - this.setState( { - products: this.state.products.concat( [ - { - id: result.id, - title: result.title, - interval: result.interval, - price: result.price, - }, - ] ), - } ); + const connectURL = result.connect_url; + const products = result.products; + const connected = result.connected_account_id + ? API_STATE_CONNECTED + : API_STATE_NOTCONNECTED; + this.setState( { connected, connectURL, products } ); } // result => { // const connectURL = null; @@ -117,12 +113,16 @@ class MembershipsButtonEdit extends Component { const fetch = { path, method, data }; apiFetch( fetch ).then( result => { - const connectURL = result.connect_url; - const products = result.products; - const connected = result.connected_account_id - ? API_STATE_CONNECTED - : API_STATE_NOTCONNECTED; - this.setState( { connected, connectURL, products } ); + this.setState( { + products: this.state.products.concat( [ + { + id: result.id, + title: result.title, + interval: result.interval, + price: result.price, + }, + ] ), + } ); } // result => { // const connectURL = null; diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 75b1e814ac880..2b53037ab4c3d 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -17,7 +17,7 @@ class Jetpack_Memberships { * * @var string */ - static private $css_classname_prefix = 'jetpack-memberships'; + static public $css_classname_prefix = 'jetpack-memberships'; /** * Increase this number each time there's a change in CSS or JS to bust cache. * @@ -245,7 +245,7 @@ public function render_button( $attrs ) { $button_styles, sprintf( 'color: %s', - sanitize_hex_color( $attr['customTextButtonColor'] ) + sanitize_hex_color( $attrs['customTextButtonColor'] ) ) ); } From c310a99dd51e516507b45fddb21d63a3de4a9aa0 Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 27 Mar 2019 17:42:43 +0100 Subject: [PATCH 17/63] Fixes to the UI --- extensions/blocks/membership-button/edit.jsx | 159 ++++++++++-------- .../blocks/membership-button/editor.scss | 18 +- 2 files changed, 102 insertions(+), 75 deletions(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index d72df86989046..06fd5b067a212 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -31,13 +31,17 @@ const API_STATE_LOADING = 0; const API_STATE_CONNECTED = 1; const API_STATE_NOTCONNECTED = 2; +const PRODUCT_NOT_ADDING = 0; +const PRODUCT_FORM = 1; +const PRODUCT_FORM_SUBMITTED = 2; + class MembershipsButtonEdit extends Component { constructor() { super( ...arguments ); this.state = { connected: API_STATE_LOADING, connectURL: null, - addingMembershipAmount: false, + addingMembershipAmount: PRODUCT_NOT_ADDING, products: [], editedProductCurrency: 'USD', editedProductPrice: 5, @@ -69,13 +73,13 @@ class MembershipsButtonEdit extends Component { ? API_STATE_CONNECTED : API_STATE_NOTCONNECTED; this.setState( { connected, connectURL, products } ); + }, + result => { + const connectURL = null; + const connected = API_STATE_NOTCONNECTED; + this.setState( { connected, connectURL } ); + this.onError( result.message ); } - // result => { - // const connectURL = null; - // const connected = API_STATE_NOTCONNECTED; - // this.setState( { connected, connectURL } ); - // this.onError( result.message ); - // } ); }; getCurrencyList = SUPPORTED_CURRENCY_LIST.map( value => { @@ -102,6 +106,7 @@ class MembershipsButtonEdit extends Component { handleTitleChange = editedProductTitle => this.setState( { editedProductTitle } ); // eslint-disable-next-line saveProduct = () => { + this.setState( { addingMembershipAmount: PRODUCT_FORM_SUBMITTED } ); const path = '/wpcom/v2/memberships/product'; const method = 'POST'; const data = { @@ -114,6 +119,7 @@ class MembershipsButtonEdit extends Component { apiFetch( fetch ).then( result => { this.setState( { + addingMembershipAmount: PRODUCT_NOT_ADDING, products: this.state.products.concat( [ { id: result.id, @@ -123,79 +129,90 @@ class MembershipsButtonEdit extends Component { }, ] ), } ); + }, + result => { + this.setState( { addingMembershipAmount: PRODUCT_FORM } ); + this.onError( result.message ); } - // result => { - // const connectURL = null; - // const connected = API_STATE_NOTCONNECTED; - // this.setState( { connected, connectURL } ); - // this.onError( result.message ); - // } ); }; renderAddMembershipAmount = () => { - if ( ! this.state.addingMembershipAmount ) { + if ( this.state.addingMembershipAmount === PRODUCT_NOT_ADDING ) { return ( ); } + if ( this.state.addingMembershipAmount === PRODUCT_FORM_SUBMITTED ) { + return ; + } return ( -
-
-
- - -
- +
+
+
- - + + +
+ + +
); }; @@ -214,7 +231,12 @@ class MembershipsButtonEdit extends Component {
{' '} { this.state.products.map( product => ( - ) ) }{' '} @@ -256,14 +278,15 @@ class MembershipsButtonEdit extends Component { ); return ( - { connected === API_STATE_LOADING && ( + { this.props.noticeUI } + { connected === API_STATE_LOADING && ! this.props.attributes.planId && ( ) } { ! this.props.attributes.planId && connected === API_STATE_NOTCONNECTED && ( -
+
{ __( 'In order to start selling Membership plans, you have to connect to Stripe:' ) }

@@ -282,7 +305,7 @@ class MembershipsButtonEdit extends Component { connected === API_STATE_CONNECTED && products.length === 0 && ( -
+
{ __( 'Add your first Membership amount:' ) }

@@ -294,7 +317,7 @@ class MembershipsButtonEdit extends Component { connected === API_STATE_CONNECTED && products.length > 0 && ( -
+
{ __( 'Select payment amount:' ) } { this.renderMembershipAmounts() } { __( 'Or add another membership amount:' ) } @@ -303,8 +326,8 @@ class MembershipsButtonEdit extends Component {
) } - { connected !== API_STATE_LOADING && this.props.attributes.planId && inspectorControls } - { connected !== API_STATE_LOADING && this.props.attributes.planId && blockContent } + { this.state.products && inspectorControls } + { this.props.attributes.planId && blockContent } ); }; diff --git a/extensions/blocks/membership-button/editor.scss b/extensions/blocks/membership-button/editor.scss index fb898a96f6648..68d265594f83c 100644 --- a/extensions/blocks/membership-button/editor.scss +++ b/extensions/blocks/membership-button/editor.scss @@ -1,7 +1,16 @@ @import './view.scss'; .wp-block-jetpack-membership-button { + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, + Helvetica Neue, sans-serif; + .membership-button__price-container { + display: flex; + flex-wrap: wrap; + } + .membership-button__field-price { + margin-left: 10px; + } .wp-block-jetpack-membership-button_notification { display: block; } @@ -13,12 +22,7 @@ } } - .wp-block-jetpack-membership-button_text-input, .jetpack-submit-button { - margin-bottom: 1.5rem; + .membership-button__field-button { + margin: 4px; } - - .wp-block-button .wp-block-button__link { - margin-top: 0; - } - } From 6787afcecb3fdc782379234c4b96f9aef6b96ff9 Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 27 Mar 2019 17:53:50 +0100 Subject: [PATCH 18/63] fix for price change --- extensions/blocks/membership-button/edit.jsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index 06fd5b067a212..1a54d901a0aba 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -150,9 +150,6 @@ class MembershipsButtonEdit extends Component { ); } - if ( this.state.addingMembershipAmount === PRODUCT_FORM_SUBMITTED ) { - return ; - } return (
@@ -217,7 +214,9 @@ class MembershipsButtonEdit extends Component { ); }; getFormattedPriceByProductId = id => { - const product = this.state.products.filter( prod => prod.id === id ).pop(); + const product = this.state.products + .filter( prod => parseInt( prod.id ) === parseInt( id ) ) + .pop(); return formatPrice( parseFloat( product.price ), product.currency ); }; @@ -279,11 +278,13 @@ class MembershipsButtonEdit extends Component { return ( { this.props.noticeUI } - { connected === API_STATE_LOADING && ! this.props.attributes.planId && ( - - - - ) } + { ( connected === API_STATE_LOADING || + this.state.addingMembershipAmount === PRODUCT_FORM_SUBMITTED ) && + ! this.props.attributes.planId && ( + + + + ) } { ! this.props.attributes.planId && connected === API_STATE_NOTCONNECTED && (
From 63c25642f2aeb6a360850e25dbcbcdcde6aaff9b Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 27 Mar 2019 17:55:43 +0100 Subject: [PATCH 19/63] remove legacy code --- modules/memberships/memberships.css | 12 ----------- modules/memberships/memberships.js | 33 ----------------------------- 2 files changed, 45 deletions(-) delete mode 100644 modules/memberships/memberships.css delete mode 100644 modules/memberships/memberships.js diff --git a/modules/memberships/memberships.css b/modules/memberships/memberships.css deleted file mode 100644 index 88ebd5483430e..0000000000000 --- a/modules/memberships/memberships.css +++ /dev/null @@ -1,12 +0,0 @@ -.jetpack-memberships_success { - background-color: #4BB543; - color: #ffffff; - padding:12px; -} -.jetpack-memberships-product { - padding:12px; - border: 1px solid black; -} -.jetpack-memberships-purchase-box { - text-align: center; -} diff --git a/modules/memberships/memberships.js b/modules/memberships/memberships.js deleted file mode 100644 index c5e2d6b35477d..0000000000000 --- a/modules/memberships/memberships.js +++ /dev/null @@ -1,33 +0,0 @@ -/* exported JetpackMemberships */ -/* jshint unused:false, es3:false, esversion:5 */ -/* global tb_show, tb_remove */ - -var JetpackMemberships = { - listener: null, - wrapper: null, - success: function() {}, - iframeResult: function( evt ) { - if ( evt.origin === 'https://subscribe.wordpress.com' ) { - window.removeEventListener( 'message', JetpackMemberships.iframeResult ); - var data = JSON.parse( evt.data ); - if ( data.success ) { - JetpackMemberships.success( data ); - } - tb_remove(); - } - }, - initPurchaseButton: function( blogId, planId, cssClass ) { - var wrapper = jQuery( '.' + cssClass ); - wrapper.find( '.jetpack-memberships_purchase_button' ).click( function() { - JetpackMemberships.success = function( data ) { - wrapper.append( '
' + - '

Success!

' + - '

You have purchased subscription and now can enjoy all the benefits.

' + - '

Your subscription is valid until "' + data.end_date + '"

' + - '
' ); - }; - JetpackMemberships.listener = window.addEventListener( 'message', JetpackMemberships.iframeResult, false ); - tb_show( null, 'https://subscribe.wordpress.com/memberships/?blog=' + blogId + '&plan=' + planId + 'TB_iframe=true&height=400&width=500', null ); - } ); - } -}; From 9dc7d46dbd6d6d048d7ae5d6b40a7692100b38b8 Mon Sep 17 00:00:00 2001 From: artpi Date: Mon, 1 Apr 2019 11:20:53 +0200 Subject: [PATCH 20/63] Review feedbac --- _inc/lib/core-api/wpcom-endpoints/memberships.php | 8 ++++---- .../blocks/membership-button/membership-button.php | 3 ++- modules/memberships/class-jetpack-memberships.php | 14 +++----------- tests/php/sync/test_class.jetpack-sync-options.php | 1 + 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index 9aa6232df98f3..7664a454ed0fb 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -3,7 +3,7 @@ /** * Memberships: API to communicate with "product" database. * - * @since 7.2 + * @since 7.3 */ @@ -65,7 +65,7 @@ public function create_product( $request ) { require_lib( 'memberships' ); $connected_destination_account_id = Jetpack_Memberships::get_connected_account_id(); if ( ! $connected_destination_account_id ) { - return new WP_Error( 'no-destination-account', __( 'Please set up Stripe account for this site first' ) ); + return new WP_Error( 'no-destination-account', __( 'Please set up Stripe account for this site first', 'jetpack' ) ); } $product = Memberships_Product::create( get_current_blog_id(), array( 'title' => $request['title'], @@ -92,7 +92,7 @@ public function create_product( $request ) { 'wpcom' ); if ( is_wp_error( $response ) ) { - return new WP_Error( 'wpcom_connection_error', 'Could not connect to WP.com', 404 ); + return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com' , 'jetpack' ), 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; return $data; @@ -119,7 +119,7 @@ public function get_status() { null ); if ( is_wp_error( $response ) ) { - return new WP_Error( 'wpcom_connection_error', 'Could not connect to WP.com', 404 ); + return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com' , 'jetpack' ), 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; if ( ! $connected_account_id ) { diff --git a/extensions/blocks/membership-button/membership-button.php b/extensions/blocks/membership-button/membership-button.php index beb8241dabd3b..85e62afcd1ca4 100644 --- a/extensions/blocks/membership-button/membership-button.php +++ b/extensions/blocks/membership-button/membership-button.php @@ -2,10 +2,11 @@ /** * Memberships block. * - * @since 7.2.0 + * @since 7.3.0 * * @package Jetpack */ + require_once JETPACK__PLUGIN_DIR . '/modules/memberships/class-jetpack-memberships.php'; if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) || Jetpack::is_active() ) { diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 2b53037ab4c3d..d75fb4bd8caf1 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -1,12 +1,4 @@ $this->get_blog_id(), 'id' => $id, - 'button_label' => sprintf( __( '$%s Contribution' ),$this->format_price( $plan ) ), - 'powered_text' => __( 'Powered by WordPress.com' ), + 'button_label' => sprintf( __( '$%s Contribution', 'jetpack' ),$this->format_price( $plan ) ), + 'powered_text' => __( 'Powered by WordPress.com', 'jetpack' ), ); $classes = array( diff --git a/tests/php/sync/test_class.jetpack-sync-options.php b/tests/php/sync/test_class.jetpack-sync-options.php index 9b6a445eca586..eeed2f37a906c 100644 --- a/tests/php/sync/test_class.jetpack-sync-options.php +++ b/tests/php/sync/test_class.jetpack-sync-options.php @@ -202,6 +202,7 @@ public function test_sync_default_options() { 'site_segment' => 'pineapple', 'site_vertical' => 'pineapple', 'jetpack_excluded_extensions' => 'pineapple', + 'jetpack-memberships-connected-account-id' => '340', ); $theme_mod_key = 'theme_mods_' . get_option( 'stylesheet' ); From 976d7f18b4eaaeb3e3c35583d4d6902fab0dee25 Mon Sep 17 00:00:00 2001 From: artpi Date: Mon, 1 Apr 2019 13:12:07 +0200 Subject: [PATCH 21/63] repurpose format_price --- modules/memberships/class-jetpack-memberships.php | 3 ++- modules/simple-payments/simple-payments.php | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index d75fb4bd8caf1..d6ebd8abb68f8 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -277,7 +277,8 @@ private function format_price( $plan ) { if ( $plan['formatted_price'] ) { return $plan['formatted_price']; } - return "{$plan['price']} {$plan['currency']}"; + require_once JETPACK__PLUGIN_DIR . '/modules/simple-payments/simple-payments.php'; + return Jetpack_Simple_Payments::format_price( $plan['price'],$plan['currency'] ); } } Jetpack_Memberships::get_instance(); \ No newline at end of file diff --git a/modules/simple-payments/simple-payments.php b/modules/simple-payments/simple-payments.php index e1b7f8d77d456..32cbb546f9056 100644 --- a/modules/simple-payments/simple-payments.php +++ b/modules/simple-payments/simple-payments.php @@ -134,7 +134,7 @@ function parse_shortcode( $attrs, $content = false ) { 'multiple' => get_post_meta( $product->ID, 'spay_multiple', true ) || '0' ), $attrs ); - $data['price'] = $this->format_price( + $data['price'] = self::format_price( get_post_meta( $product->ID, 'spay_price', true ), get_post_meta( $product->ID, 'spay_currency', true ) ); @@ -272,7 +272,7 @@ function output_shortcode( $data ) { * @param string $currency Currency. * @return string Formatted price. */ - private function format_price( $price, $currency ) { + public static function format_price( $price, $currency ) { $currency_details = self::get_currency( $currency ); if ( $currency_details ) { @@ -550,7 +550,7 @@ function setup_cpts() { * @param string $the_currency The desired currency, e.g. 'USD'. * @return ?array Currency object or null if not found. */ - private static function get_currency( $the_currency ) { + public static function get_currency( $the_currency ) { $currencies = array( 'USD' => array( 'format' => '%1$s%2$s', // 1: Symbol 2: currency value From 110e9558de277cf1cae9487785095dbc31038dc5 Mon Sep 17 00:00:00 2001 From: artpi Date: Mon, 1 Apr 2019 20:51:24 +0200 Subject: [PATCH 22/63] permissions check --- _inc/lib/core-api/wpcom-endpoints/memberships.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index 7664a454ed0fb..fad35789de44c 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -27,6 +27,7 @@ public function register_routes() { array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_status' ), + 'permission_callback' => array( $this, 'get_status_permission_check' ), ), ) ); @@ -37,6 +38,7 @@ public function register_routes() { array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_product' ), + 'permission_callback' => array( $this, 'get_status_permission_check' ), 'args' => array( 'title' => array( 'type' => 'string', @@ -60,6 +62,15 @@ public function register_routes() { ); } + /** + * Ensure the user has proper permissions + * + * @return boolean + */ + public function get_status_permission_check() { + return current_user_can( 'edit_posts' ); + } + public function create_product( $request ) { if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { require_lib( 'memberships' ); From 9087c2cdf559bec7966e70211609d6316d153596 Mon Sep 17 00:00:00 2001 From: artpi Date: Mon, 1 Apr 2019 20:51:55 +0200 Subject: [PATCH 23/63] remove simple payments import --- modules/memberships/class-jetpack-memberships.php | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index d6ebd8abb68f8..599bbd757bfa2 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -277,7 +277,6 @@ private function format_price( $plan ) { if ( $plan['formatted_price'] ) { return $plan['formatted_price']; } - require_once JETPACK__PLUGIN_DIR . '/modules/simple-payments/simple-payments.php'; return Jetpack_Simple_Payments::format_price( $plan['price'],$plan['currency'] ); } } From 255367226265b65bd9416ca73408929941e43a95 Mon Sep 17 00:00:00 2001 From: artpi Date: Mon, 1 Apr 2019 20:53:22 +0200 Subject: [PATCH 24/63] make it pull a proper file --- extensions/blocks/membership-button/membership-button.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extensions/blocks/membership-button/membership-button.php b/extensions/blocks/membership-button/membership-button.php index 85e62afcd1ca4..530ca0b774f1c 100644 --- a/extensions/blocks/membership-button/membership-button.php +++ b/extensions/blocks/membership-button/membership-button.php @@ -7,7 +7,11 @@ * @package Jetpack */ -require_once JETPACK__PLUGIN_DIR . '/modules/memberships/class-jetpack-memberships.php'; +if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + require_once WP_CONTENT_DIR . '/mu-plugins/memberships/class-jetpack-memberships.php'; +} elseif ( Jetpack::is_active() ) { + require_once JETPACK__PLUGIN_DIR . '/modules/memberships/class-jetpack-memberships.php'; +} if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) || Jetpack::is_active() ) { jetpack_register_block( From 236327f1b8898e745678c62c0f31038783a47624 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 11:13:50 +0200 Subject: [PATCH 25/63] review feedback - JS parts --- extensions/blocks/membership-button/edit.jsx | 3 +-- extensions/blocks/membership-button/index.js | 25 ++++++------------- extensions/blocks/membership-button/view.js | 16 ++++++------ extensions/blocks/membership-button/view.scss | 1 - 4 files changed, 18 insertions(+), 27 deletions(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index 1a54d901a0aba..14c95286795e4 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -228,7 +228,6 @@ class MembershipsButtonEdit extends Component { renderMembershipAmounts = () => (
- {' '} { this.state.products.map( product => ( - ) ) }{' '} + ) ) }
); diff --git a/extensions/blocks/membership-button/index.js b/extensions/blocks/membership-button/index.js index 4a1ff96484c5f..3c3e41dd1775b 100644 --- a/extensions/blocks/membership-button/index.js +++ b/extensions/blocks/membership-button/index.js @@ -9,7 +9,6 @@ import { Path, Rect, SVG, G } from '@wordpress/components'; import { __, _x } from '../../utils/i18n'; import edit from './edit'; import './editor.scss'; -import { DEFAULT_CURRENCY } from '../simple-payments/constants'; export const name = 'membership-button'; @@ -30,7 +29,7 @@ export const settings = { keywords: [ _x( 'sell', 'block search term' ), _x( 'subscription', 'block search term' ), - _x( 'stripe', 'block search term' ), + 'stripe', ], attributes: { planId: { @@ -51,29 +50,21 @@ export const settings = { save: () => null, }; +// These are Stripe Settlement currencies https://stripe.com/docs/currencies since memberships supports only Stripe ATM. export const SUPPORTED_CURRENCY_LIST = [ - DEFAULT_CURRENCY, - 'EUR', + 'USD', 'AUD', 'BRL', 'CAD', - 'CZK', + 'CHF', 'DKK', + 'EUR', + 'GBP', 'HKD', - 'HUF', - 'ILS', 'JPY', - 'MYR', 'MXN', - 'TWD', - 'NZD', 'NOK', - 'PHP', - 'PLN', - 'GBP', - 'RUB', - 'SGD', + 'NZD', 'SEK', - 'CHF', - 'THB', + 'SGD', ]; diff --git a/extensions/blocks/membership-button/view.js b/extensions/blocks/membership-button/view.js index 8af7b7fd65770..1766f9057a90e 100644 --- a/extensions/blocks/membership-button/view.js +++ b/extensions/blocks/membership-button/view.js @@ -28,21 +28,23 @@ function activateSubscription( block, blogId, planId, poweredText ) { } const initializeMembershipButtonBlocks = () => { - const mailchimpBlocks = Array.from( document.querySelectorAll( '.' + blockClassName ) ); - mailchimpBlocks.forEach( block => { - const blog_id = block.getAttribute( 'data-blog-id' ); - const plan_id = block.getAttribute( 'data-plan-id' ); - const powered_text = block + const membershipButtonBlocks = Array.prototype.slice.call( + document.querySelectorAll( '.' + blockClassName ) + ); + membershipButtonBlocks.forEach( block => { + const blogId = block.getAttribute( 'data-blog-id' ); + const planId = block.getAttribute( 'data-plan-id' ); + const poweredText = block .getAttribute( 'data-powered-text' ) .replace( 'WordPress.com', 'WordPress.com' ); try { - activateSubscription( block, blog_id, plan_id, powered_text ); + activateSubscription( block, blogId, planId, poweredText ); } catch ( err ) { // eslint-disable-next-line no-console - console.error( 'Problem activating Membership Button ' + plan_id, err ); + console.error( 'Problem activating Membership Button ' + planId, err ); } } ); }; diff --git a/extensions/blocks/membership-button/view.scss b/extensions/blocks/membership-button/view.scss index e87b124a1eaac..8e8af9f93b0de 100644 --- a/extensions/blocks/membership-button/view.scss +++ b/extensions/blocks/membership-button/view.scss @@ -38,7 +38,6 @@ .jetpack-memberships-modal .TB_footer { border-top: 1px solid #ddd; color: #a5b2bd; - font-family: 'Lato', sans-serif; font-size: 13px; padding: 4px 0; text-align: center; From 3d2c08a9b8cb2a7692e286d5d4f063eea3f54ffb Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 2 Apr 2019 11:24:58 +0200 Subject: [PATCH 26/63] Update modules/memberships/class-jetpack-memberships.php Co-Authored-By: artpi --- modules/memberships/class-jetpack-memberships.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 599bbd757bfa2..b057ab4a4f373 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -188,7 +188,7 @@ public function return_meta( $map ) { * @return string|void */ public function render_button( $attrs ) { - Jetpack_Gutenberg::load_assets_as_required( self::$button_block_name); + Jetpack_Gutenberg::load_assets_as_required( self::$button_block_name, array( 'thickbox', 'wp-polyfill' ) ); if ( empty( $attrs['planId'] ) ) { return; @@ -280,4 +280,4 @@ private function format_price( $plan ) { return Jetpack_Simple_Payments::format_price( $plan['price'],$plan['currency'] ); } } -Jetpack_Memberships::get_instance(); \ No newline at end of file +Jetpack_Memberships::get_instance(); From 8de9da5fc95d73c5613b1e8b4641645a4e04018d Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 2 Apr 2019 11:25:51 +0200 Subject: [PATCH 27/63] Update extensions/blocks/membership-button/edit.jsx Co-Authored-By: artpi --- extensions/blocks/membership-button/edit.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index 14c95286795e4..9f2c2567f2305 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -5,7 +5,7 @@ import classnames from 'classnames'; import SubmitButton from '../../utils/submit-button'; import apiFetch from '@wordpress/api-fetch'; -import { __ } from '../../utils/i18n'; +import { __ } from '@wordpress/i18n'; import { trimEnd } from 'lodash'; import { getCurrencyDefaults } from '@automattic/format-currency'; From 920f1c399a918f754c3c1cfeddba11918d897637 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 2 Apr 2019 11:27:47 +0200 Subject: [PATCH 28/63] Update extensions/blocks/membership-button/edit.jsx Co-Authored-By: artpi --- extensions/blocks/membership-button/edit.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index 9f2c2567f2305..462c78f42988b 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -145,7 +145,7 @@ class MembershipsButtonEdit extends Component { isLarge onClick={ () => this.setState( { addingMembershipAmount: PRODUCT_FORM } ) } > - { __( 'Add Memberships Amounts' ) } + { __( 'Add Memberships Amounts', 'jetpack' ) } ); } From be33ad67e868af9098d265a212606d0d9d155f34 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 11:29:07 +0200 Subject: [PATCH 29/63] textdomain --- extensions/blocks/membership-button/edit.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index 462c78f42988b..4601dee6477e2 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -223,7 +223,7 @@ class MembershipsButtonEdit extends Component { setMembershipAmount = id => this.props.setAttributes( { planId: id, - submitButtonText: this.getFormattedPriceByProductId( id ) + __( ' Contribution' ), + submitButtonText: this.getFormattedPriceByProductId( id ) + __( ' Contribution', 'jetpack' ), } ); renderMembershipAmounts = () => ( From 3ddc1f028cd3bcbf867320ea8d07b9d45f05d5e8 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 11:31:09 +0200 Subject: [PATCH 30/63] remove unnecessary version --- modules/memberships/class-jetpack-memberships.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index b057ab4a4f373..01c21fa68d904 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -10,12 +10,6 @@ class Jetpack_Memberships { * @var string */ static public $css_classname_prefix = 'jetpack-memberships'; - /** - * Increase this number each time there's a change in CSS or JS to bust cache. - * - * @var string - */ - static private $version = JETPACK__VERSION; /** * Our CPT type for the product (plan). * From 046b806e7a83aca7afc032e7e215efaf8cf11d38 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 2 Apr 2019 11:34:45 +0200 Subject: [PATCH 31/63] Remove default button text from block default Co-Authored-By: artpi --- extensions/blocks/membership-button/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/blocks/membership-button/index.js b/extensions/blocks/membership-button/index.js index 3c3e41dd1775b..bba94c0162fc6 100644 --- a/extensions/blocks/membership-button/index.js +++ b/extensions/blocks/membership-button/index.js @@ -37,7 +37,6 @@ export const settings = { }, submitButtonText: { type: 'string', - default: __( 'Your donation' ), }, customBackgroundButtonColor: { type: 'string', From 94e6994bb7f652f497cc9eef8ca12a50536d9b58 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 2 Apr 2019 11:35:57 +0200 Subject: [PATCH 32/63] Use unwrapped i18n depenencies instaed of relative path Co-Authored-By: artpi --- extensions/blocks/membership-button/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/blocks/membership-button/index.js b/extensions/blocks/membership-button/index.js index bba94c0162fc6..29a0827618e44 100644 --- a/extensions/blocks/membership-button/index.js +++ b/extensions/blocks/membership-button/index.js @@ -6,7 +6,7 @@ import { Path, Rect, SVG, G } from '@wordpress/components'; /** * Internal dependencies */ -import { __, _x } from '../../utils/i18n'; +import { __, _x } from '@wordpress/i18n'; import edit from './edit'; import './editor.scss'; From e68d671f8523478980dcfa8081079903a6898bd6 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 2 Apr 2019 11:36:30 +0200 Subject: [PATCH 33/63] Textdomain Co-Authored-By: artpi --- extensions/blocks/membership-button/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/blocks/membership-button/index.js b/extensions/blocks/membership-button/index.js index 29a0827618e44..d0f05de0df16b 100644 --- a/extensions/blocks/membership-button/index.js +++ b/extensions/blocks/membership-button/index.js @@ -22,7 +22,7 @@ export const icon = ( ); export const settings = { - title: __( 'Membership Button' ), + title: __( 'Membership Button', 'jetpack' ), icon, description: __( 'Button allowing you to sell subscription products.' ), category: 'jetpack', From 810eef99a8c67ce524ee21365f0f2d61d9c7c60f Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 11:43:50 +0200 Subject: [PATCH 34/63] texdomain again --- extensions/blocks/membership-button/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/blocks/membership-button/index.js b/extensions/blocks/membership-button/index.js index d0f05de0df16b..69578a794f430 100644 --- a/extensions/blocks/membership-button/index.js +++ b/extensions/blocks/membership-button/index.js @@ -24,11 +24,11 @@ export const icon = ( export const settings = { title: __( 'Membership Button', 'jetpack' ), icon, - description: __( 'Button allowing you to sell subscription products.' ), + description: __( 'Button allowing you to sell subscription products.', 'jetpack' ), category: 'jetpack', keywords: [ - _x( 'sell', 'block search term' ), - _x( 'subscription', 'block search term' ), + _x( 'sell', 'block search term', 'jetpack' ), + _x( 'subscription', 'block search term', 'jetpack' ), 'stripe', ], attributes: { From 7af50286f6902af514be6e4aece5450ebeb3a56b Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 11:47:13 +0200 Subject: [PATCH 35/63] properly escape attributes --- modules/memberships/class-jetpack-memberships.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 01c21fa68d904..85012e883c0f4 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -239,12 +239,12 @@ public function render_button( $attrs ) { add_thickbox(); return sprintf( '', - $data['blog_id'], - $data['powered_text'], - $data['id'], - implode( $classes, ' ' ), - $button_styles, - $data['button_label'] + esc_attr( $data['blog_id'] ), + esc_attr( $data['powered_text'] ), + esc_attr( $data['id'] ), + esc_attr( implode( $classes, ' ' ) ), + esc_attr( $button_styles ), + esc_html( $data['button_label'] ) ); } From 64fe6e46bb3fa7da7957d1f35404a700507dd629 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 12:03:20 +0200 Subject: [PATCH 36/63] reuse currency functins --- extensions/blocks/membership-button/edit.jsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index 4601dee6477e2..e49ccf5f9ff3f 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -7,7 +7,7 @@ import SubmitButton from '../../utils/submit-button'; import apiFetch from '@wordpress/api-fetch'; import { __ } from '@wordpress/i18n'; import { trimEnd } from 'lodash'; -import { getCurrencyDefaults } from '@automattic/format-currency'; +import formatCurrency, { getCurrencyDefaults } from '@automattic/format-currency'; import { Button, @@ -25,7 +25,6 @@ import { Fragment, Component } from '@wordpress/element'; * Internal dependencies */ import { icon, SUPPORTED_CURRENCY_LIST } from '.'; -import { formatPrice } from '../simple-payments/utils'; const API_STATE_LOADING = 0; const API_STATE_CONNECTED = 1; @@ -164,7 +163,7 @@ class MembershipsButtonEdit extends Component { label={ __( 'Price' ) } className="membership-button__field membership-button__field-price" onChange={ this.handlePriceChange } - placeholder={ formatPrice( 0, this.state.editedProductCurrency, false ) } + placeholder={ formatCurrency( 0, this.state.editedProductCurrency ) } required step="1" type="number" @@ -217,7 +216,7 @@ class MembershipsButtonEdit extends Component { const product = this.state.products .filter( prod => parseInt( prod.id ) === parseInt( id ) ) .pop(); - return formatPrice( parseFloat( product.price ), product.currency ); + return formatCurrency( parseFloat( product.price ), product.currency ); }; setMembershipAmount = id => @@ -235,7 +234,7 @@ class MembershipsButtonEdit extends Component { key={ product.id } onClick={ () => this.setMembershipAmount( product.id ) } > - { formatPrice( parseFloat( product.price ), product.currency ) } + { formatCurrency( parseFloat( product.price ), product.currency ) } ) ) }
@@ -253,7 +252,7 @@ class MembershipsButtonEdit extends Component { value={ this.props.attributes.planId } onChange={ this.setMembershipAmount } options={ this.state.products.map( product => ( { - label: formatPrice( parseFloat( product.price ), product.currency ), + label: formatCurrency( parseFloat( product.price ), product.currency ), value: product.id, key: product.id, } ) ) } From d4586ecfb8309c46e25c3e9f94f715ba83f3901b Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 12:14:01 +0200 Subject: [PATCH 37/63] Revert simple payments format_currency changes --- .../memberships/class-jetpack-memberships.php | 16 +--------------- modules/simple-payments/simple-payments.php | 6 +++--- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 85012e883c0f4..3af691d58b639 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -199,7 +199,7 @@ public function render_button( $attrs ) { $data = array( 'blog_id' => $this->get_blog_id(), 'id' => $id, - 'button_label' => sprintf( __( '$%s Contribution', 'jetpack' ),$this->format_price( $plan ) ), + 'button_label' => __( 'Your contribution', 'jetpack' ), 'powered_text' => __( 'Powered by WordPress.com', 'jetpack' ), ); @@ -259,19 +259,5 @@ private function get_blog_id() { static function get_connected_account_id() { return get_option( self::$connected_account_id_option_name ); } - - /** - * Formats the price. - * - * @param array $plan - array representing the plan. - * - * @return string - */ - private function format_price( $plan ) { - if ( $plan['formatted_price'] ) { - return $plan['formatted_price']; - } - return Jetpack_Simple_Payments::format_price( $plan['price'],$plan['currency'] ); - } } Jetpack_Memberships::get_instance(); diff --git a/modules/simple-payments/simple-payments.php b/modules/simple-payments/simple-payments.php index 32cbb546f9056..e1b7f8d77d456 100644 --- a/modules/simple-payments/simple-payments.php +++ b/modules/simple-payments/simple-payments.php @@ -134,7 +134,7 @@ function parse_shortcode( $attrs, $content = false ) { 'multiple' => get_post_meta( $product->ID, 'spay_multiple', true ) || '0' ), $attrs ); - $data['price'] = self::format_price( + $data['price'] = $this->format_price( get_post_meta( $product->ID, 'spay_price', true ), get_post_meta( $product->ID, 'spay_currency', true ) ); @@ -272,7 +272,7 @@ function output_shortcode( $data ) { * @param string $currency Currency. * @return string Formatted price. */ - public static function format_price( $price, $currency ) { + private function format_price( $price, $currency ) { $currency_details = self::get_currency( $currency ); if ( $currency_details ) { @@ -550,7 +550,7 @@ function setup_cpts() { * @param string $the_currency The desired currency, e.g. 'USD'. * @return ?array Currency object or null if not found. */ - public static function get_currency( $the_currency ) { + private static function get_currency( $the_currency ) { $currencies = array( 'USD' => array( 'format' => '%1$s%2$s', // 1: Symbol 2: currency value From 35397ba4df3258614a50f9330196abee93cda2cd Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 12:54:31 +0200 Subject: [PATCH 38/63] solve cancel and a small UI issue --- extensions/blocks/membership-button/edit.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index e49ccf5f9ff3f..f0019cc44aff6 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -148,6 +148,9 @@ class MembershipsButtonEdit extends Component { ); } + if ( this.state.addingMembershipAmount === PRODUCT_FORM_SUBMITTED ) { + return; + } return (
@@ -204,7 +207,7 @@ class MembershipsButtonEdit extends Component { From 25f880cfc86b4b0e37441f71d9bef29bd7aa2bdf Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 13:13:09 +0200 Subject: [PATCH 39/63] fix lint in class memberships --- .../memberships/class-jetpack-memberships.php | 52 ++++++++++++++----- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 3af691d58b639..a8a5664810c3a 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -1,4 +1,11 @@ post_type !== self::$post_type_plan || 'trash' === $product->post_status ) { return; } - $plan = self::product_post_to_array( $product ); + $data = array( - 'blog_id' => $this->get_blog_id(), - 'id' => $id, + 'blog_id' => self::get_blog_id(), + 'id' => $id, 'button_label' => __( 'Your contribution', 'jetpack' ), 'powered_text' => __( 'Powered by WordPress.com', 'jetpack' ), ); @@ -248,7 +264,12 @@ public function render_button( $attrs ) { ); } - private function get_blog_id() { + /** + * Get current blog id. + * + * @return int + */ + public static function get_blog_id() { if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { return get_current_blog_id(); } @@ -256,7 +277,12 @@ private function get_blog_id() { return Jetpack_Options::get_option( 'id' ); } - static function get_connected_account_id() { + /** + * Get the id of the connected payment acount (Stripe etc). + * + * @return int|void + */ + public static function get_connected_account_id() { return get_option( self::$connected_account_id_option_name ); } } From 28db6a47cffe1de3fd704c4ff971987fea2542cc Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 13:29:16 +0200 Subject: [PATCH 40/63] lint api files --- .../core-api/wpcom-endpoints/memberships.php | 91 ++++++++++++------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index fad35789de44c..57db08b10aa3f 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -1,17 +1,24 @@ -namespace = 'wpcom/v2'; - $this->rest_base = 'memberships'; - $this->wpcom_is_wpcom_only_endpoint = true; + $this->namespace = 'wpcom/v2'; + $this->rest_base = 'memberships'; + $this->wpcom_is_wpcom_only_endpoint = true; $this->wpcom_is_site_specific_endpoint = true; add_action( 'rest_api_init', array( $this, 'register_routes' ) ); } @@ -25,8 +32,8 @@ public function register_routes() { $this->rest_base . '/status', array( array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_status' ), + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_status' ), 'permission_callback' => array( $this, 'get_status_permission_check' ), ), ) @@ -36,24 +43,24 @@ public function register_routes() { $this->rest_base . '/product', array( array( - 'methods' => WP_REST_Server::CREATABLE, - 'callback' => array( $this, 'create_product' ), + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'create_product' ), 'permission_callback' => array( $this, 'get_status_permission_check' ), - 'args' => array( - 'title' => array( - 'type' => 'string', + 'args' => array( + 'title' => array( + 'type' => 'string', 'required' => true, ), - 'price' => array( - 'type' => 'float', + 'price' => array( + 'type' => 'float', 'required' => true, ), 'currency' => array( - 'type' => 'string', + 'type' => 'string', 'required' => true, ), 'interval' => array( - 'type' => 'string', + 'type' => 'string', 'required' => true, ), ), @@ -71,6 +78,13 @@ public function get_status_permission_check() { return current_user_can( 'edit_posts' ); } + /** + * Do create a product based on data, or pass request to wpcom. + * + * @param object $request - request passed from WP. + * + * @return array|WP_Error + */ public function create_product( $request ) { if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { require_lib( 'memberships' ); @@ -78,16 +92,19 @@ public function create_product( $request ) { if ( ! $connected_destination_account_id ) { return new WP_Error( 'no-destination-account', __( 'Please set up Stripe account for this site first', 'jetpack' ) ); } - $product = Memberships_Product::create( get_current_blog_id(), array( - 'title' => $request['title'], - 'price' => $request['price'], - 'currency' => $request['currency'], - 'interval' => $request['interval'], - 'connected_destination_account_id' => $connected_destination_account_id, - ) ); + $product = Memberships_Product::create( + get_current_blog_id(), + array( + 'title' => $request['title'], + 'price' => $request['price'], + 'currency' => $request['currency'], + 'interval' => $request['interval'], + 'connected_destination_account_id' => $connected_destination_account_id, + ) + ); return $product->to_array(); } else { - $blog_id = Jetpack_Options::get_option( 'id' ); + $blog_id = Jetpack_Options::get_option( 'id' ); $response = Jetpack_Client::wpcom_json_api_request_as_blog( "/sites/$blog_id/{$this->rest_base}/product", '2', @@ -95,15 +112,15 @@ public function create_product( $request ) { 'method' => 'POST', ), array( - 'title' => $request['title'], - 'price' => $request['price'], + 'title' => $request['title'], + 'price' => $request['price'], 'currency' => $request['currency'], 'interval' => $request['interval'], ), 'wpcom' ); if ( is_wp_error( $response ) ) { - return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com' , 'jetpack' ), 404 ); + return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com', 'jetpack' ), 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; return $data; @@ -111,9 +128,15 @@ public function create_product( $request ) { return $request; } + + /** + * Get a status of connection for the site. If this is Jetpack, pass the request to wpcom. + * + * @return array|WP_Error + */ public function get_status() { $connected_account_id = Jetpack_Memberships::get_connected_account_id(); - $connect_url = ''; + $connect_url = ''; if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { require_lib( 'memberships' ); $blog_id = get_current_blog_id(); @@ -122,7 +145,7 @@ public function get_status() { } $products = get_memberships_plans( $blog_id ); } else { - $blog_id = Jetpack_Options::get_option( 'id' ); + $blog_id = Jetpack_Options::get_option( 'id' ); $response = Jetpack_Client::wpcom_json_api_request_as_user( "/sites/$blog_id/{$this->rest_base}/status", 'v2', @@ -130,7 +153,7 @@ public function get_status() { null ); if ( is_wp_error( $response ) ) { - return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com' , 'jetpack' ), 404 ); + return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com', 'jetpack' ), 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; if ( ! $connected_account_id ) { @@ -140,8 +163,8 @@ public function get_status() { } return array( 'connected_account_id' => $connected_account_id, - 'connect_url' => $connect_url, - 'products' => $products, + 'connect_url' => $connect_url, + 'products' => $products, ); } } From 0a6aab51c1f3f0a8c7b5411b66157f764b0344ea Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 13:32:32 +0200 Subject: [PATCH 41/63] Add php files to linter --- bin/phpcs-whitelist.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/phpcs-whitelist.js b/bin/phpcs-whitelist.js index 5dc98927608d2..d3b5b3b60ceb2 100644 --- a/bin/phpcs-whitelist.js +++ b/bin/phpcs-whitelist.js @@ -8,10 +8,12 @@ module.exports = [ 'functions.global.php', 'functions.opengraph.php', '_inc/lib/debugger/', + '_inc/lib/core-api/wpcom-endpoints/memberships.php', '_inc/lib/class.jetpack-password-checker.php', 'modules/masterbar/', + 'modules/memberships/class-jetpack-memberships.php', 'modules/module-extras.php', 'modules/module-info.php', 'modules/theme-tools/social-menu/', - 'modules/wpcom-block-editor/class-jetpack-wpcom-block-editor.php', + 'modules/wpcom-block-editor/class-jetpack-wpcom-block-editor.php' ]; From cc0343af73d70bab3f68d669404d9d2135f132b8 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 16:11:08 +0200 Subject: [PATCH 42/63] jetpack-memberships class moved on wpcom --- .../membership-button/membership-button.php | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/extensions/blocks/membership-button/membership-button.php b/extensions/blocks/membership-button/membership-button.php index 530ca0b774f1c..7605e05e98e3e 100644 --- a/extensions/blocks/membership-button/membership-button.php +++ b/extensions/blocks/membership-button/membership-button.php @@ -1,4 +1,4 @@ - array( Jetpack_Memberships::get_instance(), 'render_button' ), - ) - ); -} +jetpack_register_block( + 'jetpack/membership-button', + array( + 'render_callback' => array( Jetpack_Memberships::get_instance(), 'render_button' ), + ) +); From 579e738cb287bdac5cbfb6561a1429bfa3f43279 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 18:00:40 +0200 Subject: [PATCH 43/63] make call to wpcom as a user --- extensions/blocks/membership-button/edit.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index f0019cc44aff6..1921bb53dbbe8 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -316,6 +316,7 @@ class MembershipsButtonEdit extends Component { ) } { ! this.props.attributes.planId && + this.state.addingMembershipAmount !== PRODUCT_FORM_SUBMITTED && connected === API_STATE_CONNECTED && products.length > 0 && ( From 7730f212ee1177e93224725aa3101fc594be5609 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 18:01:08 +0200 Subject: [PATCH 44/63] now really make it as a user, this is the php file --- _inc/lib/core-api/wpcom-endpoints/memberships.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index 57db08b10aa3f..e0bdfa5a6b137 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -105,9 +105,9 @@ public function create_product( $request ) { return $product->to_array(); } else { $blog_id = Jetpack_Options::get_option( 'id' ); - $response = Jetpack_Client::wpcom_json_api_request_as_blog( + $response = Jetpack_Client::wpcom_json_api_request_as_user( "/sites/$blog_id/{$this->rest_base}/product", - '2', + 'v2', array( 'method' => 'POST', ), @@ -116,8 +116,7 @@ public function create_product( $request ) { 'price' => $request['price'], 'currency' => $request['currency'], 'interval' => $request['interval'], - ), - 'wpcom' + ) ); if ( is_wp_error( $response ) ) { return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com', 'jetpack' ), 404 ); From ad22f80ab2d3669864f6d94224f7374c67222102 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 2 Apr 2019 18:28:10 +0200 Subject: [PATCH 45/63] Add missing textdomains --- extensions/blocks/membership-button/edit.jsx | 41 +++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index 1921bb53dbbe8..b644838c90c07 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -157,13 +157,13 @@ class MembershipsButtonEdit extends Component {
- { __( 'Add Amount' ) } + { __( 'Add Amount', 'jetpack' ) }
@@ -249,7 +249,7 @@ class MembershipsButtonEdit extends Component { const inspectorControls = ( - + ) } { ! this.props.attributes.planId && connected === API_STATE_NOTCONNECTED && ( - +
- { __( 'In order to start selling Membership plans, you have to connect to Stripe:' ) } + { __( + 'In order to start selling Membership plans, you have to connect to Stripe:', + 'jetpack' + ) }



@@ -306,9 +309,9 @@ class MembershipsButtonEdit extends Component { { ! this.props.attributes.planId && connected === API_STATE_CONNECTED && products.length === 0 && ( - +
- { __( 'Add your first Membership amount:' ) } + { __( 'Add your first Membership amount:', 'jetpack' ) }

{ this.renderAddMembershipAmount() } @@ -319,11 +322,11 @@ class MembershipsButtonEdit extends Component { this.state.addingMembershipAmount !== PRODUCT_FORM_SUBMITTED && connected === API_STATE_CONNECTED && products.length > 0 && ( - +
- { __( 'Select payment amount:' ) } + { __( 'Select payment amount:', 'jetpack' ) } { this.renderMembershipAmounts() } - { __( 'Or add another membership amount:' ) } + { __( 'Or add another membership amount:', 'jetpack' ) }
{ this.renderAddMembershipAmount() }
From f5d8d68feeb398c4435b886b44fc3791aead0558 Mon Sep 17 00:00:00 2001 From: artpi Date: Thu, 4 Apr 2019 13:12:54 +0200 Subject: [PATCH 46/63] Handle message to pass the iframe modal --- extensions/blocks/membership-button/view.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/extensions/blocks/membership-button/view.js b/extensions/blocks/membership-button/view.js index 1766f9057a90e..df4016f9dea9e 100644 --- a/extensions/blocks/membership-button/view.js +++ b/extensions/blocks/membership-button/view.js @@ -1,4 +1,4 @@ -/* global tb_show */ +/* global tb_show, tb_remove */ /** * Internal dependencies @@ -7,6 +7,22 @@ import './view.scss'; const name = 'membership-button'; const blockClassName = 'wp-block-jetpack-' + name; +/** + * Since "close" button is inside our checkout iframe, in order to close it, it has to pass a message to higher scope to close the modal. + * + * @param {event} eventFromIframe - message event that gets emmited in the checkout iframe. + * @listens message + */ +function handleIframeResult( eventFromIframe ) { + if ( eventFromIframe.origin === 'https://subscribe.wordpress.com' && eventFromIframe.data ) { + const data = JSON.parse( eventFromIframe.data ); + if ( data && data.action === 'close' ) { + window.removeEventListener( 'message', handleIframeResult ); + tb_remove(); + } + } +} + function activateSubscription( block, blogId, planId, poweredText ) { block.addEventListener( 'click', () => { tb_show( @@ -18,6 +34,7 @@ function activateSubscription( block, blogId, planId, poweredText ) { 'TB_iframe=true&height=600&width=400', null ); + window.addEventListener( 'message', handleIframeResult, false ); const tbWindow = document.querySelector( '#TB_window' ); tbWindow.classList.add( 'jetpack-memberships-modal' ); const footer = document.createElement( 'DIV' ); From 6c3423ca9f5d37e90e9e8aab28c9da50b858e110 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Thu, 4 Apr 2019 12:20:52 -0400 Subject: [PATCH 47/63] Update color hex's to become Muriel variables @simison I did not see where https://github.com/Automattic/color-studio/blob/546e4ed57ec2426246049096 fbd3064e1d4ecfb0/dist/color-properties.css was being pulled in. I sort of did a half and half approach to what you suggested. Happy to change this up based on your feedback. --- extensions/blocks/membership-button/view.scss | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/extensions/blocks/membership-button/view.scss b/extensions/blocks/membership-button/view.scss index 8e8af9f93b0de..876683b77d66a 100644 --- a/extensions/blocks/membership-button/view.scss +++ b/extensions/blocks/membership-button/view.scss @@ -1,12 +1,18 @@ /* Additional styling to thickbox that displays modal */ /* stylelint-disable selector-max-id */ +// @TODO: Replace with Gutenberg variables +$--muriel-gray-0: #f6f6f6; +$--muriel-gray-50: #e1e2e2; +$--muriel-blue-200: #95adc1; +$--muriel-hot-blue-500: #005fb7; + .jetpack-memberships-modal #TB_title { border-radius: 4px 4px 0 0; } #TB_window.jetpack-memberships-modal { border-radius: 4px; - background-color: #f9f9f9; + background-color: $--muriel-gray-0; background-image: url( 'https://s0.wp.com/i/loading/loading-64.gif' ); background-repeat: no-repeat; background-position: center; @@ -36,8 +42,8 @@ height: calc( 100% - 80px ) !important; } .jetpack-memberships-modal .TB_footer { - border-top: 1px solid #ddd; - color: #a5b2bd; + border-top: 1px solid $--muriel-gray-50; + color: $--muriel-blue-200; font-size: 13px; padding: 4px 0; text-align: center; @@ -45,5 +51,5 @@ .jetpack-memberships-modal .TB_footer a, .jetpack-memberships-modal .TB_footer a:hover, .jetpack-memberships-modal .TB_footer a:visited { - color: #33bbe3; + color: $--muriel-hot-blue-500; } From 45682bbda5d60eacfff85b13fa41392eebcc5632 Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 5 Apr 2019 11:43:57 +0200 Subject: [PATCH 48/63] Review feedback - some protection --- _inc/lib/core-api/wpcom-endpoints/memberships.php | 4 ++-- modules/memberships/class-jetpack-memberships.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index e0bdfa5a6b137..ec7429b6b6119 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -156,9 +156,9 @@ public function get_status() { } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; if ( ! $connected_account_id ) { - $connect_url = $data['connect_url']; + $connect_url = empty( $data['connect_url'] ) ? '' : $data['connect_url']; } - $products = $data['products']; + $products = empty( $data['products'] ) ? array() : $data['products']; } return array( 'connected_account_id' => $connected_account_id, diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index a8a5664810c3a..9288afc09d5f7 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -203,7 +203,7 @@ public function render_button( $attrs ) { if ( empty( $attrs['planId'] ) ) { return; } - $id = $attrs['planId']; + $id = intval( $attrs['planId'] ); $product = get_post( $id ); if ( ! $product || is_wp_error( $product ) ) { return; From fc685fa787bba9cd0d24446d0c17b15e6d9fb64b Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 5 Apr 2019 12:20:16 +0200 Subject: [PATCH 49/63] Rename meta name from mem_ to jetpack_memberships_ --- modules/memberships/class-jetpack-memberships.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 9288afc09d5f7..2c1c7cb0bb700 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -67,7 +67,7 @@ public static function get_instance() { * @return array */ private static function get_plan_property_mapping() { - $meta_prefix = 'mem_'; + $meta_prefix = 'jetpack_memberships_'; $properties = array( 'price' => array( 'meta' => $meta_prefix . 'price', From 682fdc50a8d87c2fe9b3b24e0c40508dbbc2fb84 Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 12 Apr 2019 20:04:18 +0200 Subject: [PATCH 50/63] change the var --- modules/memberships/class-jetpack-memberships.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 2c1c7cb0bb700..b9c1562d56eef 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -208,7 +208,7 @@ public function render_button( $attrs ) { if ( ! $product || is_wp_error( $product ) ) { return; } - if ( $product->post_type !== self::$post_type_plan || 'trash' === $product->post_status ) { + if ( $product->post_type !== self::$post_type_plan || 'public' !== $product->post_status ) { return; } From dfce75de2c1239ad0818f3b0b019a747c25faff7 Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 12 Apr 2019 20:05:31 +0200 Subject: [PATCH 51/63] change CSS vars --- extensions/blocks/membership-button/view.scss | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/extensions/blocks/membership-button/view.scss b/extensions/blocks/membership-button/view.scss index 876683b77d66a..cc0eb71c46811 100644 --- a/extensions/blocks/membership-button/view.scss +++ b/extensions/blocks/membership-button/view.scss @@ -1,18 +1,12 @@ /* Additional styling to thickbox that displays modal */ /* stylelint-disable selector-max-id */ -// @TODO: Replace with Gutenberg variables -$--muriel-gray-0: #f6f6f6; -$--muriel-gray-50: #e1e2e2; -$--muriel-blue-200: #95adc1; -$--muriel-hot-blue-500: #005fb7; - .jetpack-memberships-modal #TB_title { border-radius: 4px 4px 0 0; } #TB_window.jetpack-memberships-modal { border-radius: 4px; - background-color: $--muriel-gray-0; + background-color: $muriel-gray-0; background-image: url( 'https://s0.wp.com/i/loading/loading-64.gif' ); background-repeat: no-repeat; background-position: center; @@ -42,8 +36,8 @@ $--muriel-hot-blue-500: #005fb7; height: calc( 100% - 80px ) !important; } .jetpack-memberships-modal .TB_footer { - border-top: 1px solid $--muriel-gray-50; - color: $--muriel-blue-200; + border-top: 1px solid $muriel-gray-50; + color: $muriel-blue-200; font-size: 13px; padding: 4px 0; text-align: center; @@ -51,5 +45,5 @@ $--muriel-hot-blue-500: #005fb7; .jetpack-memberships-modal .TB_footer a, .jetpack-memberships-modal .TB_footer a:hover, .jetpack-memberships-modal .TB_footer a:visited { - color: $--muriel-hot-blue-500; + color: $muriel-hot-blue-500; } From bd5f5e2c71f2918586c1fe2cc4cd9cb274a9a7c6 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 23 Apr 2019 10:32:49 +0200 Subject: [PATCH 52/63] Fixes for changes in the upstream --- extensions/blocks/membership-button/edit.jsx | 2 +- extensions/blocks/membership-button/editor.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index b644838c90c07..ffd6cc9fbe5c4 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -3,7 +3,7 @@ */ import classnames from 'classnames'; -import SubmitButton from '../../utils/submit-button'; +import SubmitButton from '../../shared/submit-button'; import apiFetch from '@wordpress/api-fetch'; import { __ } from '@wordpress/i18n'; import { trimEnd } from 'lodash'; diff --git a/extensions/blocks/membership-button/editor.js b/extensions/blocks/membership-button/editor.js index babee275335fe..d05f403942058 100644 --- a/extensions/blocks/membership-button/editor.js +++ b/extensions/blocks/membership-button/editor.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import registerJetpackBlock from '../../utils/register-jetpack-block'; +import registerJetpackBlock from '../../shared/register-jetpack-block'; import { name, settings } from '.'; registerJetpackBlock( name, settings ); From b4367441b29c58621cb1e465a92e65b1d02d4449 Mon Sep 17 00:00:00 2001 From: artpi Date: Tue, 23 Apr 2019 11:15:19 +0200 Subject: [PATCH 53/63] fix after implementing review feedback --- modules/memberships/class-jetpack-memberships.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index b9c1562d56eef..22849073de8c2 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -208,7 +208,7 @@ public function render_button( $attrs ) { if ( ! $product || is_wp_error( $product ) ) { return; } - if ( $product->post_type !== self::$post_type_plan || 'public' !== $product->post_status ) { + if ( $product->post_type !== self::$post_type_plan || 'publish' !== $product->post_status ) { return; } From b421590103b9caf6a62fe5c992db3785f5ee685d Mon Sep 17 00:00:00 2001 From: artpi Date: Wed, 24 Apr 2019 20:21:50 +0200 Subject: [PATCH 54/63] Change copy for item description --- extensions/blocks/membership-button/edit.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index ffd6cc9fbe5c4..ad682dedc370e 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -175,9 +175,9 @@ class MembershipsButtonEdit extends Component {
Date: Thu, 25 Apr 2019 15:36:22 +0200 Subject: [PATCH 55/63] Code review suggested edits - mostly copy Co-Authored-By: artpi --- _inc/lib/core-api/wpcom-endpoints/memberships.php | 6 +++--- modules/module-extras.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index ec7429b6b6119..fac0ad343379a 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -90,7 +90,7 @@ public function create_product( $request ) { require_lib( 'memberships' ); $connected_destination_account_id = Jetpack_Memberships::get_connected_account_id(); if ( ! $connected_destination_account_id ) { - return new WP_Error( 'no-destination-account', __( 'Please set up Stripe account for this site first', 'jetpack' ) ); + return new WP_Error( 'no-destination-account', __( 'Please set up a Stripe account for this site first', 'jetpack' ) ); } $product = Memberships_Product::create( get_current_blog_id(), @@ -119,7 +119,7 @@ public function create_product( $request ) { ) ); if ( is_wp_error( $response ) ) { - return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com', 'jetpack' ), 404 ); + return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WordPress.com', 'jetpack' ), 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; return $data; @@ -152,7 +152,7 @@ public function get_status() { null ); if ( is_wp_error( $response ) ) { - return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WP.com', 'jetpack' ), 404 ); + return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WordPress.com', 'jetpack' ), 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; if ( ! $connected_account_id ) { diff --git a/modules/module-extras.php b/modules/module-extras.php index 11642e2988586..87d05f2a89534 100644 --- a/modules/module-extras.php +++ b/modules/module-extras.php @@ -42,7 +42,7 @@ $connected_tools = array( 'calypsoify/class.jetpack-calypsoify.php', 'plugin-search.php', - 'memberships/class-jectpack-memberships.php', + 'memberships/class-jetpack-memberships.php', 'simple-payments/simple-payments.php', 'woocommerce-analytics/wp-woocommerce-analytics.php', 'wpcom-block-editor/class-jetpack-wpcom-block-editor.php', From a7761d6e3c31d575ff29001b958985366079edb2 Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 26 Apr 2019 12:10:09 +0100 Subject: [PATCH 56/63] Review feedback: remove unnecessary import --- modules/module-extras.php | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/module-extras.php b/modules/module-extras.php index 87d05f2a89534..989512dcbf516 100644 --- a/modules/module-extras.php +++ b/modules/module-extras.php @@ -42,7 +42,6 @@ $connected_tools = array( 'calypsoify/class.jetpack-calypsoify.php', 'plugin-search.php', - 'memberships/class-jetpack-memberships.php', 'simple-payments/simple-payments.php', 'woocommerce-analytics/wp-woocommerce-analytics.php', 'wpcom-block-editor/class-jetpack-wpcom-block-editor.php', From 4235ae903d5bd2fccb277781d87a37ffe337b8a7 Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 26 Apr 2019 15:30:54 +0100 Subject: [PATCH 57/63] Better feedback where my account is not connected --- _inc/lib/core-api/wpcom-endpoints/memberships.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index fac0ad343379a..6b19d2f747480 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -119,6 +119,9 @@ public function create_product( $request ) { ) ); if ( is_wp_error( $response ) ) { + if ( $response->get_error_code() === 'missing_token' ) { + return new WP_Error( 'missing_token', __( 'Please connect your user account to WordPress.com', 'jetpack' ), 404 ); + } return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WordPress.com', 'jetpack' ), 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; @@ -152,6 +155,9 @@ public function get_status() { null ); if ( is_wp_error( $response ) ) { + if ( $response->get_error_code() === 'missing_token' ) { + return new WP_Error( 'missing_token', __( 'Please connect your user account to WordPress.com', 'jetpack' ), 404 ); + } return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WordPress.com', 'jetpack' ), 404 ); } $data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null; From 9bae01c78a8fcbeab4800e63bf19fdbf1b6f730a Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 26 Apr 2019 15:55:19 +0100 Subject: [PATCH 58/63] Endpoints nly for wpcom/active jetpack --- _inc/lib/core-api/wpcom-endpoints/memberships.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_inc/lib/core-api/wpcom-endpoints/memberships.php b/_inc/lib/core-api/wpcom-endpoints/memberships.php index 6b19d2f747480..f79cf5560dbca 100644 --- a/_inc/lib/core-api/wpcom-endpoints/memberships.php +++ b/_inc/lib/core-api/wpcom-endpoints/memberships.php @@ -173,4 +173,8 @@ public function get_status() { ); } } -wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Memberships' ); + +if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) || Jetpack::is_active() ) { + wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Memberships' ); +} + From 4c3153d9593dca0e359d9385a099ce30f4eb533e Mon Sep 17 00:00:00 2001 From: artpi Date: Fri, 26 Apr 2019 16:20:30 +0100 Subject: [PATCH 59/63] remove unused function --- .../memberships/class-jetpack-memberships.php | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 22849073de8c2..76c526a6baa1a 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -79,24 +79,6 @@ private static function get_plan_property_mapping() { return $properties; } - /** - * Transform WP CPT post into array representing a memberships product. - * - * @param WP_Post $product_post - CPT representing the product. - * @return array - */ - public static function product_post_to_array( $product_post ) { - $data = array(); - $mapping = self::get_plan_property_mapping(); - foreach ( $mapping as $key => $map ) { - $data[ $key ] = get_post_meta( $product_post->ID, $map['meta'], true ); - } - $data['title'] = $product_post->post_title; - $data['description'] = $product_post->post_content; - $data['id'] = $product_post->ID; - return $data; - } - /** * Inits further hooks on init hook. */ From fea7f0be71d326291744d79617596894175d6499 Mon Sep 17 00:00:00 2001 From: artpi Date: Sat, 27 Apr 2019 11:42:12 +0100 Subject: [PATCH 60/63] Additional check if JP is active --- .../membership-button/membership-button.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/extensions/blocks/membership-button/membership-button.php b/extensions/blocks/membership-button/membership-button.php index 7605e05e98e3e..d8488cf22b893 100644 --- a/extensions/blocks/membership-button/membership-button.php +++ b/extensions/blocks/membership-button/membership-button.php @@ -7,11 +7,13 @@ * @package Jetpack */ -require_once JETPACK__PLUGIN_DIR . '/modules/memberships/class-jetpack-memberships.php'; +if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) || Jetpack::is_active() ) { + require_once JETPACK__PLUGIN_DIR . '/modules/memberships/class-jetpack-memberships.php'; -jetpack_register_block( - 'jetpack/membership-button', - array( - 'render_callback' => array( Jetpack_Memberships::get_instance(), 'render_button' ), - ) -); + jetpack_register_block( + 'jetpack/membership-button', + array( + 'render_callback' => array( Jetpack_Memberships::get_instance(), 'render_button' ), + ) + ); +} From 81c6d9cd61671e56415fce4218a4a6efbc88cc1f Mon Sep 17 00:00:00 2001 From: artpi Date: Sat, 27 Apr 2019 12:17:50 +0100 Subject: [PATCH 61/63] Pass Lang to subscribe form --- extensions/blocks/membership-button/view.js | 7 +++++-- modules/memberships/class-jetpack-memberships.php | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/extensions/blocks/membership-button/view.js b/extensions/blocks/membership-button/view.js index df4016f9dea9e..6e10a1d3bcfd1 100644 --- a/extensions/blocks/membership-button/view.js +++ b/extensions/blocks/membership-button/view.js @@ -23,7 +23,7 @@ function handleIframeResult( eventFromIframe ) { } } -function activateSubscription( block, blogId, planId, poweredText ) { +function activateSubscription( block, blogId, planId, poweredText, lang ) { block.addEventListener( 'click', () => { tb_show( null, @@ -31,6 +31,8 @@ function activateSubscription( block, blogId, planId, poweredText ) { blogId + '&plan=' + planId + + '&lang=' + + lang + 'TB_iframe=true&height=600&width=400', null ); @@ -51,6 +53,7 @@ const initializeMembershipButtonBlocks = () => { membershipButtonBlocks.forEach( block => { const blogId = block.getAttribute( 'data-blog-id' ); const planId = block.getAttribute( 'data-plan-id' ); + const lang = block.getAttribute( 'data-lang' ); const poweredText = block .getAttribute( 'data-powered-text' ) .replace( @@ -58,7 +61,7 @@ const initializeMembershipButtonBlocks = () => { 'WordPress.com' ); try { - activateSubscription( block, blogId, planId, poweredText ); + activateSubscription( block, blogId, planId, poweredText, lang ); } catch ( err ) { // eslint-disable-next-line no-console console.error( 'Problem activating Membership Button ' + planId, err ); diff --git a/modules/memberships/class-jetpack-memberships.php b/modules/memberships/class-jetpack-memberships.php index 76c526a6baa1a..989d4e966dbea 100644 --- a/modules/memberships/class-jetpack-memberships.php +++ b/modules/memberships/class-jetpack-memberships.php @@ -236,10 +236,11 @@ public function render_button( $attrs ) { $button_styles = implode( $button_styles, ';' ); add_thickbox(); return sprintf( - '', + '', esc_attr( $data['blog_id'] ), esc_attr( $data['powered_text'] ), esc_attr( $data['id'] ), + esc_attr( get_locale() ), esc_attr( implode( $classes, ' ' ) ), esc_attr( $button_styles ), esc_html( $data['button_label'] ) From 7956f6a6996380eb84d98279b05a36e69f9f2a1e Mon Sep 17 00:00:00 2001 From: artpi Date: Sat, 27 Apr 2019 15:37:20 +0100 Subject: [PATCH 62/63] error catching --- extensions/blocks/membership-button/edit.jsx | 40 +++++++++++++++---- .../blocks/membership-button/editor.scss | 5 +++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/extensions/blocks/membership-button/edit.jsx b/extensions/blocks/membership-button/edit.jsx index ad682dedc370e..2fe8d942ec2d5 100644 --- a/extensions/blocks/membership-button/edit.jsx +++ b/extensions/blocks/membership-button/edit.jsx @@ -44,7 +44,9 @@ class MembershipsButtonEdit extends Component { products: [], editedProductCurrency: 'USD', editedProductPrice: 5, + editedProductPriceValid: true, editedProductTitle: '', + editedProductTitleValid: true, editedProductRenewInterval: '1 month', }; this.timeout = null; @@ -95,16 +97,31 @@ class MembershipsButtonEdit extends Component { handlePriceChange = price => { price = parseFloat( price ); - if ( ! isNaN( price ) ) { - this.setState( { editedProductPrice: price } ); - } else { - this.setState( { editedProductPrice: undefined } ); - } + this.setState( { + editedProductPrice: price, + editedProductPriceValid: ! isNaN( price ) && price >= 5, + } ); }; - handleTitleChange = editedProductTitle => this.setState( { editedProductTitle } ); + handleTitleChange = editedProductTitle => + this.setState( { + editedProductTitle, + editedProductTitleValid: editedProductTitle.length > 0, + } ); // eslint-disable-next-line saveProduct = () => { + if ( ! this.state.editedProductTitle || this.state.editedProductTitle.length === 0 ) { + this.setState( { editedProductTitleValid: false } ); + return; + } + if ( + ! this.state.editedProductPrice || + isNaN( this.state.editedProductPrice ) || + this.state.editedProductPrice < 5 + ) { + this.setState( { editedProductPriceValid: false } ); + return; + } this.setState( { addingMembershipAmount: PRODUCT_FORM_SUBMITTED } ); const path = '/wpcom/v2/memberships/product'; const method = 'POST'; @@ -164,7 +181,11 @@ class MembershipsButtonEdit extends Component { />
Date: Mon, 29 Apr 2019 23:44:45 +0200 Subject: [PATCH 63/63] PHPCS whitelist: add the whole new module folder to the pre-commit --- bin/phpcs-whitelist.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/phpcs-whitelist.js b/bin/phpcs-whitelist.js index d3b5b3b60ceb2..8e03e5a172d12 100644 --- a/bin/phpcs-whitelist.js +++ b/bin/phpcs-whitelist.js @@ -11,9 +11,9 @@ module.exports = [ '_inc/lib/core-api/wpcom-endpoints/memberships.php', '_inc/lib/class.jetpack-password-checker.php', 'modules/masterbar/', - 'modules/memberships/class-jetpack-memberships.php', + 'modules/memberships/', 'modules/module-extras.php', 'modules/module-info.php', 'modules/theme-tools/social-menu/', - 'modules/wpcom-block-editor/class-jetpack-wpcom-block-editor.php' + 'modules/wpcom-block-editor/class-jetpack-wpcom-block-editor.php', ];