Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 99
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Items
0.00% covered (danger)
0.00%
0 / 99
0.00% covered (danger)
0.00%
0 / 7
1892
0.00% covered (danger)
0.00%
0 / 1
 get
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
72
 sort
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 filter
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 filter_by_category
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 filter_by_keywords
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
182
 add_featured_categories
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
 add_plugin_requirements
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace NewfoldLabs\WP\Module\Patterns\Library;
4
5use NewfoldLabs\WP\Module\Patterns\SiteClassification;
6use NewfoldLabs\WP\Module\Data\WonderBlocks\Requests\Fetch as WonderBlocksFetchRequest;
7use NewfoldLabs\WP\Module\Data\WonderBlocks\WonderBlocks;
8use NewfoldLabs\WP\Module\Patterns\Data\PluginRequirements;
9use NewfoldLabs\WP\Module\Patterns\Data\PluginStatus;
10
11/**
12 * Library for items.
13 */
14class Items {
15
16    /**
17     * Get items.
18     *
19     * @param string $type Type of items to get.
20     * @param array  $args Array of arguments.
21     *
22     * @return array|WP_Error $data Array of items or WP_Error.
23     */
24    public static function get( $type = 'patterns', $args = array() ) {
25
26        $request = new WonderBlocksFetchRequest(
27            array(
28                'endpoint'       => $type,
29                'primary_type'   => SiteClassification::get_primary_type(),
30                'secondary_type' => SiteClassification::get_secondary_type(),
31            )
32        );
33
34        $data = WonderBlocks::fetch( $request );
35        if ( ! $data ) {
36            return new \WP_Error(
37                'nfd_wonder_blocks_error',
38                __( 'Error fetching data from the platform.', 'nfd-wonder-blocks' )
39            );
40        }
41
42        $data = self::add_featured_categories( $data, $type );
43        $data = self::add_plugin_requirements( $data, $type );
44
45        if ( isset( $args['category'] ) ) {
46            $data = self::filter( $data, 'category', \sanitize_text_field( $args['category'] ) );
47        }
48
49        if ( isset( $args['keywords'] ) ) {
50            $match_type = isset( $args['match_type'] ) ? \sanitize_text_field( $args['match_type'] ) : 'contains';
51            $data       = self::filter( $data, 'keywords', \sanitize_text_field( $args['keywords'] ), $match_type );
52        }
53
54        if ( isset( $args['sort_by'] ) ) {
55            $data = self::sort( $data, \sanitize_text_field( $args['sort_by'] ) );
56        }
57
58        if ( isset( $args['per_page'] ) ) {
59            $page = isset( $args['page'] ) ? $args['page'] : 1;
60            $data = array_slice( $data, ( $page - 1 ) * $args['per_page'], $args['per_page'] );
61        }
62
63        return $data;
64    }
65
66    /**
67     * Sorts a multidimensional array.
68     *
69     * @param array  $data The array to sort.
70     * @param string $sort_by The key to sort by.
71     *
72     * @return array The sorted array.
73     */
74    private static function sort( $data, $sort_by ) {
75
76        if ( 'newest' === $sort_by ) {
77            $data = array_reverse( $data );
78        }
79
80        return $data;
81    }
82
83    /**
84     * Filter data by key and value.
85     *
86     * @param array  $data       Array of data.
87     * @param string $key        Key to filter by.
88     * @param string $value      Value to filter by.
89     * @param string $match_type Type of matching: 'exact' or 'contains'.
90     *
91     * @return array $filtered
92     */
93    private static function filter( $data, $key, $value, $match_type = 'contains' ) {
94
95        if ( ! is_array( $data ) ) {
96            return array();
97        }
98
99        if ( empty( $data ) ) {
100            return array();
101        }
102
103        if ( 'category' === $key ) {
104            return self::filter_by_category( $data, $value );
105        }
106
107        if ( 'keywords' === $key ) {
108            return self::filter_by_keywords( $data, $value, $match_type );
109        }
110    }
111
112    /**
113     * Filter an array by category.
114     *
115     * @param array  $data  Array of data.
116     * @param string $value Value to filter by.
117     *
118     * @return array $filtered
119     */
120    private static function filter_by_category( $data, $value ) {
121
122        $filtered = array();
123
124        foreach ( $data as $item ) {
125
126            if ( isset( $item['categories'] ) ) {
127
128                $item['categories'] = (array) $item['categories'];
129
130                foreach ( $item['categories'] as $v ) {
131                    if ( strpos( $v, $value ) !== false ) {
132                        $filtered[] = $item;
133                    }
134                }
135            }
136        }
137
138        return $filtered;
139    }
140
141    /**
142     * Filter an array by keywords.
143     *
144     * @param array  $data       Array of data.
145     * @param string $value      Value to filter by.
146     * @param string $match_type Type of matching: 'exact' or 'contains'.
147     *
148     * @return array $filtered
149     */
150    private static function filter_by_keywords( $data, $value, $match_type = 'contains' ) {
151        $filtered = array();
152        $value    = strtolower( $value );
153
154        foreach ( $data as $item ) {
155            $title       = strtolower( $item['title'] );
156            $match_found = false;
157
158            // Check title based on match type.
159            if ( 'exact' === $match_type && $title === $value ) {
160                $match_found = true;
161            } elseif ( 'contains' === $match_type && false !== strpos( $title, $value ) ) {
162                $match_found = true;
163            }
164
165            if ( $match_found ) {
166                $filtered[] = $item;
167                continue;
168            }
169
170            // Check tags if available.
171            if ( isset( $item['tags'] ) ) {
172                $item['tags'] = (array) $item['tags'];
173
174                foreach ( $item['tags'] as $tag ) {
175                    $tag = strtolower( $tag );
176
177                    if ( 'exact' === $match_type && $tag === $value ) {
178                        $filtered[] = $item;
179                        break;
180                    } elseif ( 'contains' === $match_type && false !== strpos( $tag, $value ) ) {
181                        $filtered[] = $item;
182                        break;
183                    }
184                }
185            }
186        }
187
188        return $filtered;
189    }
190
191    /**
192     * Add featured category to item if it belongs to a featured category.
193     *
194     * @param array  $data List of items
195     * @param string $type Type of items
196     *
197     * @return object $data List of items updated with featured category
198     */
199    private static function add_featured_categories( $data, $type = 'patterns' ) {
200        $data = array_map(
201            function ( $item ) use ( $type ) {
202
203                if ( ! isset( $item['categories'] ) ) {
204                    $item['categories'] = array();
205                }
206
207                if ( ! is_array( $item['categories'] ) ) {
208                    $item['categories'] = array( $item['categories'] );
209                }
210
211                if ( isset( $item['is_featured'] ) && $item['is_featured'] ) {
212                    $item['categories'][] = 'featured';
213                }
214
215                return $item;
216            },
217            $data
218        );
219
220        return $data;
221    }
222
223    /**
224     * Add plugin requirements to item.
225     *
226     * @param array  $data List of items
227     * @param string $type Type of items
228     *
229     * @return object $data List of items updated with plugin requirements
230     */
231    private static function add_plugin_requirements( $data, $type = 'patterns' ) {
232        if ( 'patterns' !== $type ) {
233            return $data;
234        }
235
236        $plugin_requirements = PluginRequirements::get();
237
238        $data = array_map(
239            function ( $item ) use ( $plugin_requirements ) {
240
241                if ( ! isset( $item['slug'] ) ) {
242                    return $item;
243                }
244
245                $requirements = isset( $plugin_requirements[ $item['slug'] ] ) ? $plugin_requirements[ $item['slug'] ] : array();
246
247                // Check the status of the required plugins and add it to the item
248                foreach ( $requirements as &$requirement ) {
249                    $path                  = $requirement['path'] ?? $requirement['basename'] ?? '';
250                    $requirement['status'] = PluginStatus::check( $path );
251                }
252
253                $item['plugin_requirements'] = $requirements;
254
255                return $item;
256            },
257            $data
258        );
259
260        return $data;
261    }
262}