Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.62% covered (success)
83.62%
97 / 116
55.56% covered (danger)
55.56%
5 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
PreselectGenerateAudio
83.62% covered (success)
83.62%
97 / 116
55.56% covered (danger)
55.56%
5 / 9
32.70
0.00% covered (danger)
0.00%
0 / 1
 init
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addSetting
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 render
64.00% covered (warning)
64.00%
16 / 25
0.00% covered (danger)
0.00%
0 / 1
3.42
 renderTaxonomyFields
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
5
 renderTaxonomyTerms
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
1 / 1
3
 postTypeIsSelected
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
3.14
 taxonomyIsSelected
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 termIsSelected
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
7.90
 enqueueScripts
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Setting: PreselectGenerateAudio
7 *
8 * @package Beyondwords\Wordpress
9 * @author  Stuart McAlpine <stu@beyondwords.io>
10 * @since   3.0.0
11 */
12
13namespace Beyondwords\Wordpress\Component\Settings\Fields\PreselectGenerateAudio;
14
15use Beyondwords\Wordpress\Component\Settings\SettingsUtils;
16
17/**
18 * PreselectGenerateAudio
19 *
20 * @since 3.0.0
21 */
22class PreselectGenerateAudio
23{
24    /**
25     * Option name.
26     *
27     * @since 5.0.0
28     */
29    public const OPTION_NAME = 'beyondwords_preselect';
30
31    public const DEFAULT_PRESELECT = [
32        'post' => '1',
33        'page' => '1',
34    ];
35
36    /**
37     * Init.
38     *
39     * @since 4.0.0
40     * @since 6.0.0 Make static.
41     */
42    public static function init()
43    {
44        add_action('admin_init', [self::class, 'addSetting']);
45        add_action('admin_enqueue_scripts', [self::class, 'enqueueScripts']);
46    }
47
48    /**
49     * Init setting.
50     *
51     * @since 5.0.0
52     * @since 6.0.0 Make static.
53     *
54     * @return void
55     */
56    public static function addSetting()
57    {
58        register_setting(
59            'beyondwords_content_settings',
60            self::OPTION_NAME,
61            [
62                'default' => self::DEFAULT_PRESELECT,
63            ]
64        );
65
66        add_settings_field(
67            'beyondwords-preselect',
68            __('Preselect ‘Generate audio’', 'speechkit'),
69            [self::class, 'render'],
70            'beyondwords_content',
71            'content'
72        );
73    }
74
75    /**
76     * Render setting field.
77     *
78     * @since 3.0.0
79     * @since 6.0.0 Make static.
80     *
81     * @return void
82     **/
83    public static function render()
84    {
85        $postTypes = SettingsUtils::getCompatiblePostTypes();
86
87        if (count($postTypes) === 0) :
88            ?>
89            <p class="description">
90                <?php
91                esc_html_e(
92                    'No compatible post types found. This plugin will only work with post types that support custom fields.', // phpcs:ignore Generic.Files.LineLength.TooLong
93                    'speechkit'
94                );
95                ?>
96            </p>
97            <?php
98            return;
99        endif;
100
101        foreach ($postTypes as $name) :
102            $postType = get_post_type_object($name);
103            ?>
104            <div class="beyondwords-setting__preselect--post-type">
105                <label>
106                    <input
107                        type="checkbox"
108                        name="<?php echo esc_attr(self::OPTION_NAME); ?>[<?php echo esc_attr($postType->name); ?>]"
109                        value="1"
110                        <?php checked(self::postTypeIsSelected($postType)); ?>
111                    />
112                    <?php echo esc_html($postType->label); ?>
113                </label>
114                <?php self::renderTaxonomyFields($postType); ?>
115            </div>
116            <?php
117        endforeach;
118    }
119
120    /**
121     * Get the taxonomy fields, as a hierarchical list of nested checkboxes.
122     *
123     * @since 3.0.0
124     * @since 6.0.0 Make static.
125     *
126     * @return void
127     **/
128    public static function renderTaxonomyFields($postType)
129    {
130        $taxonomies = get_object_taxonomies($postType->name, 'objects');
131
132        if ($taxonomies) {
133            ?>
134            <div class="beyondwords-setting__preselect--taxonomy" style="margin: 0.5rem 0;">
135                <?php
136                foreach ($taxonomies as $taxonomy) {
137                    // Ignore the "Format" taxonomy (aside, etc)
138                    if ($taxonomy->name === 'post_format') {
139                        continue;
140                    }
141                    // todo enable for custom taxonomies, and add tests for them
142                    if ($taxonomy->name !== 'category') {
143                        continue;
144                    }
145                    ?>
146                    <h4 style="margin: 0.5rem 0 0.5rem 1.5rem;"><?php echo esc_html($taxonomy->label); ?></h4>
147                    <?php
148                    self::renderTaxonomyTerms($postType, $taxonomy);
149                }
150                ?>
151            </div>
152            <?php
153        }
154    }
155
156    /**
157     * Get the taxonomy terms, as a hierarchical list of nested checkboxes.
158     *
159     * @since 3.0.0
160     * @since 6.0.0 Make static.
161     *
162     * @return void
163     **/
164    public static function renderTaxonomyTerms($postType, $taxonomy, $parent = 0)
165    {
166        $terms = get_terms([
167            'taxonomy'   => $taxonomy->name,
168            'hide_empty' => false,
169            'parent'     => $parent,
170        ]);
171
172        if ($terms) {
173            ?>
174            <ul style="margin: 0; padding: 0; list-style:none;">
175                <?php
176                foreach ($terms as $term) :
177                    $inputName = sprintf(
178                        "%s[%s][%s][]",
179                        self::OPTION_NAME,
180                        $postType->name,
181                        $taxonomy->name
182                    );
183                    ?>
184                    <li class="beyondwords-setting__preselect--term" style="margin: 0.5rem 0 0 1.5rem;">
185                        <label>
186                            <input
187                                type="checkbox"
188                                name="<?php echo esc_attr($inputName); ?>"
189                                value="<?php echo esc_attr($term->term_id); ?>"
190                                <?php checked(self::termIsSelected($postType, $taxonomy, $term)) ?>
191                            />
192                            <?php echo esc_html($term->name); ?>
193                        </label>
194                        <?php self::renderTaxonomyTerms($postType, $taxonomy, $term->term_id); ?>
195                    </li>
196                    <?php
197                endforeach;
198                ?>
199                </ul>
200            <?php
201        }
202    }
203
204    /**
205     * Check whether a post type should be preselected.
206     *
207     * @since 6.0.0 Make static.
208     */
209    public static function postTypeIsSelected($postType)
210    {
211        $preselect = get_option(self::OPTION_NAME);
212
213        if (! is_array($preselect)) {
214            return false;
215        }
216
217        return array_key_exists($postType->name, $preselect) && $preselect[$postType->name] === '1';
218    }
219
220    /**
221     * Check whether a taxonomy should be preselected for a post type.
222     *
223     * @since 6.0.0 Make static.
224     */
225    public static function taxonomyIsSelected($postType, $taxonomy)
226    {
227        $preselect = get_option(self::OPTION_NAME);
228
229        if (! is_array($preselect)) {
230            return false;
231        }
232
233        if (! isset($preselect[$postType->name]) || ! is_array($preselect[$postType->name])) {
234            return false;
235        }
236
237        return in_array($taxonomy->name, $preselect[$postType->name]);
238    }
239
240    /**
241     * Check whether a term is selected for a post type and taxonomy.
242     *
243     * @since 6.0.0 Make static.
244     */
245    public static function termIsSelected($postType, $taxonomy, $term)
246    {
247        $preselect = get_option(self::OPTION_NAME);
248
249        if (! is_array($preselect)) {
250            return false;
251        }
252
253        if (! isset($preselect[$postType->name]) || ! is_array($preselect[$postType->name])) {
254            return false;
255        }
256
257        if (! isset($preselect[$postType->name][$taxonomy->name]) || ! is_array($preselect[$postType->name][$taxonomy->name])) { // phpcs:ignore Generic.Files.LineLength.TooLong
258            return false;
259        }
260
261        return in_array($term->term_id, $preselect[$postType->name][$taxonomy->name]);
262    }
263
264    /**
265     * Register the component scripts.
266     *
267     * @since 5.0.0
268     * @since 6.0.0 Make static.
269     *
270     * @param string $hook Page hook
271     *
272     * @return void
273     */
274    public static function enqueueScripts($hook)
275    {
276        if ($hook === 'post.php' || $hook === 'post-new.php') {
277            wp_register_script(
278                'beyondwords-settings--preselect-post',
279                BEYONDWORDS__PLUGIN_URI . 'src/Component/Settings/Fields/PreselectGenerateAudio/post.js',
280                ['jquery', 'underscore'],
281                BEYONDWORDS__PLUGIN_VERSION,
282                true
283            );
284
285            // Localize the script with new data
286            $data = [
287                'postType'  => get_post_type(),
288                'preselect' => get_option(self::OPTION_NAME),
289            ];
290
291            wp_localize_script('beyondwords-settings--preselect-post', 'beyondwords', $data);
292
293            wp_enqueue_script('beyondwords-settings--preselect-post');
294        }
295    }
296}