Completed
Push — feature/simple-payments ( acd858...d88e95 )
by
unknown
39s
created

Jetpack_Simple_Payments::output_shortcode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
nc 2
nop 1
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/*
3
 * Simple Payments lets users embed a PayPal button fully integrated with wpcom to sell products on the site.
4
 * This is not a proper module yet, because not all the pieces are in place. Until everything is shipped, it can be turned
5
 * into module that can be enabled/disabled.
6
 * TODO: Once the feature is fully shipped, create a file modules/simple-payments.php with a proper header to turn module on/off.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
7
*/
8
class Jetpack_Simple_Payments {
9
	// These have to be under 20 chars because that is CPT limit.
10
	static $post_type_order = 'jp_pay_order';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $post_type_order.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
11
	static $post_type_product = 'jp_pay_product';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $post_type_product.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
12
13
	static $shortcode = 'simple-payment';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $shortcode.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
14
15
	// Classic singleton pattern:
16
	private static $instance;
17
	private function __construct() {}
18
	static function getInstance() {
19
		if ( ! self::$instance ) {
20
			self::$instance = new self();
21
			self::$instance->register_init_hook();
22
		}
23
		return self::$instance;
24
	}
25
26
	private function register_scripts() {
27
		/**
28
		 * Paypal heavily discourages putting that script in your own server:
29
		 * @see https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/add-paypal-button/
30
		 */
31
		wp_register_script( 'paypal-checkout-js', 'https://www.paypalobjects.com/api/checkout.js' );
32
		wp_register_script( 'paypal-express-checkout', plugins_url( '/paypal-express-checkout.js', __FILE__ ) , array( 'paypal-checkout-js' ), '0.21' );
33
	}
34
	private function register_init_hook() {
35
		add_action( 'init', array( $this, 'init_hook_action' ) );
36
	}
37
	private function register_shortcode() {
38
		add_shortcode( self::$shortcode, array( $this, 'parse_shortcode' ) );
39
	}
40
41
	public function init_hook_action() {
42
		add_filter( 'rest_api_allowed_post_types', array( $this, 'allow_rest_api_types' ) );
43
		add_filter( 'jetpack_sync_post_meta_whitelist', array( $this, 'allow_sync_post_meta' ) );
44
		$this->register_scripts();
45
		$this->register_shortcode();
46
		$this->setup_cpts();
47
	}
48
49
	function parse_shortcode( $attrs, $content = false ) {
50
		if ( empty( $attrs['id'] ) ) {
51
			return;
52
		}
53
		$product = get_post( $attrs['id'] );
54
		if ( ! $product || is_wp_error( $product ) ) {
55
			return;
56
		}
57
		if ( $product->post_type !== self::$post_type_product ) {
58
			return;
59
		}
60
61
		// We allow for overriding the presentation labels
62
		$data = shortcode_atts( array(
63
			'blog_id' => Jetpack_Options::get_option( 'id' ),
64
			'dom_id' => uniqid( 'jetpack-simple-payments-' . $product->ID . '_', true ),
65
			'class' => 'jetpack-simple-payments-' . $product->ID,
66
			'title' => get_the_title( $product ),
67
			'description' => $product->post_content,
68
			'cta' => get_post_meta( $product->ID, 'spay_cta', true ),
69
			'multiple' => get_post_meta( $product->ID, 'spay_multiple', true ) || '0'
70
		), $attrs );
71
		$data['price'] = $this->format_price(
72
			get_post_meta( $product->ID, 'spay_price', true ),
73
			get_post_meta( $product->ID, 'spay_currency', true ),
74
			$data
75
		);
76
77
		if ( ! wp_script_is( 'paypal-express-checkout','enqueued' ) ) {
78
			wp_enqueue_script( 'paypal-express-checkout' );
79
		}
80
81
		wp_add_inline_script( 'paypal-express-checkout', "try{PaypalExpressCheckout.renderButton( '{$data['blog_id']}', '{$attrs['id']}', '{$data['dom_id']}', '{$data['multiple']}' );}catch(e){}" );
82
83
		return $this->output_shortcode( $data );
84
	}
85
86
	function output_shortcode( $data ) {
87
		$items = '';
88
		if ( $data['multiple'] ) {
89
		       $items="<div class='jetpack-simple-payments-items'>
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 0 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
90
		       <input class='jetpack-simple-payments-items-number' type='number' value='1' id='{$data['dom_id']}_number'>
91
		       </div>";
92
		}
93
		$output = "
94
<div class='{$data[ 'class' ]} jetpack-simple-payments-wrapper'>
95
	<div class='jetpack-simple-payments-title'>{$data['title']}</div>
96
	<div class='jetpack-simple-payments-description'>{$data['description']}</div>
97
	<div class='jetpack-simple-payments-price'>{$data['price']}</div>
98
	{$items}
99
	<div class='jetpack-simple-payments-button' id='{$data['dom_id']}_button'></div>
100
</div>
101
";
102
		return $output;
103
	}
104
105
	function format_price( $price, $currency, $all_data ) {
106
		// TODO: better price formatting logic. Extracting from woocmmerce is not a solution since its bound with woo site options.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
107
		return "$price $currency";
108
	}
109
110
	/**
111
	 * Allows custom post types to be used by REST API.
112
	 * @param $post_types
113
	 * @see hook 'rest_api_allowed_post_types'
114
	 * @return array
115
	 */
116
	function allow_rest_api_types( $post_types ) {
117
		$post_types[] = self::$post_type_order;
118
		$post_types[] = self::$post_type_product;
119
		return $post_types;
120
	}
121
122
	function allow_sync_post_meta( $post_meta ) {
123
		return array_merge( $post_meta, array(
124
			'spay_paypal_id',
125
			'spay_status',
126
			'spay_product_id',
127
			'spay_quantity',
128
			'spay_price',
129
			'spay_customer_email',
130
			'spay_currency',
131
			'spay_cta',
132
			'spay_email',
133
			'spay_multiple'
134
		) );
135
	}
136
137
	/**
138
	 * Sets up the custom post types for the module.
139
	 */
140
	function setup_cpts() {
141
142
		/*
143
		 * ORDER data structure. holds:
144
		 * title = customer_name | 4xproduct_name
145
		 * excerpt = customer_name + customer contact info + customer notes from paypal form
146
		 * metadata:
147
		 * spay_paypal_id - paypal id of transaction
148
		 * spay_status
149
		 * spay_product_id - post_id of bought product
150
		 * spay_quantity - quantity of product
151
		 * spay_price - item price at the time of purchase
152
		 * spay_customer_email - customer email
153
		 * ... (WIP)
154
		 */
155
		$order_capabilities = array(
156
			'edit_post'             => 'edit_posts',
157
			'read_post'             => 'read_private_posts',
158
			'delete_post'           => 'delete_posts',
159
			'edit_posts'            => 'edit_posts',
160
			'edit_others_posts'     => 'edit_others_posts',
161
			'publish_posts'         => 'publish_posts',
162
			'read_private_posts'    => 'read_private_posts',
163
		);
164
		$order_args = array(
165
			'label'                 => esc_html__( 'Order', 'jetpack' ),
166
			'description'           => esc_html__( 'Simple Payments orders', 'jetpack' ),
167
			'supports'              => array( 'custom-fields', 'excerpt' ),
168
			'hierarchical'          => false,
169
			'public'                => false,
170
			'show_ui'               => false,
171
			'show_in_menu'          => false,
172
			'show_in_admin_bar'     => false,
173
			'show_in_nav_menus'     => false,
174
			'can_export'            => true,
175
			'has_archive'           => false,
176
			'exclude_from_search'   => true,
177
			'publicly_queryable'    => false,
178
			'rewrite'               => false,
179
			'capabilities'          => $order_capabilities,
180
			'show_in_rest'          => true,
181
		);
182
		register_post_type( self::$post_type_order, $order_args );
183
184
		/*
185
		 * PRODUCT data structure. Holds:
186
		 * title - title
187
		 * content - description
188
		 * thumbnail - image
189
		 * metadata:
190
		 * spay_price - price
191
		 * spay_currency - currency code
192
		 * spay_cta - text with "Buy" or other CTA
193
		 * spay_email - paypal email
194
		 * spay_multiple - allow for multiple items
195
		 * spay_status - status. { enabled | disabled }
196
		 */
197
		$product_capabilities = array(
198
			'edit_post'             => 'edit_posts',
199
			'read_post'             => 'read_private_posts',
200
			'delete_post'           => 'delete_posts',
201
			'edit_posts'            => 'edit_posts',
202
			'edit_others_posts'     => 'edit_others_posts',
203
			'publish_posts'         => 'publish_posts',
204
			'read_private_posts'    => 'read_private_posts',
205
		);
206
		$product_args = array(
207
			'label'                 => esc_html__( 'Product', 'jetpack' ),
208
			'description'           => esc_html__( 'Simple Payments products', 'jetpack' ),
209
			'supports'              => array( 'title', 'editor','thumbnail', 'custom-fields' ),
210
			'hierarchical'          => false,
211
			'public'                => false,
212
			'show_ui'               => false,
213
			'show_in_menu'          => false,
214
			'show_in_admin_bar'     => false,
215
			'show_in_nav_menus'     => false,
216
			'can_export'            => true,
217
			'has_archive'           => false,
218
			'exclude_from_search'   => true,
219
			'publicly_queryable'    => false,
220
			'rewrite'               => false,
221
			'capabilities'          => $product_capabilities,
222
			'show_in_rest'          => true,
223
		);
224
		register_post_type( self::$post_type_product, $product_args );
225
	}
226
227
}
228
Jetpack_Simple_Payments::getInstance();
229