PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.1.1
Post Grid Gutenberg Blocks – PostX v5.1.1
5.1.1 5.1.0 5.0.41 5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 All 240 releases
ultimate-post / includes / notice / class-promo-links.php

class-promo-links.php in Post Grid Gutenberg Blocks – PostX 5.1.1, at includes/notice/class-promo-links.php

196 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Upgrade links outside the notices.
4 *
5 * @package ULTP\Notice
6 */
7
8 namespace ULTP\Includes\Notice;
9
10 defined( 'ABSPATH' ) || exit;
11
12 use ULTP\Includes\Durbin\Xpo;
13
14 /**
15 * The "Upgrade to Pro" link on the Plugins page and the "Upgrade to Pro" item in the PostX menu.
16 *
17 * Both switch to "Renew License" when the licence has expired, and to a sale's text during a sale.
18 * The sale texts and dates live in Campaigns: plugin_link_offers() and menu_offers().
19 */
20 class Promo_Links {
21
22 /**
23 * Slug of the menu item.
24 */
25 const MENU_SLUG = 'ultp-pro';
26
27 /**
28 * Register the hooks.
29 */
30 public function __construct() {
31 add_filter( 'plugin_action_links_' . ULTP_BASE, array( $this, 'add_plugin_action_link' ) );
32 add_action( 'admin_menu', array( $this, 'add_menu_link' ), 11 ); // After Options adds the rest of the menu, so it stays last.
33 add_action( 'admin_init', array( $this, 'redirect_menu_link' ) );
34 }
35
36 /**
37 * Append the upgrade (or renew) link to PostX's row on the Plugins page.
38 *
39 * @param array $links Plugin action links.
40 * @return array
41 */
42 public function add_plugin_action_link( $links ) {
43 // Free user or expired license user.
44 if ( defined( 'ULTP_PRO_VER' ) && ! Xpo::is_lc_expired() ) {
45 return $links;
46 }
47
48 $license_key = Xpo::get_lc_key() ?? '';
49
50 if ( Xpo::is_lc_expired() ) {
51 $text = esc_html__( 'Renew License', 'ultimate-post' );
52 $url = 'https://account.wpxpo.com/checkout/?edd_license_key=' . $license_key;
53 } else {
54 $text = esc_html__( 'Upgrade to Pro', 'ultimate-post' );
55 $url = Xpo::generate_utm_link(
56 array(
57 'utmKey' => 'sub_menu',
58 )
59 );
60
61 $offer = self::live_offer( self::campaign( 'plugin_link_offers', array() ) );
62 if ( $offer ) {
63 $url = Xpo::generate_utm_link(
64 array(
65 'utmKey' => $offer['utm_key'],
66 )
67 );
68 $text = $offer['text'];
69 }
70 }
71
72 $links['ultp_pro'] = '<a style="color: #0062ff; font-weight: bold;" target="_blank" href="' . esc_url( $url ) . '">' . esc_html( $text ) . '</a>';
73 return $links;
74 }
75
76 /**
77 * Add the upgrade (or renew) item at the end of the PostX menu.
78 *
79 * @return void
80 */
81 public function add_menu_link() {
82 $link = $this->get_menu_link();
83 if ( empty( $link ) ) {
84 return;
85 }
86
87 ob_start();
88 ?>
89 <a href="<?php echo esc_url( $link['url'] ); ?>" target="_blank" class="ultp-go-pro">
90 <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
91 <path d="M2.86 6.553a.5.5 0 01.823-.482l3.02 2.745c.196.178.506.13.64-.098L9.64 4.779a.417.417 0 01.72 0l2.297 3.939a.417.417 0 00.64.098l3.02-2.745a.5.5 0 01.823.482l-1.99 8.63a.833.833 0 01-.813.646H5.663a.833.833 0 01-.812-.646L2.86 6.553z" stroke="currentColor" stroke-width="1.5"></path>
92 </svg>
93 <span><?php echo esc_html( $link['text'] ); ?></span>
94 </a>
95 <?php
96 $submenu_content = ob_get_clean();
97
98 add_submenu_page(
99 'ultp-settings',
100 '',
101 $submenu_content,
102 'manage_options',
103 self::MENU_SLUG,
104 '__return_null' // Never rendered: redirect_menu_link() leaves first.
105 );
106 }
107
108 /**
109 * Send admin.php?page=ultp-pro to the same link the menu item shows.
110 *
111 * The item's visible link already opens it directly; this covers the item's own menu link
112 * (reachable by keyboard or by URL), which used to end in a fatal error.
113 *
114 * @return void
115 */
116 public function redirect_menu_link() {
117 if ( empty( $_GET['page'] ) || self::MENU_SLUG !== sanitize_key( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin page slug.
118 return;
119 }
120 $link = current_user_can( 'manage_options' ) ? $this->get_menu_link() : array();
121 if ( empty( $link ) ) {
122 return;
123 }
124 wp_redirect( $link['url'] ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- Fixed wpxpo.com pricing or checkout URL.
125 exit;
126 }
127
128 /**
129 * The first offer whose `start`–`end` window includes now.
130 *
131 * @param array $offers Offers from Campaigns.
132 * @return array|null
133 */
134 private static function live_offer( $offers ) {
135 $current_time = gmdate( 'U' );
136 foreach ( $offers as $offer ) {
137 if ( ! isset( $offer['start'], $offer['end'], $offer['text'] ) ) {
138 continue;
139 }
140 $offer_start = gmdate( 'U', strtotime( $offer['start'] ) );
141 $offer_end = gmdate( 'U', strtotime( $offer['end'] ) );
142 if ( $current_time >= $offer_start && $current_time <= $offer_end ) {
143 return $offer;
144 }
145 }
146 return null;
147 }
148
149 /**
150 * Read sale settings from Campaigns. class-campaigns.php is edited for every sale, so it is loaded
151 * here inside a try, as Notice does: a mistake in it drops the sale text, never the page.
152 *
153 * @param string $method Campaigns method to call.
154 * @param array $fallback Returned when the file or method fails.
155 * @return array
156 */
157 private static function campaign( $method, $fallback ) {
158 try {
159 require_once __DIR__ . '/class-campaigns.php';
160 $value = call_user_func( array( Campaigns::class, $method ) );
161 } catch ( \Throwable $e ) {
162 return $fallback;
163 }
164 return is_array( $value ) ? $value : $fallback;
165 }
166
167 /**
168 * The menu item's link and text, or nothing when the licence is active.
169 *
170 * @return array{url: string, text: string}|array Empty when no item should show.
171 */
172 private function get_menu_link() {
173 $offer = self::live_offer( self::campaign( 'menu_offers', array() ) );
174
175 if ( ! Xpo::is_lc_active() ) {
176 return array(
177 'url' => Xpo::generate_utm_link(
178 array(
179 'utmKey' => 'sub_menu',
180 )
181 ),
182 'text' => $offer ? $offer['text'] : __( 'Upgrade to Pro', 'ultimate-post' ),
183 );
184 }
185
186 if ( Xpo::is_lc_expired() ) {
187 return array(
188 'url' => 'https://account.wpxpo.com/checkout/?edd_license_key=' . Xpo::get_lc_key(),
189 'text' => __( 'Renew License', 'ultimate-post' ),
190 );
191 }
192
193 return array();
194 }
195 }
196