| @@ -22,8 +22,11 @@ | ||
| 22 | 22 | $label = '<span style="color:#1da867">' . $label . '</span>'; |
| 23 | 23 | |
| 24 | 24 | add_submenu_page( 'formidable', 'Formidable | ' . __( 'Add-Ons', 'formidable' ), $label, 'frm_view_forms', 'formidable-addons', 'FrmAddonsController::list_addons' ); |
| 25 | 25 | |
| 26 | + // remove default created subpage, make the page with highest priority as default. | |
| 27 | + remove_submenu_page( 'formidable', 'formidable' ); | |
| 28 | + | |
| 26 | 29 | if ( ! FrmAppHelper::pro_is_installed() ) { |
| 27 | 30 | add_submenu_page( |
| 28 | 31 | 'formidable', |
| 29 | 32 | 'Formidable | ' . __( 'Upgrade', 'formidable' ), |
| @@ -297,12 +300,13 @@ | ||
| 297 | 300 | } |
| 298 | 301 | |
| 299 | 302 | /** |
| 300 | 303 | * @since 4.08 |
| 304 | + * @since 6.7 This is public. | |
| 301 | 305 | * |
| 302 | 306 | * @return array|false |
| 303 | 307 | */ |
| 304 | - protected static function get_primary_license_info() { | |
| 308 | + public static function get_primary_license_info() { | |
| 305 | 309 | $installed_addons = apply_filters( 'frm_installed_addons', array() ); |
| 306 | 310 | if ( empty( $installed_addons ) || ! isset( $installed_addons['formidable_pro'] ) ) { |
| 307 | 311 | return false; |
| 308 | 312 | } |
| @@ -351,20 +355,21 @@ | ||
| 351 | 355 | // don't show an update if the plugin isn't installed |
| 352 | 356 | continue; |
| 353 | 357 | } |
| 354 | 358 | |
| 355 | - $wp_plugin = isset( $wp_plugins[ $folder ] ) ? $wp_plugins[ $folder ] : array(); | |
| 356 | - $wp_version = isset( $wp_plugin['Version'] ) ? $wp_plugin['Version'] : '1.0'; | |
| 359 | + $wp_plugin = isset( $wp_plugins[ $folder ] ) ? $wp_plugins[ $folder ] : array(); | |
| 360 | + $wp_version = isset( $wp_plugin['Version'] ) ? $wp_plugin['Version'] : '1.0'; | |
| 361 | + $plugin->slug = explode( '/', $folder )[0]; | |
| 357 | 362 | |
| 358 | 363 | if ( version_compare( $wp_version, $plugin->new_version, '<' ) ) { |
| 359 | - $slug = explode( '/', $folder ); | |
| 360 | - $plugin->slug = $slug[0]; | |
| 361 | 364 | $transient->response[ $folder ] = $plugin; |
| 365 | + } else { | |
| 366 | + $transient->no_update[ $folder ] = $plugin; | |
| 362 | 367 | } |
| 363 | 368 | |
| 364 | 369 | $transient->checked[ $folder ] = $wp_version; |
| 365 | 370 | |
| 366 | - } | |
| 371 | + }//end foreach | |
| 367 | 372 | |
| 368 | 373 | return $transient; |
| 369 | 374 | } |
| 370 | 375 | |
| @@ -387,9 +392,9 @@ | ||
| 387 | 392 | * Check if a plugin is installed before showing an update for it |
| 388 | 393 | * |
| 389 | 394 | * @since 3.05 |
| 390 | 395 | * |
| 391 | - * @param string $plugin - the folder/filename.php for a plugin | |
| 396 | + * @param string $plugin The folder/filename.php for a plugin. | |
| 392 | 397 | * |
| 393 | 398 | * @return bool - True if installed |
| 394 | 399 | */ |
| 395 | 400 | protected static function is_installed( $plugin ) { |
| @@ -444,9 +449,9 @@ | ||
| 444 | 449 | 'code' => $addon_info['error']['code'], |
| 445 | 450 | ); |
| 446 | 451 | } |
| 447 | 452 | } |
| 448 | - } | |
| 453 | + }//end foreach | |
| 449 | 454 | |
| 450 | 455 | return $version_info; |
| 451 | 456 | } |
| 452 | 457 | |
| @@ -453,9 +458,9 @@ | ||
| 453 | 458 | /** |
| 454 | 459 | * Get the action link for an addon that isn't active. |
| 455 | 460 | * |
| 456 | 461 | * @since 3.06.03 |
| 457 | - * @param string $plugin The plugin slug | |
| 462 | + * @param string $plugin The plugin slug. | |
| 458 | 463 | * @return array |
| 459 | 464 | */ |
| 460 | 465 | public static function install_link( $plugin ) { |
| 461 | 466 | $link = array(); |
| @@ -485,9 +490,9 @@ | ||
| 485 | 490 | $link = array( |
| 486 | 491 | 'url' => 'formidable-' . $plugin . '/formidable-' . $plugin . '.php', |
| 487 | 492 | 'class' => 'frm-activate-addon', |
| 488 | 493 | ); |
| 489 | - } | |
| 494 | + }//end if | |
| 490 | 495 | |
| 491 | 496 | return $link; |
| 492 | 497 | } |
| 493 | 498 | |
| @@ -492,9 +497,9 @@ | ||
| 492 | 497 | } |
| 493 | 498 | |
| 494 | 499 | /** |
| 495 | 500 | * @since 4.09 |
| 496 | - * @param string $plugin The plugin slug | |
| 501 | + * @param string $plugin The plugin slug. | |
| 497 | 502 | * @return array|false |
| 498 | 503 | */ |
| 499 | 504 | protected static function get_addon( $plugin ) { |
| 500 | 505 | $addons = self::get_api_addons(); |
| @@ -523,10 +528,10 @@ | ||
| 523 | 528 | |
| 524 | 529 | /** |
| 525 | 530 | * @since 3.04.03 |
| 526 | 531 | * |
| 527 | - * @param array $addons | |
| 528 | - * @param object $license The FrmAddon object | |
| 532 | + * @param array $addons | |
| 533 | + * @param object $license The FrmAddon object. | |
| 529 | 534 | * |
| 530 | 535 | * @return array |
| 531 | 536 | */ |
| 532 | 537 | public static function get_addon_for_license( $addons, $license ) { |
| @@ -603,9 +608,9 @@ | ||
| 603 | 608 | self::prepare_addon_link( $addon['link'] ); |
| 604 | 609 | |
| 605 | 610 | self::set_addon_status( $addon ); |
| 606 | 611 | $addons[ $id ] = $addon; |
| 607 | - } | |
| 612 | + }//end foreach | |
| 608 | 613 | } |
| 609 | 614 | |
| 610 | 615 | /** |
| 611 | 616 | * @return bool |
| @@ -932,14 +937,57 @@ | ||
| 932 | 937 | return activate_plugin( $plugin, $redirect, $network_wide, $silent ); |
| 933 | 938 | } |
| 934 | 939 | |
| 935 | 940 | /** |
| 941 | + * Deactivate a specified plugin. | |
| 942 | + * | |
| 943 | + * @since 6.8 | |
| 944 | + * | |
| 945 | + * @param string $plugin | |
| 946 | + * @param bool $silent | |
| 947 | + * @return void | |
| 948 | + */ | |
| 949 | + protected static function deactivate_plugin( $plugin, $silent = false ) { | |
| 950 | + if ( ! function_exists( 'deactivate_plugins' ) ) { | |
| 951 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; | |
| 952 | + } | |
| 953 | + deactivate_plugins( $plugin, $silent ); | |
| 954 | + } | |
| 955 | + | |
| 956 | + /** | |
| 957 | + * Uninstall a specified plugin. | |
| 958 | + * | |
| 959 | + * @since 6.8 | |
| 960 | + * | |
| 961 | + * @param string $plugin | |
| 962 | + * @return true|WP_Error True on success, WP_Error on invalid file. | |
| 963 | + */ | |
| 964 | + protected static function uninstall_plugin( $plugin ) { | |
| 965 | + if ( ! current_user_can( 'delete_plugins' ) ) { | |
| 966 | + return new WP_Error( 'uninstall_failed', __( 'Current user cannot delete plugins.', 'formidable' ) ); | |
| 967 | + } | |
| 968 | + | |
| 969 | + if ( ! function_exists( 'delete_plugins' ) ) { | |
| 970 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; | |
| 971 | + } | |
| 972 | + | |
| 973 | + self::deactivate_plugin( $plugin, true ); | |
| 974 | + $result = delete_plugins( array( $plugin ) ); | |
| 975 | + | |
| 976 | + if ( is_wp_error( $result ) ) { | |
| 977 | + return $result; | |
| 978 | + } | |
| 979 | + | |
| 980 | + return true; | |
| 981 | + } | |
| 982 | + | |
| 983 | + /** | |
| 936 | 984 | * @since 5.0.10 |
| 937 | 985 | * |
| 938 | 986 | * @return string |
| 939 | 987 | */ |
| 940 | 988 | protected static function get_current_plugin() { |
| 941 | - if ( ! isset( self::$plugin ) ) { | |
| 989 | + if ( empty( self::$plugin ) ) { | |
| 942 | 990 | self::$plugin = FrmAppHelper::get_param( 'plugin', '', 'post', 'esc_url_raw' ); |
| 943 | 991 | } |
| 944 | 992 | return self::$plugin; |
| 945 | 993 | } |
| @@ -957,9 +1005,9 @@ | ||
| 957 | 1005 | $installed = self::install_addon(); |
| 958 | 1006 | if ( is_array( $installed ) && isset( $installed['message'] ) ) { |
| 959 | 1007 | return $installed; |
| 960 | 1008 | } |
| 961 | - self::maybe_activate_addon( $installed ); | |
| 1009 | + self::handle_addon_action( $installed, 'activate' ); | |
| 962 | 1010 | } |
| 963 | 1011 | |
| 964 | 1012 | /** |
| 965 | 1013 | * @since 3.04.02 |
| @@ -1052,26 +1100,130 @@ | ||
| 1052 | 1100 | return $plugin; |
| 1053 | 1101 | } |
| 1054 | 1102 | |
| 1055 | 1103 | /** |
| 1056 | - * @since 3.06.03 | |
| 1104 | + * Handle the AJAX request to activate an add-on. | |
| 1057 | 1105 | * |
| 1106 | + * @since 6.8 | |
| 1107 | + * | |
| 1058 | 1108 | * @return void |
| 1059 | 1109 | */ |
| 1060 | 1110 | public static function ajax_activate_addon() { |
| 1111 | + self::process_addon_action( | |
| 1112 | + function( $plugin ) { | |
| 1113 | + return self::handle_addon_action( $plugin, 'activate' ); | |
| 1114 | + }, | |
| 1115 | + array( 'FrmAddonsController', 'get_addon_activation_response' ) | |
| 1116 | + ); | |
| 1117 | + } | |
| 1061 | 1118 | |
| 1119 | + /** | |
| 1120 | + * @since 3.04.02 | |
| 1121 | + * | |
| 1122 | + * @param string $installed The plugin folder name with file name. | |
| 1123 | + */ | |
| 1124 | + protected static function maybe_activate_addon( $installed ) { | |
| 1125 | + self::ajax_activate_addon(); | |
| 1126 | + } | |
| 1127 | + | |
| 1128 | + /** | |
| 1129 | + * Handle the AJAX request to deactivate an add-on. | |
| 1130 | + * | |
| 1131 | + * @since 6.8 | |
| 1132 | + * | |
| 1133 | + * @return void | |
| 1134 | + */ | |
| 1135 | + public static function ajax_deactivate_addon() { | |
| 1136 | + self::process_addon_action( | |
| 1137 | + function( $plugin ) { | |
| 1138 | + return self::handle_addon_action( $plugin, 'deactivate' ); | |
| 1139 | + } | |
| 1140 | + ); | |
| 1141 | + } | |
| 1142 | + | |
| 1143 | + /** | |
| 1144 | + * Handle the AJAX request to uninstall an add-on. | |
| 1145 | + * | |
| 1146 | + * @since 6.8 | |
| 1147 | + * | |
| 1148 | + * @return void | |
| 1149 | + */ | |
| 1150 | + public static function ajax_uninstall_addon() { | |
| 1151 | + self::process_addon_action( | |
| 1152 | + function( $plugin ) { | |
| 1153 | + return self::handle_addon_action( $plugin, 'uninstall' ); | |
| 1154 | + } | |
| 1155 | + ); | |
| 1156 | + } | |
| 1157 | + | |
| 1158 | + /** | |
| 1159 | + * Process a specific action (activate, deactivate, uninstall) on an add-on. | |
| 1160 | + * | |
| 1161 | + * @since 6.8 | |
| 1162 | + * | |
| 1163 | + * @param callable $action_callback The specific add-on action to be executed. | |
| 1164 | + * @param callable|null $response_callback Optional. The response handling callback. Default null. | |
| 1165 | + * @return void | |
| 1166 | + */ | |
| 1167 | + private static function process_addon_action( $action_callback, $response_callback = null ) { | |
| 1062 | 1168 | self::install_addon_permissions(); |
| 1063 | - | |
| 1064 | 1169 | FrmAppHelper::set_current_screen_and_hook_suffix(); |
| 1065 | 1170 | |
| 1066 | 1171 | $plugin = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' ); |
| 1067 | - self::maybe_activate_addon( $plugin ); | |
| 1172 | + call_user_func( $action_callback, $plugin ); | |
| 1068 | 1173 | |
| 1069 | - echo json_encode( self::get_addon_activation_response() ); | |
| 1070 | - wp_die(); | |
| 1174 | + if ( is_callable( $response_callback ) ) { | |
| 1175 | + wp_send_json_success( call_user_func( $response_callback ) ); | |
| 1176 | + return; | |
| 1177 | + } | |
| 1178 | + | |
| 1179 | + wp_send_json_success(); | |
| 1071 | 1180 | } |
| 1072 | 1181 | |
| 1073 | 1182 | /** |
| 1183 | + * Attempt to perform a specific action (activate, deactivate, uninstall) on an add-on. | |
| 1184 | + * | |
| 1185 | + * @since 6.8 | |
| 1186 | + * | |
| 1187 | + * @param string $installed The plugin folder name with file name. | |
| 1188 | + * @param string $action The action type ('activate', 'deactivate', 'uninstall'). | |
| 1189 | + * @return void|array | |
| 1190 | + */ | |
| 1191 | + protected static function handle_addon_action( $installed, $action ) { | |
| 1192 | + if ( ! $installed || ! $action ) { | |
| 1193 | + return; | |
| 1194 | + } | |
| 1195 | + | |
| 1196 | + $result = null; | |
| 1197 | + switch ( $action ) { | |
| 1198 | + case 'activate': | |
| 1199 | + $result = self::activate_plugin( $installed ); | |
| 1200 | + break; | |
| 1201 | + case 'deactivate': | |
| 1202 | + self::deactivate_plugin( $installed ); | |
| 1203 | + break; | |
| 1204 | + case 'uninstall': | |
| 1205 | + $result = self::uninstall_plugin( $installed ); | |
| 1206 | + break; | |
| 1207 | + } | |
| 1208 | + | |
| 1209 | + if ( is_wp_error( $result ) ) { | |
| 1210 | + // Ignore the invalid header message that shows with nested plugins. | |
| 1211 | + if ( $result->get_error_code() !== 'no_plugin_header' ) { | |
| 1212 | + if ( wp_doing_ajax() ) { | |
| 1213 | + wp_send_json_error( array( 'error' => $result->get_error_message() ) ); | |
| 1214 | + } | |
| 1215 | + return array( | |
| 1216 | + 'message' => $result->get_error_message(), | |
| 1217 | + 'success' => false, | |
| 1218 | + ); | |
| 1219 | + } | |
| 1220 | + } | |
| 1221 | + | |
| 1222 | + return $result; | |
| 1223 | + } | |
| 1224 | + | |
| 1225 | + /** | |
| 1074 | 1226 | * @return array |
| 1075 | 1227 | */ |
| 1076 | 1228 | private static function get_addon_activation_response() { |
| 1077 | 1229 | $activating_page = self::get_activating_page(); |
| @@ -1105,34 +1257,8 @@ | ||
| 1105 | 1257 | return ''; |
| 1106 | 1258 | } |
| 1107 | 1259 | |
| 1108 | 1260 | /** |
| 1109 | - * @since 3.04.02 | |
| 1110 | - * | |
| 1111 | - * @param string $installed The plugin folder name with file name | |
| 1112 | - */ | |
| 1113 | - protected static function maybe_activate_addon( $installed ) { | |
| 1114 | - if ( ! $installed ) { | |
| 1115 | - return; | |
| 1116 | - } | |
| 1117 | - | |
| 1118 | - $activate = self::activate_plugin( $installed ); | |
| 1119 | - if ( is_wp_error( $activate ) ) { | |
| 1120 | - // Ignore the invalid header message that shows with nested plugins. | |
| 1121 | - if ( $activate->get_error_code() !== 'no_plugin_header' ) { | |
| 1122 | - if ( wp_doing_ajax() ) { | |
| 1123 | - echo json_encode( array( 'error' => $activate->get_error_message() ) ); | |
| 1124 | - wp_die(); | |
| 1125 | - } | |
| 1126 | - return array( | |
| 1127 | - 'message' => $activate->get_error_message(), | |
| 1128 | - 'success' => false, | |
| 1129 | - ); | |
| 1130 | - } | |
| 1131 | - } | |
| 1132 | - } | |
| 1133 | - | |
| 1134 | - /** | |
| 1135 | 1261 | * Run security checks before installing |
| 1136 | 1262 | * |
| 1137 | 1263 | * @since 3.04.02 |
| 1138 | 1264 | * |
| @@ -1155,9 +1281,9 @@ | ||
| 1155 | 1281 | public static function connect_link() { |
| 1156 | 1282 | $auth = get_option( 'frm_connect_token' ); |
| 1157 | 1283 | if ( empty( $auth ) ) { |
| 1158 | 1284 | $auth = hash( 'sha512', wp_rand() ); |
| 1159 | - update_option( 'frm_connect_token', $auth ); | |
| 1285 | + update_option( 'frm_connect_token', $auth, 'no' ); | |
| 1160 | 1286 | } |
| 1161 | 1287 | $link = FrmAppHelper::admin_upgrade_link( 'connect', 'api-connect' ); |
| 1162 | 1288 | $args = array( |
| 1163 | 1289 | 'v' => 2, |
| @@ -1243,21 +1369,32 @@ | ||
| 1243 | 1369 | |
| 1244 | 1370 | /** |
| 1245 | 1371 | * Render a conditional action button for a specified plugin |
| 1246 | 1372 | * |
| 1247 | - * @param string $plugin | |
| 1373 | + * @since 4.09 | |
| 1374 | + * | |
| 1375 | + * @param string $plugin | |
| 1248 | 1376 | * @param array|string $upgrade_link_args |
| 1249 | - * @since 4.09 | |
| 1377 | + * @return void | |
| 1250 | 1378 | */ |
| 1251 | 1379 | public static function conditional_action_button( $plugin, $upgrade_link_args ) { |
| 1252 | 1380 | if ( is_callable( 'FrmProAddonsController::conditional_action_button' ) ) { |
| 1253 | - return FrmProAddonsController::conditional_action_button( $plugin, $upgrade_link_args ); | |
| 1381 | + FrmProAddonsController::conditional_action_button( $plugin, $upgrade_link_args ); | |
| 1382 | + return; | |
| 1254 | 1383 | } |
| 1255 | 1384 | |
| 1256 | 1385 | $addon = self::get_addon( $plugin ); |
| 1257 | 1386 | $upgrade_link = FrmAppHelper::admin_upgrade_link( $upgrade_link_args ); |
| 1258 | 1387 | |
| 1388 | + if ( ! is_array( $upgrade_link_args ) ) { | |
| 1389 | + // A string $upgrade_link_args is used for the utm-medium value when calling | |
| 1390 | + // FrmAppHelper::admin_upgrade_link above. | |
| 1391 | + // For self::addon_upgrade_link, we'll pass just an empty array with the link key (set below). | |
| 1392 | + $upgrade_link_args = array(); | |
| 1393 | + } | |
| 1394 | + | |
| 1259 | 1395 | $upgrade_link_args['link'] = $upgrade_link; |
| 1396 | + | |
| 1260 | 1397 | self::addon_upgrade_link( $addon, $upgrade_link_args ); |
| 1261 | 1398 | } |
| 1262 | 1399 | |
| 1263 | 1400 | /** |
| @@ -1264,16 +1401,22 @@ | ||
| 1264 | 1401 | * Render a conditional action button for an add on |
| 1265 | 1402 | * |
| 1266 | 1403 | * @since 4.09.01 |
| 1267 | 1404 | * |
| 1268 | - * @param array $addon | |
| 1269 | - * @param string|false $license_type | |
| 1270 | - * @param string $plan_required | |
| 1271 | - * @param string $upgrade_link | |
| 1405 | + * @param array $atts { | |
| 1406 | + * Button attributes. | |
| 1407 | + * | |
| 1408 | + * @type array $addon | |
| 1409 | + * @type string|false $license_type | |
| 1410 | + * @type string $plan_required | |
| 1411 | + * @type string $upgrade_link | |
| 1412 | + * } | |
| 1413 | + * @return void | |
| 1272 | 1414 | */ |
| 1273 | 1415 | public static function show_conditional_action_button( $atts ) { |
| 1274 | 1416 | if ( is_callable( 'FrmProAddonsController::show_conditional_action_button' ) ) { |
| 1275 | - return FrmProAddonsController::show_conditional_action_button( $atts ); | |
| 1417 | + FrmProAddonsController::show_conditional_action_button( $atts ); | |
| 1418 | + return; | |
| 1276 | 1419 | } |
| 1277 | 1420 | |
| 1278 | 1421 | self::addon_upgrade_link( $atts['addon'], $atts['upgrade_link'] ); |
| 1279 | 1422 | } |
| @@ -1453,9 +1596,9 @@ | ||
| 1453 | 1596 | * @deprecated 3.04.03 |
| 1454 | 1597 | * @codeCoverageIgnore |
| 1455 | 1598 | * |
| 1456 | 1599 | * @param boolean $return |
| 1457 | - * @param string $package | |
| 1600 | + * @param string $package | |
| 1458 | 1601 | * |
| 1459 | 1602 | * @return boolean |
| 1460 | 1603 | */ |
| 1461 | 1604 | public static function add_shorten_edd_filename_filter( $return, $package ) { |