PluginProbe
PatternsWP – Gutenberg Block Patterns & Page Templates Library / 1.0.7
PatternsWP – Gutenberg Block Patterns & Page Templates Library v1.0.7
trunk 1.0.0 1.0.1 1.0.10 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9
patternswp / includes / class-patternswp-admin.php

class-patternswp-admin.php in PatternsWP – Gutenberg Block Patterns & Page Templates Library 1.0.7, at includes/class-patternswp-admin.php

346 lines 17.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin Page
4 */
5
6 class PatternsWP_Admin {
7
8 /**
9 * Constructor
10 */
11 public function __construct() {
12 // Add menu and pages
13 add_action('admin_menu', array($this, 'add_admin_menu'));
14 add_action('admin_init', array($this, 'patternswp_clear_cache'));
15 add_action( 'admin_init', array( $this, 'patternswp_ensure_hourly_cron' ) );
16 add_action( 'wp_ajax_patternswp_background_transient_load_ajax', array( $this, 'patternswp_background_transient_load_ajaxcc' ) );
17 add_action( 'wp_ajax_nopriv_patternswp_background_transient_load_ajax', array( $this, 'patternswp_background_transient_load_ajaxcc' ) );
18 add_action( 'patternswp_load_patterns_by_ra', array( $this, 'patternswp_load_patterns_by_remote_ajax' ) );
19 register_activation_hook(plugin_dir_path(__DIR__) . 'patternswp.php', array($this, 'patternswp_on_activation'));
20 add_action('admin_init', array($this, 'patternswp_redirect_on_activation'));
21 }
22
23 /**
24 * Add admin menu
25 */
26 public function add_admin_menu() {
27 // Custom SVG icon (base64 encoded)
28 $custom_icon = 'data:image/svg+xml;base64,' . base64_encode('
29 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
30 <path d="M9.34 24L4.45 21.16L4.03 20.92V15.3L9.34 12V24Z"/>
31 <path fill-rule="evenodd" clip-rule="evenodd" d="M14.66 9.2L20.97 6L14.66 2.8V9.2Z"/>
32 <path d="M14.66 2.8L9.34 6L4.03 9.2V2.8L9.34 0L14.66 2.8Z"/>
33 <path fill-rule="evenodd" clip-rule="evenodd" d="M10.79 11.44V17.84L14.66 15.3L20.97 12V6L14.66 9.2L10.79 11.44Z"/>
34 </svg>
35 ');
36
37 // Add top-level menu with custom SVG icon
38 $menu_slug = 'patternswp-plugin-menu';
39 add_menu_page(
40 'PatternsWP',
41 'PatternsWP',
42 'manage_options',
43 $menu_slug,
44 array($this, 'render_main_page'),
45 $custom_icon,
46 60
47 );
48
49 // Add subpages
50 $this->add_subpage($menu_slug, 'Dashboard', 'Dashboard', 'patternswp-plugin-menu', array($this, 'render_main_page'));
51 $this->add_subpage($menu_slug, 'Support', 'Support', 'patternswp-plugin-page-1', array($this, 'patternswp_support'));
52 $this->add_subpage($menu_slug, 'Clear Cache', 'Clear Cache', 'patternswp-clear-cache', array($this, 'patternswp_clear_cache_form'));
53 }
54
55 /**
56 * Add subpage
57 */
58 private function add_subpage($parent_slug, $page_title, $menu_title, $menu_slug, $callback) {
59 // Add subpage
60 add_submenu_page($parent_slug, $page_title, $menu_title, 'manage_options', $menu_slug, $callback);
61 }
62
63 /**
64 * Render tabs
65 */
66 public function patterswp_tab( $tab ) {
67 $tabs = array(
68 'Dashboard' => 'patternswp-plugin-menu',
69 'Support' => 'patternswp-plugin-page-1',
70 'Clear Cache' => 'patternswp-clear-cache',
71 'License' => 'patternswp-license_section'
72 );
73
74 foreach ($tabs as $name => $slug) {
75 $class = ( $tab === $name ) ? 'nav-tab-active' : '';
76 echo '<a href="?page=' . esc_attr($slug) . '" class="nav-tab ' . esc_attr($class) . '">' . esc_html($name) . '</a>';
77 }
78 }
79
80 /**
81 * Render main page
82 */
83 public function render_main_page() { ?>
84 <div class="wrap">
85 <h1><?php esc_html_e('PatternsWP', 'patternswp'); ?></h1>
86 <h2 class="nav-tab-wrapper">
87 <?php $this->patterswp_tab( 'Dashboard' ); ?>
88 </h2>
89 <div class="patterns-wp-tabs-content">
90 <div id="tab-1" class="patterns-wp-tab-content patterns-wp-tab-active">
91 <div class="wrap">
92 <div class="pw-feature-box big-box" style="max-width: 1280px; padding: 40px; background-color: white; border-radius: 10px; overflow: hidden;">
93 <div class="about__section has-1-columns">
94 <div class="column" style="text-align:center;">
95 <h4><?php echo esc_html('Hello, ' . wp_get_current_user()->display_name . ' 👋'); ?></h4>
96 <h1 class="feature-title"><?php esc_html_e('Welcome to PatternsWP', 'patternswp'); ?></h1>
97 <p><?php esc_html_e('Thanks for choosing PatternsWP! Follow these three simple steps to get started!', 'patternswp'); ?></p>
98 </div>
99 <div class="column" style="padding: 10px; text-align: center;">
100 <a href="<?php echo esc_url(admin_url('post-new.php?post_type=page')); ?>" class="button button-primary">
101 <?php esc_html_e('Start building with PatternsWP', 'patternswp'); ?>
102 </a>
103 </div>
104 </div>
105 <div class="about__section has-3-columns">
106 <div class="column" style="padding: 40px;">
107 <div class="about__image">
108 <?php
109 // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage
110 echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . 'pwp-welcome-01.png') . '" alt="" height="auto" width="100%">';
111 ?>
112 </div>
113 <h4><?php esc_html_e('01. Open the PatternsWP Library', 'patternswp'); ?></h4>
114 <p><?php esc_html_e('When editing a page or post in the block editor, locate the PatternsWP Library button in the editor’s header. Click it to access a collection of pre-designed patterns and full-page templates.', 'patternswp'); ?></p>
115 </div>
116 <div class="column" style="padding: 40px;">
117 <div class="about__image">
118 <?php
119 // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage
120 echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . 'pwp-welcome-02.png') . '" alt="" height="auto" width="100%">';
121 ?>
122 </div>
123 <h4><?php esc_html_e('02. Browse Patterns & Templates', 'patternswp'); ?></h4>
124 <p><?php esc_html_e('Explore a diverse range of block patterns and full-page layouts. Use the search box or filter by category to quickly find the perfect design for your website.', 'patternswp'); ?></p>
125 </div>
126 <div class="column" style="padding: 40px;">
127 <div class="about__image">
128 <?php
129 // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage
130 echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . 'pwp-welcome-03.png') . '" alt="" height="auto" width="100%">';
131 ?>
132 </div>
133 <h4><?php esc_html_e('03. Add Patterns & Customize', 'patternswp'); ?></h4>
134 <p><?php esc_html_e('Once you’ve found the right pattern, add it to your page with a single click. Every pattern is fully customizable, allowing you to tweak colors, typography, and content effortlessly.', 'patternswp'); ?></p>
135 </div>
136 </div>
137 </div>
138 </div>
139 </div>
140 </div>
141 </div>
142 <?php }
143
144 /**
145 * Support page
146 */
147 public function patternswp_support() { ?>
148 <div class="wrap">
149 <h1><?php esc_html_e('Support', 'patternswp'); ?></h1>
150 <h2 class="nav-tab-wrapper">
151 <?php $this->patterswp_tab( 'Support' ); ?>
152 </h2>
153 <div class="patterns-wp-tabs-content">
154 <div id="tab-1" class="patterns-wp-tab-content patterns-wp-tab-active">
155 </div>
156 <div id="tab-2" class="patterns-wp-tab-content">
157 <div class="wrap">
158 <div class="pw-feature-box big-box" style="max-width: 1280px; padding: 40px; background-color: white; border-radius: 10px; overflow: hidden;">
159 <div class="about__section has-1-columns">
160 <div class="column" style="">
161 <h1 class="feature-title"><?php esc_html_e('Support', 'patternswp'); ?></h1>
162 <p><?php esc_html_e('Need help with PatternsWP? Whether you have a question, need technical assistance, or just want to reach out, we’re here for you. Contact us, and we’ll be happy to assist!', 'patternswp'); ?></p>
163 </div>
164 <div style="height: 1px; background-color: #ccc; width: 100%; margin: 20px 0;"></div>
165 </div>
166 <div class="about__section has-2-columns">
167 <div class="column" style="padding-right: 100px;">
168
169 <h4><?php esc_html_e('Frequently asked questions', 'patternswp'); ?></h4>
170 <p>
171 <?php
172 printf(
173 esc_attr('Here, you will find answers to commonly asked questions about using PatternsWP. If you need further assistance, feel free to %s.', 'patternswp'),
174 '<a href="https://thepatternswp.com/contact/" target="_blank">'.esc_attr('contact us via the support form →', 'patternswp').'</a>'
175 );
176 ?>
177 </p>
178 </div>
179 <div class="column" style="padding: 0px;">
180 <h5>
181 <a href="https://thepatternswp.com/docs/getting-started-with-patternswp/" target="_blank" style="color: #3858e9; text-decoration: none;">
182 <?php esc_html_e('Getting Started with PatternsWP →', 'patternswp'); ?>
183 </a>
184 </h5>
185 <div style="height: 1px; background-color: #ccc; width: 100%; margin: 10px 0;"></div>
186 <h5>
187 <a href="https://thepatternswp.com/docs/how-to-install-patternswp/" target="_blank" style="color: #3858e9; text-decoration: none;">
188 <?php esc_html_e('How to install PatternsWP →', 'patternswp'); ?>
189 </a>
190 </h5> <div style="height: 1px; background-color: #ccc; width: 100%; margin: 10px 0;"></div>
191 <h5>
192 <a href="https://thepatternswp.com/docs/how-to-upgrade-patternswp-to-pro/" target="_blank" style="color: #3858e9; text-decoration: none;">
193 <?php esc_html_e('How to Upgrade PatternsWP to Pro →', 'patternswp'); ?>
194 </a>
195 </h5> <div style="height: 1px; background-color: #ccc; width: 100%; margin: 10px 0;"></div>
196 <h5>
197 <a href="https://thepatternswp.com/docs/patternswp-support/" target="_blank" style="color: #3858e9; text-decoration: none;">
198 <?php esc_html_e('PatternsWP Support →', 'patternswp'); ?>
199 </a>
200 </h5> <div style="height: 1px; background-color: #ccc; width: 100%; margin: 10px 0;"></div>
201 </div>
202
203 </div>
204 </div>
205 </div>
206 </div>
207 </div>
208 </div>
209 <?php }
210
211 /**
212 * Clear Cache page
213 */
214 public function patternswp_clear_cache_form() { ?>
215 <div class="wrap">
216 <h1><?php esc_html_e('Clear Cache', 'patternswp'); ?></h1>
217 <h2 class="nav-tab-wrapper">
218 <?php $this->patterswp_tab( 'Clear Cache' ); ?>
219 </h2>
220 <div class="patterns-wp-tabs-content">
221 <div id="tab-1" class="patterns-wp-tab-content patterns-wp-tab-active">
222 <div class="wrap">
223 <div class="container" style="padding: 20px; background-color: white; border-radius: 5px; overflow: hidden; width: 70%;">
224 <div class="">
225 <form id="patternswp_clearcache_form" method="post">
226 <?php wp_nonce_field('patternswp_clear_cache_action', 'patternswp_clear_cache_nonce'); ?>
227 <input name="patternswp_clear_cache" type="submit" class="button button-primary" value="Clear Cache">
228 <div>
229 </div>
230 </form>
231 </div>
232 </div>
233 </div>
234 </div>
235 </div>
236 </div>
237 <?php }
238
239 /**
240 * Clear Cache
241 */
242 public function patternswp_clear_cache() {
243 global $wpdb;
244
245 if (isset($_POST['patternswp_clear_cache'])) {
246 if (!isset($_POST['patternswp_clear_cache_nonce'])) {
247 wp_die(esc_attr__('Security check failed. Please try again.', 'patternswp'));
248 }
249
250 $nonce = sanitize_text_field(wp_unslash($_POST['patternswp_clear_cache_nonce']));
251
252 if (!wp_verify_nonce($nonce, 'patternswp_clear_cache_action')) {
253 wp_die(esc_attr__('Security check failed. Please try again.', 'patternswp'));
254 }
255
256 if (!current_user_can('manage_options')) {
257 wp_die(esc_attr('You do not have sufficient permissions to perform this action.', 'patternswp'));
258 }
259
260 // Delete category type transient
261 delete_transient('patternswp_category_type');
262
263 // Delete all API-related transients
264 $pattern = '_transient_patternswp_';
265 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
266 $results = $wpdb->get_col($wpdb->prepare("SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s", $wpdb->esc_like($pattern) . '%'));
267
268 // Delete all patterns cache
269 $patterns = 'patterns_cache_';
270 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
271 $wpdb->query(
272 $wpdb->prepare(
273 "DELETE FROM $wpdb->options WHERE option_name LIKE %s",
274 $wpdb->esc_like($patterns) . '%'
275 )
276 );
277
278 foreach ($results as $transient) {
279 delete_option($transient);
280 delete_option(str_replace('_transient_', '_transient_timeout_', $transient));
281 }
282
283 //load patterns in background
284 $this->patternswp_load_patterns_by_remote_ajax();
285
286 wp_redirect(add_query_arg(array(
287 'page' => 'patternswp-clear-cache',
288 'pt_msg' => urlencode('Clear Cache Successfully'),
289 'status' => 'success'
290 ), admin_url('admin.php')));
291 exit;
292 }
293 }
294
295 /**
296 * Ensure hourly cron job is scheduled
297 */
298 public function patternswp_ensure_hourly_cron() {
299 if ( ! wp_next_scheduled( 'patternswp_hourly_transient_load' ) ) {
300 wp_schedule_event( time(), 'hourly', 'patternswp_hourly_transient_load' );
301 }
302 }
303
304 /**
305 * AJAX handler to load transient data
306 */
307 public function patternswp_background_transient_load_ajaxcc() {
308 do_action( 'patternswp_hourly_transient_load' );
309 wp_die();
310 }
311
312 /**
313 * Load patterns via AJAX
314 */
315 public function patternswp_load_patterns_by_remote_ajax() {
316 $ajax_url = admin_url('admin-ajax.php');
317 wp_remote_post( $ajax_url , array(
318 'body' => array( 'action' => 'patternswp_background_transient_load_ajax' ),
319 'timeout' => 1,
320 'blocking' => false,
321 'sslverify' => false,
322 ));
323 }
324
325 /**
326 * Set transient on plugin activation
327 */
328 public function patternswp_on_activation() {
329 set_transient('patternswp_activation_redirect', true, 30);
330 }
331
332 /**
333 * Redirect to welcome page after activation
334 */
335 public function patternswp_redirect_on_activation() {
336 if (get_transient('patternswp_activation_redirect')) {
337 delete_transient('patternswp_activation_redirect');
338 if (!is_network_admin() && !isset($_GET['activate-multi'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Safe usage: only checking if 'activate-multi' is set
339 wp_safe_redirect(admin_url('admin.php?page=patternswp-plugin-menu'));
340 exit;
341 }
342 }
343 }
344 }
345
346 new PatternsWP_Admin();