Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 133
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
CTA
0.00% covered (danger)
0.00%
0 / 133
0.00% covered (danger)
0.00%
0 / 9
756
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 maybe_init_options
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 get_option_name_for_screen
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 handle_ajax_toggle
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 add_screen_option_html
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
6
 add_toggle_script
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 add_cta_to_add_new_button
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
12
 add_style
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
2
 is_core_post_type
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2namespace NewfoldLabs\WP\Module\Patterns\Admin;
3
4/**
5 * CTA for the edit pages screen.
6 */
7class CTA {
8
9    /**
10     * WordPress option name for posts
11     */
12    const POST_OPTION_NAME = 'nfd_wb_cta_enabled_posts';
13
14    /**
15     * WordPress option name for pages
16     */
17    const PAGE_OPTION_NAME = 'nfd_wb_cta_enabled_pages';
18
19    /**
20     * Nonce action name
21     */
22    const NONCE_ACTION = 'nfd_wonderblocks_toggle';
23
24    /**
25     * Constructor.
26     */
27    public function __construct() {
28
29        $this->maybe_init_options();
30
31        \add_action( 'wp_ajax_toggle_wonderblocks_cta', array( $this, 'handle_ajax_toggle' ) );
32
33        if ( ! $this->is_core_post_type() ) {
34            return;
35        }
36
37        \add_action( 'admin_head', array( $this, 'add_style' ) );
38        \add_action( 'admin_footer', array( $this, 'add_cta_to_add_new_button' ), 10 );
39        \add_action( 'admin_footer', array( $this, 'add_toggle_script' ), 20 );
40        \add_filter( 'screen_settings', array( $this, 'add_screen_option_html' ), 10, 2 );
41    }
42
43    /**
44     * Initialize options if they don't exist
45     */
46    private function maybe_init_options() {
47        if ( false === get_option( self::POST_OPTION_NAME ) ) {
48            add_option( self::POST_OPTION_NAME, true );
49        }
50        if ( false === get_option( self::PAGE_OPTION_NAME ) ) {
51            add_option( self::PAGE_OPTION_NAME, true );
52        }
53    }
54
55    /**
56     * Get the appropriate option name based on screen
57     *
58     * @param string $screen_id The screen ID
59     */
60    private function get_option_name_for_screen( $screen_id ) {
61        return 'edit-page' === $screen_id ? self::PAGE_OPTION_NAME : self::POST_OPTION_NAME;
62    }
63
64    /**
65     * Handle the AJAX toggle
66     */
67    public function handle_ajax_toggle() {
68        if ( ! \is_user_logged_in() ) {
69            \wp_die( '', '', 403 );
70        }
71
72        \check_ajax_referer( self::NONCE_ACTION, 'nonce' );
73
74        if ( ! \current_user_can( 'manage_options' ) ) {
75            \wp_die( '', '', 403 );
76        }
77
78        $screen_id   = isset( $_POST['screen_id'] ) ? \sanitize_text_field( $_POST['screen_id'] ) : 'edit-post';
79        $enabled     = (bool) ( 'true' === $_POST['nfd_wba_cta_button'] );
80        $option_name = $this->get_option_name_for_screen( $screen_id );
81
82        $updated = \update_option( $option_name, $enabled );
83
84        if ( $updated ) {
85            \wp_send_json_success(
86                array(
87                    'enabled'     => $enabled,
88                    'option_name' => $option_name,
89                    'screen_id'   => $screen_id,
90                )
91            );
92        } else {
93            \wp_send_json_error( 'Failed to update option' );
94        }
95    }
96
97    /**
98     * Add the screen option HTML
99     *
100     * @param string $settings The current screen settings
101     * @param object $screen The current screen object
102     */
103    public function add_screen_option_html( $settings, $screen ) {
104        if ( ! \in_array( $screen->id, array( 'edit-page', 'edit-post' ), true ) ) {
105            return $settings;
106        }
107
108        $option_name = $this->get_option_name_for_screen( $screen->id );
109        $enabled     = \get_option( $option_name, true );
110
111        $html  = '<fieldset class="metabox-prefs wonderblocks">';
112        $html .= '<legend>' . esc_html__( 'WonderBlocks', 'nfd-wonder-blocks' ) . '</legend>';
113        $html .= '<label>';
114        $html .= '<input type="checkbox" id="wonderblocks-toggle"' . checked( $enabled, true, false ) . ' /> ';
115        $html .= esc_html__( 'Show WonderBlocks Button', 'nfd-wonder-blocks' );
116        $html .= '</label>';
117        $html .= '</fieldset>';
118        $html .= \wp_nonce_field( self::NONCE_ACTION, 'wonderblocks_nonce', true, false );
119
120        $allowed_html = array(
121            'fieldset' => array(
122                'class' => true,
123            ),
124            'legend'   => array(),
125            'label'    => array(),
126            'input'    => array(
127                'type'    => true,
128                'id'      => true,
129                'checked' => true,
130                'name'    => true,
131                'value'   => true,
132            ),
133        );
134
135        return \wp_kses( $settings . $html, $allowed_html );
136    }
137
138    /**
139     * Add toggle script to footer
140     */
141    public function add_toggle_script() {
142        $screen = \get_current_screen();
143        ?>
144        <script>
145            document.addEventListener("DOMContentLoaded", function () {
146                const toggle = document.getElementById("wonderblocks-toggle");
147                const nonceField = document.getElementById("wonderblocks_nonce");
148                const ajaxUrl = "<?php echo esc_js( admin_url( 'admin-ajax.php' ) ); ?>";
149                const screenId = "<?php echo esc_js( $screen->id ); ?>";
150                const ctaButton = document.querySelector('.nfd-wba-cta-edit-screen');
151
152                if (!toggle || !nonceField || !ctaButton) return;
153
154                toggle.addEventListener("change", function () {
155                    const enabled = this.checked ? "true" : "false";
156                    const data = new FormData();
157                    data.append("action", "toggle_wonderblocks_cta");
158                    data.append("nonce", nonceField.value);
159                    data.append("nfd_wba_cta_button", enabled);
160                    data.append("screen_id", screenId);
161
162                    fetch(
163                        ajaxUrl,
164                        {
165                            method: "POST",
166                            body: data,
167                        }
168                    )
169                    .then((response) => response.json())
170                    .then((response) => {
171                        if (response.success) {
172                            ctaButton.style.display = enabled === "true" ? "inline-flex" : "none";
173                        } else {
174                            toggle.checked = !toggle.checked;
175                            console.error("Failed to update WonderBlocks setting:", response);
176                        }
177                    })
178                    .catch((error) => {
179                        toggle.checked = !toggle.checked;
180                        console.error("AJAX request failed:", error);
181                    });
182                });
183            });
184        </script>
185        <?php
186    }
187
188    /**
189     * Add CTA to Add New button
190     */
191    public function add_cta_to_add_new_button() {
192        $screen      = \get_current_screen();
193        $option_name = $this->get_option_name_for_screen( $screen->id );
194        $enabled     = \get_option( $option_name, true );
195
196        // Set the URL based on screen type
197        if ( 'edit-post' === $screen->id ) {
198            $url = \admin_url( 'post-new.php?wb-library=patterns&wb-category=text' );
199        } elseif ( 'edit-page' === $screen->id ) {
200            $url = \admin_url( 'post-new.php?post_type=page&wb-library=patterns&wb-category=features' );
201        } else {
202            // Default fallback URL
203            $url = \admin_url( 'post-new.php?wb-library=patterns' );
204        }
205
206        $svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="2.25 6 19.5 13.5" width="19px" height="19px"><path stroke-linecap="round" stroke-linejoin="round" d="M3.34 7.754c0-.552.447-.999.999-.999h5.328a1 1 0 0 1 .999.999v3.329a1 1 0 0 1-.999.999H4.339a.999.999 0 0 1-.999-.999V7.754Zm10.655 1.331a1 1 0 0 1 .999-.998h4.662c.552 0 .999.447.999.998v7.326a.999.999 0 0 1-.999.999h-4.662a1 1 0 0 1-.999-.999V9.085Zm-9.323 6.66a1 1 0 0 1 .998-.999h4.662a1 1 0 0 1 .999.999v1.998a1 1 0 0 1-.999.999H5.67a1 1 0 0 1-.998-.999v-1.998Z" style="fill:none;stroke-width:1.5px;paint-order:stroke;stroke:currentColor"/></svg>';
207
208        $cta_text = sprintf(
209            /* translators: %1$s: opening anchor tag, %2$s: closing anchor tag */
210            _x(
211                '%1$sAdd With WonderBlocks%2$s',
212                'Button label',
213                'nfd-wonder-blocks'
214            ),
215            '<a class="page-title-action" href="' . \esc_url( $url ) . '">' . $svg . '<span class="text">',
216            '</span></a>'
217        );
218
219        ?>
220        <script>
221            document.addEventListener('DOMContentLoaded', function() {
222                const pageTitleAction = document.querySelector('.wrap .page-title-action');
223                if (pageTitleAction) {
224                    const newElement = document.createElement('div');
225                    newElement.innerHTML = <?php echo \wp_json_encode( $cta_text ); ?>;
226                    newElement.classList.add('nfd-wba-cta-edit-screen');
227                    if (!<?php echo json_encode( $enabled ); ?>) {
228                        newElement.style.display = 'none';
229                    }
230                    pageTitleAction.insertAdjacentElement('afterend', newElement);
231                }
232            });
233        </script>
234        <?php
235    }
236
237    /**
238     * Add styles for the CTA
239     */
240    public function add_style() {
241        ?>
242        <style>
243            .nfd-wba-cta-edit-screen {
244                display: inline-flex;
245            }
246            .nfd-wba-cta-edit-screen .page-title-action {
247                align-items: center;
248                border-color: #3d7e29;
249                background-color: #3d7e29;
250                color: #ffffff;
251            }
252            .nfd-wba-cta-edit-screen .page-title-action:hover,
253            .nfd-wba-cta-edit-screen .page-title-action:active {
254                border-color: #3F8F3C;
255                background-color: #3F8F3C;
256                color: #ffffff;
257            }
258            .nfd-wba-cta-edit-screen .page-title-action:focus {
259                border-color: #2f621f;
260                background-color: #2f621f;
261                box-shadow: 0 0 0 1px #2f621f;
262            }
263
264            .nfd-wba-cta-edit-screen svg {
265                margin-right: 5px;
266                position: relative;
267                top: 4px;
268            }
269            @media only screen and (max-width: 433px) {
270                .nfd-wba-cta-edit-screen {
271                    margin-top: 6px;
272                }
273            }
274        </style>
275        <?php
276    }
277
278    /**
279     * Check if we're on the edit pages screen
280     */
281    private function is_core_post_type() {
282        if ( ! \is_admin() || ! \is_user_logged_in() ) {
283            return false;
284        }
285
286        global $pagenow, $typenow;
287
288        $is_core_post_type = ( 'edit.php' === $pagenow && (
289            // Default post type (no post_type parameter)
290            ( ! isset( $_GET['post_type'] ) && empty( $typenow ) ) ||
291            // Explicit post type check
292            ( isset( $_GET['post_type'] ) && in_array( $_GET['post_type'], array( 'post', 'page' ), true ) ) ||
293            // Fallback to typenow
294            in_array( $typenow, array( 'post', 'page' ), true )
295        ) );
296
297        return $is_core_post_type;
298    }
299}