'woocommerce/woocommerce.php', ]; return is_plugin_active($paths[strtolower($pluginSlug)] ?? "{$pluginSlug}/{$pluginSlug}.php"); } public static function getCurrentUrl($clean = false) { $http = 'http'; if (isset($_SERVER['HTTPS'])) { $http = 'https'; } $host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : ''; $requestUri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; if ($clean == true) { return trim(strtok($http . '://' . htmlentities($host) . htmlentities($requestUri), '?')); } else { return $http . '://' . htmlentities($host) . htmlentities($requestUri); } } public static function getHomeUrl($path = '/', $trailingSlash = true) { return $trailingSlash ? trailingslashit(home_url($path, 'https')) : untrailingslashit(home_url($path, 'https')); } /** * Whether the running build can actually execute Pro code. * * Deliberately mirrors the SDK's premium-only licence check, but without the * suffix in the name. Freemius' deployment processor strips the body of any * `if` that calls a suffixed method, and it does not understand the `!`, so a * negated branch written that way would silently vanish from the free build. * The admin UI decides what to *show* and must behave identically in both * builds, so it uses this; includes/features/ decides what to *run* and keeps * the suffixed call so Freemius strips it. */ public static function hasActivePro() { $fs = \DaftPlug\Rankify\rankify_pro(); return $fs->is_premium() && $fs->can_use_premium_code(); } /** * Where the in-admin "Enable Pro" CTAs point. * * Still the plugin's own page rather than the store: the click opens the Pro * popup in place, and only the button inside it leaves for daftplug.com. */ public static function getUpgradeUrl() { return admin_url('admin.php?page=rankify&upgradeToPro=true'); } /** The store page the popup's button opens. */ public static function getPricingUrl($utmSource = 'plugin-admin-area') { return "https://daftplug.com/pricing/?utm_source={$utmSource}&utm_medium=crownify-admin-page&utm_campaign=upgrade-to-pro"; } /** This plugin's own marketing page, for readers who want detail before price. */ public static function getProInfoUrl($utmSource = 'plugin-admin-area') { return "https://daftplug.com/crownify/?utm_source={$utmSource}&utm_medium=crownify-admin-page&utm_campaign=learn-more"; } /** * "Enable", not "Upgrade": Pro reads as a switch the site owner turns on * rather than purely a transaction, and every CTA now says the same thing. */ public static function getUpgradeLabel() { return __('Enable Pro', 'crownify'); } /** * Register one REST route on the public namespace and the legacy one. * * The admin calls crownify/v1. rankify/v1 stays registered so a cached * admin script, a page-cache beacon, or anything else already calling the * old path keeps working after the rename. */ public static function registerRestRoute($route, $args) { register_rest_route('crownify/v1', $route, $args); register_rest_route('rankify/v1', $route, $args); } public static function getSetting($key) { $keys = preg_split('/\]\[|\[|\]/', $key, -1, PREG_SPLIT_NO_EMPTY); $settings = get_option('rankify_settings', []); foreach ($keys as $k) { if (isset($settings[$k])) { $settings = $settings[$k]; } else { return false; } } return $settings; } public static function ensureDir($dir) { if (file_exists($dir)) { return is_dir($dir); } return (bool) wp_mkdir_p($dir); } public static function getContent($file) { if (empty($file) || !is_file($file)) { return false; } $wp_filesystem = self::filesystem(); $content = $wp_filesystem->get_contents($file); if ($content === false) { return false; } return $content; } public static function putContent($file, $content = null) { if (empty($file)) { return false; } if (is_file($file)) { wp_delete_file($file); } $wp_filesystem = self::filesystem(); $chmod = defined('FS_CHMOD_FILE') ? FS_CHMOD_FILE : 0644; if (!$wp_filesystem->put_contents($file, $content, $chmod)) { return false; } return true; } public static function appendContent($file, $content) { if (empty($file)) { return false; } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem has no append mode; the 404 log and sitemap writers append in chunks. return file_put_contents($file, $content, FILE_APPEND) !== false; } public static function deleteFile($file) { if (empty($file) || !file_exists($file)) { return true; } if (is_dir($file) && !is_link($file)) { return false; } return (bool) wp_delete_file($file); } public static function deleteDir($dir, $recursive = false) { if (empty($dir) || !file_exists($dir)) { return true; } if (!is_dir($dir)) { return false; } $wp_filesystem = self::filesystem(); return (bool) $wp_filesystem->rmdir($dir, $recursive); } public static function renameFile($source, $destination) { if (empty($source) || empty($destination) || !file_exists($source)) { return false; } $wp_filesystem = self::filesystem(); return (bool) $wp_filesystem->move($source, $destination, true); } public static function touchFile($file) { if (empty($file)) { return false; } $wp_filesystem = self::filesystem(); if (method_exists($wp_filesystem, 'touch')) { return (bool) $wp_filesystem->touch($file); } return self::putContent($file, ''); } public static function copyFile($source, $destination) { if (empty($source) || empty($destination) || !is_file($source)) { return false; } $wp_filesystem = self::filesystem(); $chmod = defined('FS_CHMOD_FILE') ? FS_CHMOD_FILE : 0644; return (bool) $wp_filesystem->copy($source, $destination, true, $chmod); } // ──────────────────────────────────────────────────────────── // Optional PHP functions // ──────────────────────────────────────────────────────────── // // Shared hosts routinely list these in disable_functions. A disabled function // is REMOVED from PHP, not made to fail — so an unqualified call from a // namespaced file cannot fall back to the global scope and dies with // "Call to undefined function DaftPlug\Rankify\...\name()". The @ operator // does not help: that is a fatal Error, not a diagnostic. Every call to one of // these has to be guarded by function_exists() and fully qualified. /** * Give a long-running job the best chance of finishing: keep going if the * client disconnects, and lift the execution time limit. Both are advisory — * hosts disable them, and set_time_limit is a no-op in safe_mode-like setups. */ public static function relaxExecutionLimits($ignoreUserAbort = true) { if ($ignoreUserAbort && function_exists('ignore_user_abort')) { @\ignore_user_abort(true); } if (function_exists('set_time_limit')) { @\set_time_limit(0); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- Bulk optimize and sitemap generation legitimately outlive the default execution limit. } } /** * Free bytes on the filesystem holding $path, or null when the host won't * say (disk_free_space disabled, open_basedir, or an odd filesystem). * Callers must treat null as "unknown" and carry on rather than blocking. * * @return float|null */ public static function freeDiskSpace($path) { if (!function_exists('disk_free_space')) { return null; } $free = @\disk_free_space($path); return is_float($free) || is_int($free) ? (float) $free : null; } }