Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 101
0.00% covered (danger)
0.00%
0 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
RestApiFilter
0.00% covered (danger)
0.00%
0 / 101
0.00% covered (danger)
0.00%
0 / 14
1980
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 add_appropriate_filters_for_onboarding
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 get_method_filters
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 wp_onboarding_site_logo_filter
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
72
 wp_onboarding_add_site_logo_styles
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
 wp_onboarding_calculate_site_logo_width
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
56
 wp_onboarding_nav_menu_filter
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 prepare_raw_html_menu
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 header_menu_limit_pages
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 header_menu_rename_pages
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 is_request_from_onboarding_flow
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 modify_get_pages_response
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
12
 rename_page
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 register_wc_settings_options
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace NewfoldLabs\WP\Module\Onboarding\RestApi;
4
5use NewfoldLabs\WP\Module\Onboarding\Data\Data;
6use NewfoldLabs\WP\Module\Onboarding\Data\Options;
7use NewfoldLabs\WP\Module\Onboarding\Data\Patterns;
8use NewfoldLabs\WP\Module\Onboarding\WP_Admin;
9
10/**
11 * Instantiate controllers and register routes.
12 */
13class RestApiFilter {
14
15    /**
16     * Setup the custom REST API filters
17     */
18    public function __construct() {
19        \add_filter( 'rest_request_before_callbacks', array( __CLASS__, 'add_appropriate_filters_for_onboarding' ), 10, 3 );
20        if ( 'ecommerce' === Data::current_flow() ) {
21            \add_filter( 'rest_api_init', array( __CLASS__, 'register_wc_settings_options' ) );
22        }
23    }
24
25    /**
26     * Custom filter to check for pages API call, if true then add more filters for the onboarding flow only.
27     *
28     * @param array            $response - the API response
29     * @param array            $handler - handler
30     * @param \WP_REST_Request $request - WP_REST_Request object
31     *
32     * @return array
33     */
34    public static function add_appropriate_filters_for_onboarding( $response, array $handler, \WP_REST_Request $request ) {
35        if ( ! self::is_request_from_onboarding_flow( $request ) ) {
36            return $response;
37        }
38        $request_method = $request->get_method();
39        switch ( $request_method ) {
40            case 'GET':
41                self::get_method_filters( $request );
42                break;
43        }
44        return $response;
45    }
46
47    /**
48     * Apply the appropriate filters based on the route
49     *
50     * @param object $request REST API object
51     * @return void
52     */
53    private static function get_method_filters( $request ) {
54        $request_route = $request->get_route();
55        switch ( $request_route ) {
56            case '/wp/v2/pages':
57                \add_filter( 'rest_page_query', array( __CLASS__, 'header_menu_limit_pages' ) );
58                \add_filter( 'rest_request_after_callbacks', array( __CLASS__, 'header_menu_rename_pages' ), 10, 3 );
59                break;
60            case '/wp/v2/navigation':
61                \add_filter( 'rest_request_after_callbacks', array( __CLASS__, 'wp_onboarding_nav_menu_filter' ), 10, 2 );
62                break;
63            case '/newfold-onboarding/v1/patterns':
64                \add_filter( 'rest_request_after_callbacks', array( __CLASS__, 'wp_onboarding_site_logo_filter' ), 10, 2 );
65                break;
66        }
67    }
68
69    /**
70     * Function for modifying the grammar to contain a dynamic sized logo.
71     *
72     * @param object $response - WP_REST_Response object
73     * @param array  $args - An array containing arguments.
74     *
75     * @return object
76     */
77    public static function wp_onboarding_site_logo_filter( $response, $args ) {
78        $response_data = $response->get_data();
79
80        $site_logo_id = \get_option( Options::get_option_name( 'site_icon', false ) );
81        if ( '0' !== $site_logo_id ) {
82            if ( is_string( $response_data ) ) {
83                $response_data = self::wp_onboarding_add_site_logo_styles( $response_data, $site_logo_id );
84            }
85
86            if ( is_array( $response_data ) ) {
87                foreach ( $response_data as &$value ) {
88                    if ( isset( $value['slug'] ) && isset( $value['content'] ) ) {
89                        if ( false !== strpos( $value['slug'], 'header' ) ) {
90                            $value['content'] = self::wp_onboarding_add_site_logo_styles( $value['content'], $site_logo_id );
91                        }
92                    }
93                }
94            }
95        }
96
97        $response->set_data( $response_data );
98        return $response;
99    }
100
101    /**
102     * Function for adding a custom width style to the Site Logo.
103     *
104     * @param string $content - WP Grammar with site Logo
105     * @param string $site_logo_id - Site Logo ID to be resized
106     *
107     * @return string
108     */
109    public static function wp_onboarding_add_site_logo_styles( $content, $site_logo_id ) {
110        $calculated_width = self::wp_onboarding_calculate_site_logo_width( $site_logo_id );
111        if ( $calculated_width ) {
112            // Final Width Style to be applied.
113            $custom_width_style = '{"width":' . $calculated_width . '}';
114            // Check if there is a site-logo at all.
115            preg_match( '/<!-- wp:site-logo.*?\/-->/m', $content, $matches );
116
117            if ( isset( $matches ) && count( $matches ) >= 1 ) {
118                $site_logo_grammar = $matches[0];
119                // Check if the site-logo has a predefined width.
120                preg_match( '/{"width":.*?}/m', $site_logo_grammar, $width_style );
121                if ( isset( $width_style ) && count( $width_style ) >= 1 ) {
122                    // If width is present we need to just replace that not modifying other properties.
123                    $site_logo_grammar = preg_replace( '/{"width":.*?}/m', $custom_width_style, $site_logo_grammar );
124                    $content           = preg_replace( '/<!-- wp:site-logo .*? \/-->/m', $site_logo_grammar, $content );
125                } else {
126                    // If width is not present we need add it not modifying other properties.
127                    $content = preg_replace( '/<!-- wp:site-logo/m', '<!-- wp:site-logo ' . $custom_width_style, $content );
128                }
129            }
130        }
131
132        return $content;
133    }
134
135    /**
136     * Calculate the new site Logo size
137     *
138     * @param string $site_logo_id - Site Logo ID to be resized
139     *
140     * @return integer|boolean
141     */
142    private static function wp_onboarding_calculate_site_logo_width( $site_logo_id ) {
143        $site_logo_metadata = wp_get_attachment_metadata( $site_logo_id );
144        if ( isset( $site_logo_metadata ) && isset( $site_logo_metadata['height'] ) && isset( $site_logo_metadata['width'] ) ) {
145            $site_logo_img_ratio = $site_logo_metadata['height'] / $site_logo_metadata['width'];
146            switch ( $site_logo_img_ratio ) {
147                // Landscape
148                case ( $site_logo_img_ratio < 0.7 ):
149                    return 180;
150                // Portrait
151                case ( $site_logo_img_ratio > 1.3 ):
152                    return 130;
153                // Squarish
154                default:
155                    return 150;
156            }
157        }
158        return false;
159    }
160
161    /**
162     * Function for modifying the navigation menu grammar.
163     *
164     * @param object $response - WP_REST_Response object
165     * @param array  $args - An array containing arguments.
166     *
167     * @return object
168     */
169    public static function wp_onboarding_nav_menu_filter( $response, $args ) {
170        $modified_data = array_map(
171            array( __CLASS__, 'prepare_raw_html_menu' ),
172            $response->get_data(),
173            array_keys( $response->get_data() )
174        );
175        $response->set_data( $modified_data );
176        return $response;
177    }
178
179    /**
180     * Modify the response to make sure it has the dummy pages.
181     *
182     * @param array   $data - array containing navigation menu data
183     * @param integer $index - array index from the pages list
184     *
185     * @return array
186     */
187    public static function prepare_raw_html_menu( $data, $index ) {
188        // create dummy menu links
189        $menu_navigation_grammar = '';
190        foreach ( Patterns::get_dummy_navigation_menu_items() as $page_title ) {
191            $menu_navigation_grammar .= '<!-- wp:navigation-link {"isTopLevelLink":true, "label":"' . $page_title . '", "title":"' . $page_title . '"} /-->';
192        }
193        // need to reset ID else the data saved in the DB gets used
194        $data['id']                  = $index;
195        $data['content']['rendered'] = $menu_navigation_grammar;
196        return $data;
197    }
198
199    /**
200     * Custom filter to check for pages API call, if true then add more filters for the onboarding flow only.
201     *
202     * @param array $args - the arguments used by the WP_QUERY
203     *
204     * @return array
205     */
206    public static function header_menu_limit_pages( $args ) {
207        $args['posts_per_page'] = 6;
208        $args['orderby']        = 'id';
209        $args['no_found_rows']  = true;
210        return $args;
211    }
212
213    /**
214     * Custom filter to rename the info for the pages API call.
215     *
216     * @param array            $response - the api response
217     * @param array            $handler - handler
218     * @param \WP_REST_Request $request - WP_REST_Request object
219     *
220     * @return array
221     */
222    public static function header_menu_rename_pages( $response, array $handler, \WP_REST_Request $request ) {
223        self::modify_get_pages_response( $response );
224        return $response;
225    }
226
227    /**
228     * Check if the API call is being made from the onboarding flow.
229     *
230     * @param \WP_REST_Request $request - WP_REST_Request object
231     *
232     * @return boolean
233     */
234    public static function is_request_from_onboarding_flow( \WP_REST_Request $request ) {
235        $referrer = $request->get_header( 'referer' );
236        if ( ! $referrer ) {
237            return false;
238        }
239        return false !== stripos( $referrer, 'page=' . WP_Admin::$slug );
240    }
241
242    /**
243     * Modify the response to make sure it has the dummy pages.
244     *
245     * @param array $response - response array
246     *
247     * @return null
248     */
249    public static function modify_get_pages_response( $response ) {
250        if ( ! ( $response instanceof \WP_REST_Response ) ) {
251            return;
252        }
253
254        // make sure we have the number of dummy pages required
255        $pages       = $response->get_data();
256        $dummy_items = Patterns::get_dummy_navigation_menu_items();
257        if ( count( $pages ) < count( $dummy_items ) ) {
258            $pages = array_pad(
259                $pages,
260                count( $dummy_items ),
261                array_pop( $pages )
262            );
263        }
264
265        $data = array_map(
266            array( __CLASS__, 'rename_page' ),
267            $pages,
268            array_keys( $pages )
269        );
270        $response->set_data( $data );
271    }
272
273    /**
274     * Modify the response to make sure it has the dummy pages.
275     *
276     * @param array   $page - array containing page attributes
277     * @param integer $index - array index from the pages list
278     *
279     * @return array
280     */
281    public static function rename_page( array $page, $index ) {
282        if ( isset( $page['title']['rendered'] ) ) {
283            // changed id so that while rendering the menu link and name are proper
284            $page['id']                = $page['id'] + $index;
285            $page['title']['rendered'] = Patterns::get_dummy_navigation_menu_items()[ $index ];
286            $page['menu_order']        = $index;
287        }
288
289        return $page;
290    }
291
292    /**
293     * Registers Woocommerce settings options with the wp/v2/settings API.
294     *
295     * @return void
296     */
297    public static function register_wc_settings_options() {
298        $wc_settings_options = Options::get_wc_settings_options();
299        foreach ( $wc_settings_options as $wc_settings_option => $value ) {
300            register_setting( 'general', Options::get_option_name( $wc_settings_option, false ), $value );
301        }
302    }
303} // END /NewfoldLabs/WP/Module/Onboarding/RestApiFilter()