Issues (8)

src/BlockUpdater.php (3 issues)

1
<?php
2
/**
3
 * Block updater.
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2021 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay
9
 */
10
11
namespace Pronamic\WordPress\Pay\Fundraising;
12
13
use Pronamic\WordPress\Money\Money;
14
use Pronamic\WordPress\Money\Parser;
15
use WP_Post;
16
17
/**
18
 * Addon.
19
 *
20
 * @author  Reüel van der Steege
21
 * @since   1.0.0
22
 * @version 1.0.0
23
 */
24
class BlockUpdater {
25
	/**
26
	 * Block names.
27
	 *
28
	 * @var array
29
	 */
30
	public $block_names;
31
32
	/**
33
	 * Add raised money.
34
	 *
35
	 * @var Money|null
36
	 */
37
	public $add_raised;
38
39
	/**
40
	 * Target amount.
41
	 *
42
	 * @var Money|null
43
	 */
44
	public $target_amount;
45
46
	/**
47
	 * Raised amount.
48
	 *
49
	 * @var Money|null
50
	 */
51
	public $raised_amount;
52
53
	/**
54
	 * Number of contributions.
55
	 *
56
	 * @var int|null
57
	 */
58
	public $contributions;
59
60
	/**
61
	 * Block updater constructor.
62
	 */
63
	public function __construct() {
64
		$this->block_names = array(
65
			'pronamic-pay/fundraising-progress-circle',
66
			'pronamic-pay/fundraising-progress-bar',
67
			'pronamic-pay/fundraising-progress-text',
68
		);
69
	}
70
71
	/**
72
	 * Add raised money.
73
	 *
74
	 * @param Money $add Money to add to raised amount.
75
	 * @return void
76
	 */
77
	public function add_raised_money( Money $add ) {
78
		$this->add_raised = $add;
79
	}
80
81
	/**
82
	 * Update post.
83
	 *
84
	 * @param WP_Post $post Post to update fundraising blocks in.
85
	 */
86
	public function update_post( WP_Post $post ) {
87
		$post_content = $post->post_content;
88
89
		if ( ! \has_blocks( $post_content ) ) {
90
			return;
91
		}
92
93
		if ( null === $this->add_raised ) {
94
			return;
95
		}
96
97
		$updated_content = $this->update_content( $post_content );
98
99
		if ( $updated_content === $post_content ) {
100
			return;
101
		}
102
103
		// Temporary allow unfiltered HTML for `transform` CSS attribute.
104
		\add_filter( 'user_has_cap', array( $this, 'allow_unfiltered_html' ), 10, 2 );
105
106
		\kses_init();
107
108
		// Update post.
109
		\wp_update_post(
110
			array(
111
				'ID'           => $post->ID,
112
				'post_content' => $updated_content,
113
			)
114
		);
115
116
		\remove_filter( 'user_has_cap', array( $this, 'allow_unfiltered_html' ) );
117
118
		\kses_init();
119
	}
120
121
	/**
122
	 * Allow unfiltered HTML.
123
	 *
124
	 * @param array $capabilities Capabilities.
125
	 * @param array $capability Capability.
126
	 * @return array
127
	 */
128
	public function allow_unfiltered_html( $capabilities, $capability ) {
129
		if ( in_array( 'unfiltered_html', $capability, true ) ) {
130
			$capabilities['unfiltered_html'] = true;
131
		}
132
133
		return $capabilities;
134
	}
135
136
	/**
137
	 * Update content.
138
	 *
139
	 * @param string $post_content Post content.
140
	 * @return string
141
	 */
142
	public function update_content( $post_content ) {
143
		$blocks = \parse_blocks( $post_content );
144
145
		foreach ( $blocks as &$block ) {
146
			$block = $this->update_block( $block );
147
		}
148
149
		// Serialize blocks.
150
		$updated_content = \serialize_blocks( $blocks );
0 ignored issues
show
$blocks of type array<mixed,array> is incompatible with the type WP_Block_Parser_Block[] expected by parameter $blocks of serialize_blocks(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

150
		$updated_content = \serialize_blocks( /** @scrutinizer ignore-type */ $blocks );
Loading history...
151
152
		return $updated_content;
153
	}
154
155
	/**
156
	 * Update block.
157
	 *
158
	 * @param array $block Block to update.
159
	 * @return array
160
	 */
161
	public function update_block( $block ) {
162
		// Update fundraising block.
163
		if ( \in_array( $block['blockName'], $this->block_names, true ) ) {
164
			$block = $this->update_fundraising_block( $block );
165
		}
166
167
		// Update inner blocks.
168
		if ( \array_key_exists( 'innerBlocks', $block ) ) {
169
			foreach ( $block['innerBlocks'] as &$inner_block ) {
170
				$inner_block = $this->update_block( $inner_block );
171
			}
172
		}
173
174
		return $block;
175
	}
176
177
	/**
178
	 * Update fundraising block.
179
	 *
180
	 * @param array $block Block.
181
	 * @return array
182
	 */
183
	public function update_fundraising_block( $block ) {
184
		$parser = new Parser();
185
186
		// Get target amount for use when updating inner blocks.
187
		if ( ! \array_key_exists( 'targetAmount', $block['attrs'] ) ) {
188
			$block['attrs']['targetAmount'] = 0;
189
		}
190
191
		// Try parsing `targetAmount` block attribute.
192
		try {
193
			$this->target_amount = $parser->parse( $block['attrs']['targetAmount'] );
194
		} catch ( \Exception $e ) {
195
			$this->target_amount = null;
196
		}
197
198
		// Set raised amount.
199
		if ( ! \array_key_exists( 'raisedAmount', $block['attrs'] ) ) {
200
			$block['attrs']['raisedAmount'] = 0;
201
		}
202
203
		// Try parsing and updating `raisedAmount` block attribute.
204
		try {
205
			$this->raised_amount = $parser->parse( $block['attrs']['raisedAmount'] );
206
207
			$this->raised_amount = $this->raised_amount->add( $this->add_raised );
0 ignored issues
show
It seems like $this->add_raised can also be of type null; however, parameter $addend of Pronamic\WordPress\Money\Money::add() does only seem to accept Pronamic\WordPress\Money\Money, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

207
			$this->raised_amount = $this->raised_amount->add( /** @scrutinizer ignore-type */ $this->add_raised );
Loading history...
208
209
			$this->raised_amount->set_currency( $this->add_raised->get_currency() );
210
211
			// Update block attributes.
212
			$block['attrs']['raisedAmount']     = \number_format( $this->raised_amount->get_value(), 2, '.', '' );
0 ignored issues
show
$this->raised_amount->get_value() of type string is incompatible with the type double expected by parameter $num of number_format(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

212
			$block['attrs']['raisedAmount']     = \number_format( /** @scrutinizer ignore-type */ $this->raised_amount->get_value(), 2, '.', '' );
Loading history...
213
			$block['attrs']['currencyCode']     = $this->raised_amount->get_currency()->get_alphabetic_code();
214
			$block['attrs']['currencyDecimals'] = $this->raised_amount->get_currency()->get_number_decimals();
215
			$block['attrs']['locale']           = str_replace( '_', '-', \get_locale() );
216
		} catch ( \Exception $e ) {
217
			$this->raised_amount = null;
218
		}
219
220
		// Set number of contributions.
221
		if ( ! \array_key_exists( 'contributionsValue', $block['attrs'] ) ) {
222
			$block['attrs']['contributionsValue'] = 0;
223
		}
224
225
		$this->contributions = 1 + \intval( $block['attrs']['contributionsValue'] );
226
227
		$block['attrs']['contributionsValue'] = strval( $this->contributions );
228
229
		return $block;
230
	}
231
}
232