Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.64% covered (warning)
85.64%
155 / 181
33.33% covered (danger)
33.33%
5 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
Settings
85.64% covered (warning)
85.64%
155 / 181
33.33% covered (danger)
33.33%
5 / 15
47.23
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 migrate_old_option
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
7
 register_settings
100.00% covered (success)
100.00%
100 / 100
100.00% covered (success)
100.00%
1 / 1
1
 get_image_generator_settings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_utm_settings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_social_notes_config
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 should_show_pricing_page
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_social_notes_enabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_settings
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
3.01
 get_initial_state
n/a
0 / 0
n/a
0 / 0
1
 update_settings
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
72
 update_social_image_generator_settings
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
3.07
 is_sig_available
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 sig_get_default_template
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 sig_get_default_image_id
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
 sig_get_default_font
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * Settings class.
4 *
5 * @package automattic/jetpack-publicize
6 */
7
8namespace Automattic\Jetpack\Publicize\Jetpack_Social_Settings;
9
10use Automattic\Jetpack\Modules;
11use Automattic\Jetpack\Publicize\Social_Image_Generator\Templates;
12
13/**
14 * This class is used to get and update Jetpack_Social_Settings.
15 * Currently supported features:
16 *      - Social Image Generator
17 *      - UTM Settings
18 *      - Social Notes
19 *
20 * @phan-constructor-used-for-side-effects
21 */
22class Settings {
23    /**
24     * Name of the database option.
25     *
26     * @var string
27     */
28    const OPTION_PREFIX            = 'jetpack_social_';
29    const IMAGE_GENERATOR_SETTINGS = 'image_generator_settings';
30
31    const DEFAULT_IMAGE_GENERATOR_SETTINGS = array(
32        'enabled'  => false,
33        'template' => Templates::DEFAULT_TEMPLATE,
34    );
35
36    const UTM_SETTINGS = 'utm_settings';
37
38    const DEFAULT_UTM_SETTINGS = array(
39        'enabled' => false,
40    );
41
42    const NOTES_CONFIG = 'notes_config';
43
44    const DEFAULT_NOTES_CONFIG = array(
45        'append_link' => true,
46    );
47
48    // Legacy named options.
49    const JETPACK_SOCIAL_NOTE_CPT_ENABLED   = 'jetpack-social-note';
50    const JETPACK_SOCIAL_SHOW_PRICING_PAGE  = 'jetpack-social_show_pricing_page';
51    const NOTES_FLUSH_REWRITE_RULES_FLUSHED = 'jetpack_social_rewrite_rules_flushed';
52
53    /**
54     * Whether the actions have been hooked into.
55     *
56     * @var bool
57     */
58    protected static $actions_hooked_in = false;
59
60    /**
61     * Constructor.
62     */
63    public function __construct() {
64
65        if ( ! self::$actions_hooked_in ) {
66            add_action( 'rest_api_init', array( $this, 'register_settings' ) );
67            add_action( 'admin_init', array( $this, 'register_settings' ) );
68
69            self::$actions_hooked_in = true;
70        }
71    }
72
73    /**
74     * Migrate old options to the new settings. Previously SIG settings were stored in the
75     * jetpack_social_image_generator_settings option. Now they are stored in the jetpack_social_settings.
76     *
77     * TODO: Work out if this is possible on plugin upgrade
78     *
79     * @return void
80     */
81    private function migrate_old_option() {
82        // Delete the old options if they exist.
83        if ( get_option( 'jetpack_social_settings' ) ) {
84            delete_option( 'jetpack_social_settings' );
85        }
86        if ( get_option( 'jetpack_social_autoconvert_images' ) ) {
87            delete_option( 'jetpack_social_autoconvert_images' );
88        }
89
90        $sig_settings = get_option( 'jetpack_social_image_generator_settings' );
91        // If the option is not set, we don't need to migrate.
92        if ( false === $sig_settings ) {
93            return;
94        }
95
96        $enabled  = false;
97        $template = Templates::DEFAULT_TEMPLATE;
98
99        if ( isset( $sig_settings['defaults']['template'] ) ) {
100            $template = $sig_settings['defaults']['template'];
101        }
102
103        if ( isset( $sig_settings['enabled'] ) ) {
104            $enabled = $sig_settings['enabled'];
105        }
106
107        if ( ! isset( $sig_settings['template'] ) ) {
108            update_option(
109                self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS,
110                array(
111                    'enabled'  => $enabled,
112                    'template' => $template,
113                )
114            );
115        }
116    }
117
118    /**
119     * Register the settings.
120     *
121     * @return void
122     */
123    public function register_settings() {
124
125        register_setting(
126            'jetpack_social',
127            self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS,
128            array(
129                'type'         => 'object',
130                'default'      => array(
131                    'enabled'  => false,
132                    'template' => Templates::DEFAULT_TEMPLATE,
133                ),
134                'show_in_rest' => array(
135                    'schema' => array(
136                        'type'       => 'object',
137                        'properties' => array(
138                            'enabled'          => array(
139                                'type' => 'boolean',
140                            ),
141                            'template'         => array(
142                                'type' => 'string',
143                            ),
144                            'font'             => array(
145                                'type' => 'string',
146                            ),
147                            'default_image_id' => array(
148                                'type' => 'number',
149                            ),
150                        ),
151                    ),
152                ),
153            )
154        );
155
156        register_setting(
157            'jetpack_social',
158            self::OPTION_PREFIX . self::UTM_SETTINGS,
159            array(
160                'type'         => 'boolean',
161                'default'      => array(
162                    'enabled' => false,
163                ),
164                'show_in_rest' => array(
165                    'schema' => array(
166                        'type'       => 'object',
167                        'properties' => array(
168                            'enabled' => array(
169                                'type' => 'boolean',
170                            ),
171                        ),
172                    ),
173                ),
174            )
175        );
176
177        register_setting(
178            'jetpack_social',
179            self::JETPACK_SOCIAL_SHOW_PRICING_PAGE,
180            array(
181                'type'         => 'boolean',
182                'default'      => true,
183                'show_in_rest' => array(
184                    'schema' => array(
185                        'type' => 'boolean',
186                    ),
187                ),
188            )
189        );
190
191        register_setting(
192            'jetpack_social',
193            self::JETPACK_SOCIAL_NOTE_CPT_ENABLED,
194            array(
195                'type'         => 'boolean',
196                'default'      => false,
197                'show_in_rest' => array(
198                    'schema' => array(
199                        'type' => 'boolean',
200                    ),
201                ),
202            )
203        );
204
205        register_setting(
206            'jetpack_social',
207            self::OPTION_PREFIX . self::NOTES_CONFIG,
208            array(
209                'type'         => 'object',
210                'default'      => self::DEFAULT_NOTES_CONFIG,
211                'show_in_rest' => array(
212                    'schema' => array(
213                        'type'       => 'object',
214                        'context'    => array( 'view', 'edit' ),
215                        'properties' => array(
216                            'append_link' => array(
217                                'type' => 'boolean',
218                            ),
219                            'link_format' => array(
220                                'type' => 'string',
221                                'enum' => array( 'full_url', 'shortlink', 'permashortcitation' ),
222                            ),
223                        ),
224                    ),
225                ),
226            )
227        );
228
229        add_filter( 'rest_pre_update_setting', array( $this, 'update_settings' ), 10, 3 );
230    }
231
232    /**
233     * Get the image generator settings.
234     *
235     * @return array
236     */
237    public function get_image_generator_settings() {
238        return get_option( self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS, self::DEFAULT_IMAGE_GENERATOR_SETTINGS );
239    }
240
241    /**
242     * Get if the UTM params is enabled.
243     *
244     * @return array
245     */
246    public function get_utm_settings() {
247        return get_option( self::OPTION_PREFIX . self::UTM_SETTINGS, self::DEFAULT_UTM_SETTINGS );
248    }
249
250    /**
251     * Get the social notes config.
252     *
253     * @return array The social notes config.
254     */
255    public function get_social_notes_config() {
256        return get_option( self::OPTION_PREFIX . self::NOTES_CONFIG, self::DEFAULT_NOTES_CONFIG );
257    }
258
259    /**
260     * Check if the pricing page should be displayed.
261     *
262     * @return bool
263     */
264    public static function should_show_pricing_page() {
265        return (bool) get_option( self::JETPACK_SOCIAL_SHOW_PRICING_PAGE, true );
266    }
267
268    /**
269     * Get if the social notes feature is enabled.
270     *
271     * @return bool
272     */
273    public function is_social_notes_enabled() {
274        return (bool) get_option( self::JETPACK_SOCIAL_NOTE_CPT_ENABLED, false );
275    }
276
277    /**
278     * Get the current settings.
279     *
280     * @param bool $with_available Whether to include the available status of the features.
281     *
282     * @return array
283     */
284    public function get_settings( $with_available = false ) {
285        $this->migrate_old_option();
286
287        $settings = array(
288            'socialImageGeneratorSettings' => $this->get_image_generator_settings(),
289        );
290
291        // The feature cannot be enabled without Publicize.
292        if ( ! ( new Modules() )->is_active( 'publicize' ) ) {
293            $settings['socialImageGeneratorSettings']['enabled'] = false;
294        }
295
296        if ( $with_available ) {
297            $settings['socialImageGeneratorSettings']['available'] = $this->is_sig_available();
298        }
299
300        return $settings;
301    }
302
303    /**
304     * Get the initial state.
305     * Deprecated method, stub left here to avoid fatal.
306     *
307     * @deprecated 0.62.0
308     */
309    public function get_initial_state() {
310        return array();
311    }
312
313    /**
314     * Update the settings.
315     *
316     * @param bool   $updated The updated settings.
317     * @param string $name    The name of the setting.
318     * @param mixed  $value   The value of the setting.
319     *
320     * @return bool
321     */
322    public function update_settings( $updated, $name, $value ) {
323
324        // Social Image Generator.
325        if ( self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS === $name ) {
326            return $this->update_social_image_generator_settings( $value );
327        }
328
329        // UTM Settings.
330        if ( self::OPTION_PREFIX . self::UTM_SETTINGS === $name ) {
331            $current_utm_settings = $this->get_utm_settings();
332
333            if ( empty( $current_utm_settings ) || ! is_array( $current_utm_settings ) ) {
334                $current_utm_settings = self::DEFAULT_UTM_SETTINGS;
335            }
336
337            return update_option( self::OPTION_PREFIX . self::UTM_SETTINGS, array_replace_recursive( $current_utm_settings, $value ) );
338        }
339
340        // Social Notes.
341        if ( self::JETPACK_SOCIAL_NOTE_CPT_ENABLED === $name ) {
342            // Delete this option, so the rules get flushed in maybe_flush_rewrite_rules when the CPT is registered.
343            delete_option( self::NOTES_FLUSH_REWRITE_RULES_FLUSHED );
344            return update_option( self::JETPACK_SOCIAL_NOTE_CPT_ENABLED, (bool) $value );
345        }
346        if ( self::OPTION_PREFIX . self::NOTES_CONFIG === $name ) {
347            $old_config = $this->get_social_notes_config();
348            $new_config = array_merge( $old_config, $value );
349            return update_option( self::OPTION_PREFIX . self::NOTES_CONFIG, $new_config );
350        }
351
352        if ( self::JETPACK_SOCIAL_SHOW_PRICING_PAGE === $name ) {
353            return update_option( self::JETPACK_SOCIAL_SHOW_PRICING_PAGE, (int) $value );
354        }
355
356        return $updated;
357    }
358
359    /**
360     * Update the social image generator settings.
361     *
362     * @param array $new_setting The new settings.
363     *
364     * @return bool
365     */
366    public function update_social_image_generator_settings( $new_setting ) {
367        $this->migrate_old_option();
368        $sig_settings = get_option( self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS );
369
370        if ( empty( $sig_settings ) || ! is_array( $sig_settings ) ) {
371            $sig_settings = self::DEFAULT_IMAGE_GENERATOR_SETTINGS;
372        }
373
374        return update_option( self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS, array_replace_recursive( $sig_settings, $new_setting ) );
375    }
376
377    /**
378     * Check if SIG is available.
379     *
380     * @return bool True if SIG is available, false otherwise.
381     */
382    public function is_sig_available() {
383        global $publicize;
384
385        if ( ! $publicize ) {
386            return false;
387        }
388
389        return $publicize->has_social_image_generator_feature();
390    }
391
392    /**
393     * Get the default template.
394     *
395     * @return string
396     */
397    public function sig_get_default_template() {
398        $this->migrate_old_option();
399        $sig_settings = get_option( self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS );
400        if ( empty( $sig_settings ) || ! is_array( $sig_settings ) ) {
401            $sig_settings = self::DEFAULT_IMAGE_GENERATOR_SETTINGS;
402        }
403        return $sig_settings['template'];
404    }
405
406    /**
407     * Get the default image ID.
408     *
409     * @return int
410     */
411    public function sig_get_default_image_id() {
412        $this->migrate_old_option();
413        $sig_settings = get_option( self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS );
414        if ( empty( $sig_settings ) || ! is_array( $sig_settings ) ) {
415            return 0;
416        }
417
418        if ( isset( $sig_settings['default_image_id'] ) ) {
419            return $sig_settings['default_image_id'];
420        }
421
422        return 0;
423    }
424
425    /**
426     * Get the default font.
427     *
428     * @return string
429     */
430    public function sig_get_default_font() {
431        $this->migrate_old_option();
432        $sig_settings = get_option( self::OPTION_PREFIX . self::IMAGE_GENERATOR_SETTINGS );
433        if ( empty( $sig_settings ) || ! is_array( $sig_settings ) ) {
434            return '';
435        }
436
437        return $sig_settings['font'] ?? '';
438    }
439}