: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ( $data['slug'] !== $this->slug ) {
// Don't allow a plugin to ping itself.
if ( trailingslashit( home_url() ) === $this->api_url ) {
if ( $this->request_recently_failed() ) {
return $this->get_version_from_remote();
* Determines if a request has recently failed.
private function request_recently_failed() {
$failed_request_details = get_option( $this->failed_request_cache_key );
// Request has never failed.
if ( empty( $failed_request_details ) || ! is_numeric( $failed_request_details ) ) {
* Request previously failed, but the timeout has expired.
* This means we're allowed to try again.
if ( time() > $failed_request_details ) {
delete_option( $this->failed_request_cache_key );
* Logs a failed HTTP request for this API URL.
* We set a timestamp for 1 hour from now. This prevents future API requests from being
* made to this domain for 1 hour. Once the timestamp is in the past, API requests
* will be allowed again. This way if the site is down for some reason we don't bombard
* it with failed API requests.
* @see EDD_SL_Plugin_Updater::request_recently_failed
private function log_failed_request() {
update_option( $this->failed_request_cache_key, strtotime( '+1 hour' ) );
* If available, show the changelog for sites in a multisite install.
public function show_changelog() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( empty( $_REQUEST['edd_sl_action'] ) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action'] ) {
if ( empty( $_REQUEST['plugin'] ) ) {
if ( empty( $_REQUEST['slug'] ) || $this->slug !== $_REQUEST['slug'] ) {
// phpcs:enable WordPress.Security.NonceVerification.Recommended
if ( ! current_user_can( 'update_plugins' ) ) {
wp_die( esc_html__( 'You do not have permission to install plugin updates', 'popup-maker' ), esc_html__( 'Error', 'popup-maker' ), [ 'response' => 403 ] );
$version_info = $this->get_repo_api_data();
if ( isset( $version_info->sections ) ) {
$sections = $this->convert_object_to_array( $version_info->sections );
if ( ! empty( $sections['changelog'] ) ) {
echo '<div style="background:#fff;padding:10px;">' . wp_kses_post( $sections['changelog'] ) . '</div>';
* Gets the current version information from the remote site.
private function get_version_from_remote() {
'edd_action' => 'get_version',
'license' => ! empty( $this->api_data['license'] ) ? $this->api_data['license'] : '',
'item_name' => isset( $this->api_data['item_name'] ) ? $this->api_data['item_name'] : false,
'item_id' => isset( $this->api_data['item_id'] ) ? $this->api_data['item_id'] : false,
'version' => isset( $this->api_data['version'] ) ? $this->api_data['version'] : false,
'author' => $this->api_data['author'],
'php_version' => phpversion(),
'wp_version' => get_bloginfo( 'version' ),
* Filters the parameters sent in the API request.
* @param array $api_params The array of data sent in the request.
* @param array $this->api_data The array of data set up in the class constructor.
* @param string $this->plugin_file The full path and filename of the file.
$api_params = apply_filters( 'edd_sl_plugin_updater_api_params', $api_params, $this->api_data, $this->plugin_file );
$request = wp_remote_post(
'sslverify' => $this->verify_ssl(),
if ( is_wp_error( $request ) || ( 200 !== wp_remote_retrieve_response_code( $request ) ) ) {
$this->log_failed_request();
$request = json_decode( wp_remote_retrieve_body( $request ) );
if ( $request && isset( $request->sections ) ) {
$request->sections = maybe_unserialize( $request->sections );
if ( $request && isset( $request->banners ) ) {
$request->banners = maybe_unserialize( $request->banners );
if ( $request && isset( $request->icons ) ) {
$request->icons = maybe_unserialize( $request->icons );
if ( ! empty( $request->sections ) ) {
foreach ( $request->sections as $key => $section ) {
$request->$key = (array) $section;
* Get the version info from the cache, if it exists.
* @param string $cache_key Cache key.
public function get_cached_version_info( $cache_key = '' ) {
if ( empty( $cache_key ) ) {
$cache_key = $this->get_cache_key();
$cache = get_option( $cache_key );
if ( empty( $cache['timeout'] ) || time() > $cache['timeout'] ) {
// We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point.
$cache['value'] = json_decode( $cache['value'] );
if ( ! empty( $cache['value']->icons ) ) {
$cache['value']->icons = (array) $cache['value']->icons;
* Adds the plugin version information to the database.
* @param string $value Value.
* @param string $cache_key Cache key.
public function set_version_info_cache( $value = '', $cache_key = '' ) {
if ( empty( $cache_key ) ) {
$cache_key = $this->get_cache_key();
'timeout' => strtotime( '+3 hours', time() ),
'value' => wp_json_encode( $value ),
update_option( $cache_key, $data, 'no' );
// Delete the duplicate option.
delete_option( 'edd_api_request_' . md5( maybe_serialize( $this->slug . $this->api_data['license'] . $this->beta ) ) );
* Returns if the SSL of the store should be verified.
private function verify_ssl() {
return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this );
* Gets the unique key (option name) for a plugin.
private function get_cache_key() {
$string = $this->slug . $this->api_data['license'] . $this->beta;
return 'edd_sl_' . md5( maybe_serialize( $string ) );