/** * Plugin Name: Elementor * Description: The Elementor Website Builder has it all: drag and drop page builder, pixel perfect design, mobile responsive editing, and more. Get started now! * Plugin URI: https://elementor.com/?utm_source=wp-plugins&utm_campaign=plugin-uri&utm_medium=wp-dash * Author: Elementor.com * Version: 3.20.1 * Author URI: https://elementor.com/?utm_source=wp-plugins&utm_campaign=author-uri&utm_medium=wp-dash * * Text Domain: elementor * * @package Elementor * @category Core * * Elementor is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * Elementor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } define( 'ELEMENTOR_VERSION', '3.20.1' ); define( 'ELEMENTOR__FILE__', __FILE__ ); define( 'ELEMENTOR_PLUGIN_BASE', plugin_basename( ELEMENTOR__FILE__ ) ); define( 'ELEMENTOR_PATH', plugin_dir_path( ELEMENTOR__FILE__ ) ); if ( defined( 'ELEMENTOR_TESTS' ) && ELEMENTOR_TESTS ) { define( 'ELEMENTOR_URL', 'file://' . ELEMENTOR_PATH ); } else { define( 'ELEMENTOR_URL', plugins_url( '/', ELEMENTOR__FILE__ ) ); } define( 'ELEMENTOR_MODULES_PATH', plugin_dir_path( ELEMENTOR__FILE__ ) . '/modules' ); define( 'ELEMENTOR_ASSETS_PATH', ELEMENTOR_PATH . 'assets/' ); define( 'ELEMENTOR_ASSETS_URL', ELEMENTOR_URL . 'assets/' ); add_action( 'plugins_loaded', 'elementor_load_plugin_textdomain' ); if ( ! version_compare( PHP_VERSION, '7.4', '>=' ) ) { add_action( 'admin_notices', 'elementor_fail_php_version' ); } elseif ( ! version_compare( get_bloginfo( 'version' ), '6.0', '>=' ) ) { add_action( 'admin_notices', 'elementor_fail_wp_version' ); } else { require ELEMENTOR_PATH . 'includes/plugin.php'; } /** * Load Elementor textdomain. * * Load gettext translate for Elementor text domain. * * @since 1.0.0 * * @return void */ function elementor_load_plugin_textdomain() { load_plugin_textdomain( 'elementor' ); } /** * Elementor admin notice for minimum PHP version. * * Warning when the site doesn't have the minimum required PHP version. * * @since 1.0.0 * * @return void */ function elementor_fail_php_version() { $message = sprintf( /* translators: 1: `

` opening tag, 2: `

` closing tag, 3: PHP version. 4: Link opening tag, 5: Link closing tag. */ esc_html__( '%1$sElementor isn’t running because PHP is outdated.%2$s Update to PHP version %3$s and get back to creating! %4$sShow me how%5$s', 'elementor' ), '

', '

', '7.4', '', '' ); $html_message = sprintf( '
%s
', wpautop( $message ) ); echo wp_kses_post( $html_message ); } /** * Elementor admin notice for minimum WordPress version. * * Warning when the site doesn't have the minimum required WordPress version. * * @since 1.5.0 * * @return void */ function elementor_fail_wp_version() { $message = sprintf( /* translators: 1: `

` opening tag, 2: `

` closing tag, 3: WP version. 4: Link opening tag, 5: Link closing tag. */ esc_html__( '%1$sElementor isn’t running because WordPress is outdated.%2$s Update to version %3$s and get back to creating! %4$sShow me how%5$s', 'elementor' ), '

', '

', '6.0', '', '' ); $html_message = sprintf( '
%s
', wpautop( $message ) ); echo wp_kses_post( $html_message ); }/** * Exit if accessed directly. */ if ( ! defined( 'ABSPATH' ) ) { exit; } #[AllowDynamicProperties] class Wpzoom_Instagram_Widget_API { /** * @var Wpzoom_Instagram_Widget_API The reference to *Singleton* instance of this class */ private static $instance; /** * Request headers. * * @var array */ public $headers = array(); /** * Errors collector. * * @var array|WP_Error */ public $errors = array(); /** * Instagram Settings * * @var array */ public $settings; /** * Instagram Access Token * * @var string */ protected $access_token; /** * Feed ID * * @var string */ protected $feed_id; /** * Class constructor */ protected function __construct() { $this->is_forced_timeout = (bool) WPZOOM_Instagram_Widget_Settings::get_feed_setting_value( get_the_ID(), 'enable-request-timeout' ); $this->request_timeout_value = 15; if ( $this->is_forced_timeout && ! empty( $this->request_timeout_value ) ) { $this->headers['timeout'] = $this->request_timeout_value; } $this->image_uploader = WPZOOM_Instagram_Image_Uploader::getInstance(); $this->errors = new WP_Error(); } public function init() { add_action( 'init', array( $this, 'set_schedule' ) ); add_action( 'wpzoom_instagram_widget_cron_hook', array( $this, 'execute_cron' ) ); add_filter( 'cron_schedules', array( $this, 'add_cron_interval' ) ); } /** * Returns the *Singleton* instance of this class. * * @return Wpzoom_Instagram_Widget_API The *Singleton* instance. */ public static function getInstance() { if ( null === self::$instance ) { self::$instance = new self(); self::$instance->init(); } return self::$instance; } /** * Manually set the access token. * * @since 2.0.0 * * @param string $token The access token to set. * @return void */ public function set_access_token( $token ) { $this->access_token = $token; } /** * Manually set the access token. * * @since 2.0.0 * * @param string $token The access token to set. * @return void */ public function set_feed_id( $id ) { $this->feed_id = $id; } /** * Fetches a remote URL either safely or not, depending on a setting. * * @since 2.0.6 * * @param string $url URL to retrieve. * @param array $args Optional. Request arguments. Default empty array. * @return array|WP_Error The response or WP_Error on failure. */ public static function remote_get( $url, $args = array() ) { $settings = get_option( 'wpzoom-instagram-general-settings' ); $enable_unsafe_requests = ! empty( $settings['enable-unsafe-requests'] ) ? wp_validate_boolean( $settings['enable-unsafe-requests'] ) : false; return $enable_unsafe_requests ? wp_remote_get( $url, $args ) : wp_safe_remote_get( $url, $args ); } /** * Register custom cron intervals * * @since 1.8.0 * * @param array $schedules Registered schedules array. * @return array */ public function add_cron_interval( $schedules ) { $schedules['before_access_token_expires'] = array( 'interval' => 5097600, // 59 days. 'display' => esc_attr__( 'Before Access Token Expires', 'instagram-widget-by-wpzoom' ), ); return $schedules; } /** * Register schedule event * * @return void */ public function set_schedule() { if ( ! wp_next_scheduled( 'wpzoom_instagram_widget_cron_hook' ) ) { wp_schedule_event( time(), 'before_access_token_expires', 'wpzoom_instagram_widget_cron_hook' ); } } /** * Execute cron event * * @return boolean */ public function execute_cron() { $all_users = get_posts( array( 'numberposts' => -1, 'post_type' => 'wpz-insta_user', ) ); if ( ! empty( $all_users ) && is_array( $all_users ) ) { foreach ( $all_users as $user ) { if ( $user instanceof WP_Post ) { $user_name = get_the_title( $user ); $user_display = sprintf( '@%s', $user_name ); $token = get_post_meta( $user->ID, '_wpz-insta_token', true ); if ( false !== $token && ! empty( $token ) ) { $request_url = add_query_arg( array( 'grant_type' => 'ig_refresh_token', 'access_token' => $token, ), 'https://graph.instagram.com/refresh_access_token' ); $response = self::remote_get( $request_url, $this->headers ); $response_code = wp_remote_retrieve_response_code( $response ); if ( ! is_wp_error( $response ) ) { $body = wp_remote_retrieve_body( $response ); $data = json_decode( $body ); } if ( 200 === $response_code ) { $date_format = get_option( 'date_format' ); $time_format = get_option( 'time_format' ); $notice_status = 'success'; $notice_message = sprintf( __( 'WPZOOM Instagram Widget: The Instagram Access Token was refreshed automatically on %1$s at %2$s for the account %3$s.', 'instagram-widget-by-wpzoom' ), date( $date_format ), date( $time_format ), esc_html( $user_display ) ); update_post_meta( $user->ID, '_wpz-insta_token', $data->access_token ); update_post_meta( $user->ID, '_wpz-insta_token_expire', strtotime( '+60 days' ) ); } else { if ( ! isset( $data->error ) ) { error_log( __( 'Something wrong! Doesn\'t isset $data->error.', 'instagram-widget-by-wpzoom' ) ); return false; } else { error_log( $data->error->error_user_msg ); } $notice_status = 'error'; $notice_message = ''; $settings_url = admin_url( 'edit.php?post_type=wpz-insta_user' ); if ( 190 === $data->error->code ) { // Error validating access token: Session has expired. $notice_message = wp_kses_post( __( 'WPZOOM Instagram Widget: ', 'instagram-widget-by-wpzoom' ) ) . $data->error->message; } elseif ( 10 === $data->error->code && ! self::is_access_token_valid( $token ) ) { // Application does not have permission for this action. // User need to generate new Access Token manually. $notice_message = sprintf( __( 'WPZOOM Instagram Widget: The Access Token for the account %1$s has expired!
', 'instagram-widget-by-wpzoom' ), $user_display ); $notice_message .= sprintf( __( 'We cannot update access tokens automatically for Instagram private accounts. You need to manually generate a new access token, reauthorize here: %1$s', 'instagram-widget-by-wpzoom' ), '' . __( 'Instagram Widget Settings', 'instagram-widget-by-wpzoom' ) . '' ); } } update_option( '_wpz-insta_cron-result', array( $user->ID => array( 'status' => $notice_status, 'message' => $notice_message ) ) + (array) get_option( '_wpz-insta_cron-result', array() ) ); } } } } } public static function reset_cache( $sanitized_data ) { delete_transient( 'zoom_instagram_is_configured' ); delete_transient( 'zoom_instagram_user_info' ); // Remove schedule hook `wpzoom_instagram_widget_cron_hook`. if ( empty( $sanitized_data['basic-access-token'] ) ) { wp_clear_scheduled_hook( 'wpzoom_instagram_widget_cron_hook' ); } } /** * @param $screen_name string Instagram username * @param $image_limit int Number of images to retrieve * @param $image_width int Desired image width to retrieve * * @return array|bool Array of tweets or false if method fails */ public function get_items( $instance ) { $sliced = wp_array_slice_assoc( $instance, array( 'image-limit', 'image-width', 'image-resolution', 'username', 'disable-video-thumbs', 'include-pagination', 'bypass-transient', ) ); $image_limit = $sliced['image-limit']; $image_width = $sliced['image-width']; $image_resolution = ! empty( $sliced['image-resolution'] ) ? $sliced['image-resolution'] : 'low_resolution'; $injected_username = ! empty( $sliced['username'] ) ? $sliced['username'] : ''; $disable_video_thumbs = ! empty( $sliced['disable-video-thumbs'] ); $include_pagination = ! empty( $sliced['include-pagination'] ); $bypass_transient = ! empty( $sliced['bypass-transient'] ); if( isset( $instance['widget-id'] ) ) { $transient = 'zoom_instagram_is_configured_' . $instance['widget-id']; } else { $transient = 'zoom_instagram_is_configured'; } if ( ! empty( $this->access_token ) ) { $transient = $transient . '_' . substr( $this->access_token, 0, 20 ); } $injected_username = trim( $injected_username ); if ( ! $bypass_transient ) { $data = json_decode( get_transient( $transient ) ); if ( false !== $data && is_object( $data ) && ! empty( $data->data ) ) { return self::processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs, $include_pagination ); } } if ( ! empty( $this->access_token ) ) { $request_url = add_query_arg( array( 'fields' => 'media_url,media_type,caption,username,permalink,thumbnail_url,timestamp,children{media_url,media_type,thumbnail_url}', 'access_token' => $this->access_token, 'limit' => $image_limit, ), 'https://graph.instagram.com/me/media' ); $response = self::remote_get( $request_url, $this->headers ); if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) { if ( ! $bypass_transient ) { set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS ); } $error_data = $this->get_error( 'items-with-token-invalid-response' ); $this->errors->add( $error_data['code'], $error_data['message'] ); return false; } $raw_data = json_decode( wp_remote_retrieve_body( $response ) ); $data = self::convert_items_to_old_structure( $raw_data, $bypass_transient ); if ( $include_pagination && property_exists( $raw_data, 'paging' ) ) { $data->paging = $raw_data->paging; } } if ( ! empty( $data->data ) ) { if ( ! $bypass_transient ) { set_transient( $transient, wp_json_encode( $data ), $this->get_transient_lifetime( $this->feed_id ) ); } } else { if ( ! $bypass_transient ) { set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS ); } $error_data = $this->get_error( 'items-with-token-invalid-data-structure' ); $this->errors->add( $error_data['code'], $error_data['message'] ); return false; } return self::processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs, $include_pagination ); } public static function processing_response_data( $data, $image_width, $image_resolution, $image_limit, $disable_video_thumbs = false, $include_pagination = false ) { $result = array(); $username = ''; $defaults = array( 'link' => '', 'image-url' => '', 'original-image-url' => '', 'type' => '', 'timestamp' => '', 'children' => '', 'image-id' => '', 'image-caption' => '', 'likes_count' => 0, 'comments_count' => 0, ); if ( empty( $image_resolution ) ) { $image_resolution = 'low_resolution'; } foreach ( $data->data as $key => $item ) { $item = (object) wp_parse_args( $item, $defaults ); if ( empty( $username ) ) { $username = $item->user->username; } if ( $key === $image_limit ) { break; } if ( ! empty( $disable_video_thumbs ) && isset( $item->type ) && 'VIDEO' == $item->type ) { $image_limit ++; continue; } $best_size = self::get_best_size( $image_width, $image_resolution ); $image_url = $item->images->{$best_size}->url; $regexPattern = '/-\d+[Xx]\d+\./'; $subst = '.'; $local_image_url = preg_replace( $regexPattern, $subst, $image_url, 1 ); $result[] = array( 'link' => $item->link, 'image-url' => $image_url, 'local-image-url' => $local_image_url, 'original-image-url' => property_exists( $item, 'media_url' ) && ! empty( $item->media_url ) ? $item->media_url : '', 'type' => $item->type, 'timestamp' => property_exists( $item, 'timestamp' ) && ! empty( $item->timestamp ) ? $item->timestamp : '', 'children' => property_exists( $item, 'children' ) && ! empty( $item->children ) ? $item->children : '', 'image-id' => ! empty( $item->id ) ? esc_attr( $item->id ) : '', 'image-caption' => ! empty( $item->caption->text ) ? esc_attr( $item->caption->text ) : '', 'likes_count' => ! empty( $item->likes->count ) ? esc_attr( $item->likes->count ) : 0, 'comments_count' => ! empty( $item->comments->count ) ? esc_attr( $item->comments->count ) : 0, ); } $result = array( 'items' => $result, 'username' => $username, ); if ( $include_pagination && property_exists( $data, 'paging' ) ) { $result['paging'] = $data->paging; } return $result; } /** * @param $desired_width int Desired image width in pixels * * @return string Image size for Instagram API */ public static function get_best_size( $desired_width, $image_resolution = 'low_resolution' ) { $size = 'thumbnail'; $sizes = array( 'thumbnail' => 150, 'low_resolution' => 306, 'standard_resolution' => 640, 'full_resolution' => 9999, ); $diff = PHP_INT_MAX; if ( array_key_exists( $image_resolution, $sizes ) ) { return $image_resolution; } foreach ( $sizes as $key => $value ) { if ( abs( $desired_width - $value ) < $diff ) { $size = $key; $diff = abs( $desired_width - $value ); } } return $size; } /** * Retrieve error message by key. * * @param $key * * @return bool|mixed */ public function get_error( $key ) { $errors = $this->get_errors(); return array_key_exists( $key, $errors ) ? $errors[ $key ] : false; } /** * Get error messages collection. * * @return array */ public function get_errors() { return array( 'user-info-without-token' => array( 'code' => 'user-info-without-token', 'message' => esc_html__( 'Empty json user info from Public Feed.', 'instagram-widget-by-wpzoom' ), ), 'response-data-without-token-from-json-invalid-response' => array( 'code' => 'response-data-without-token-from-json-invalid-response', 'message' => esc_html__( 'The request from the Public Feed failed. Invalid server response from Public JSON API url.', 'instagram-widget-by-wpzoom' ), ), 'response-data-without-token-from-json-invalid-json-format' => array( 'code' => 'response-data-without-token-from-json-invalid-json-format', 'message' => esc_html__( 'The request from the Public Feed failed. Invalid JSON format from Public JSON API url.', 'instagram-widget-by-wpzoom' ), ), 'response-data-without-token-from-html-invalid-response' => array( 'code' => 'response-data-without-token-from-html-invalid-response', 'message' => esc_html__( 'The request from the Public Feed failed. Check username.', 'instagram-widget-by-wpzoom' ), ), 'response-data-without-token-from-html-invalid-json-format' => array( 'code' => 'response-data-without-token-from-html-invalid-json-format', 'message' => esc_html__( 'The request from the Public Feed failed. Invalid JSON format from parsed html body.', 'instagram-widget-by-wpzoom' ), ), 'items-without-token-invalid-response' => array( 'code' => 'items-without-token-invalid-response', 'message' => esc_html__( 'Get items from the Public Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ), ), 'items-without-token-invalid-json-structure' => array( 'code' => 'items-without-token-invalid-json-structure', 'message' => esc_html__( 'Get items from the Public Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ), ), 'items-with-token-invalid-response' => array( 'code' => 'items-with-token-invalid-response', 'message' => esc_html__( 'Geting items from the Instagram API Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ), ), 'items-with-token-invalid-data-structure' => array( 'code' => 'items-with-token-invalid-data-structure', 'message' => esc_html__( 'Get items from the Instagram API Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ), ), 'user-with-token-invalid-response' => array( 'code' => 'user-with-token-invalid-response', 'message' => esc_html__( 'Get user data from the Instagram API Feed failed. Invalid response.', 'instagram-widget-by-wpzoom' ), ), 'user-with-token-invalid-data-structure' => array( 'code' => 'user-with-token-invalid-data-structure', 'message' => esc_html__( 'Get user data from the Instagram API Feed failed. Malformed data structure.', 'instagram-widget-by-wpzoom' ), ), ); } public static function convert_items_to_old_structure( $data, $preview = false ) { $converted = new stdClass(); $converted->data = array(); $image_uploader = WPZOOM_Instagram_Image_Uploader::getInstance(); foreach ( $data->data as $key => $item ) { $is_video = property_exists( $item, 'media_type' ) && 'VIDEO' === $item->media_type; $media_url = $is_video && property_exists( $item, 'thumbnail_url' ) && ! empty( $item->thumbnail_url ) ? $item->thumbnail_url : $item->media_url; $converted->data[] = (object) array( 'id' => $item->id, 'media_url' => ( $is_video ? $item->media_url : $media_url ), 'user' => (object) array( 'id' => null, 'fullname' => null, 'profile_picture' => null, 'username' => $item->username, ), 'images' => (object) array( 'thumbnail' => (object) array( 'url' => $preview ? $media_url : $image_uploader->get_image( 'thumbnail', $media_url, $item->id ), 'width' => 150, 'height' => 150, ), 'low_resolution' => (object) array( 'url' => $preview ? $media_url : $image_uploader->get_image( 'low_resolution', $media_url, $item->id ), 'width' => 320, 'height' => 320, ), 'standard_resolution' => (object) array( 'url' => $preview ? $media_url : $image_uploader->get_image( 'standard_resolution', $media_url, $item->id ), 'width' => 640, 'height' => 640, ), 'full_resolution' => (object) array( 'url' => $preview ? $media_url : $image_uploader->get_image( 'full_resolution', $media_url, $item->id ), 'width' => 9999, 'height' => 9999, ), ), 'type' => $item->media_type, 'likes' => null, 'comments' => null, 'created_time' => null, 'timestamp' => $item->timestamp, 'children' => ( isset( $item->children ) ? $item->children : null ), 'link' => $item->permalink, 'caption' => (object) array( 'text' => isset( $item->caption ) ? $item->caption : '', ), ); } return $converted; } function get_transient_lifetime( $id ) { $feed_id = isset( $id ) ? $id : 0; $interval = (int) WPZOOM_Instagram_Widget_Settings::get_feed_setting_value( $feed_id, 'check-new-posts-interval-number' ); $interval_suffix = (int) WPZOOM_Instagram_Widget_Settings::get_feed_setting_value( $feed_id, 'check-new-posts-interval-suffix' ); $values = array( MINUTE_IN_SECONDS, HOUR_IN_SECONDS, DAY_IN_SECONDS, WEEK_IN_SECONDS, MONTH_IN_SECONDS, ); $keys = array_keys( $values ); $type = in_array( $interval_suffix, $keys ) ? $values[ $interval_suffix ] : $values[2]; return intval( $type * $interval ) ; } public function get_user_info( $injected_username = '' ) { $transient = 'zoom_instagram_user_info'; $injected_username = rtrim( $injected_username ); if ( false !== ( $data = json_decode( get_transient( $transient ) ) ) && is_object( $data ) && ! empty( $data->data ) ) { return $data; } if ( ! empty( $this->access_token ) ) { $request_url = add_query_arg( array( 'access_token' => $this->access_token, 'fields' => 'account_type,id,media_count,username', ), 'https://graph.instagram.com/me' ); $response = self::remote_get( $request_url, $this->headers ); if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) ) { set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS ); $error_data = $this->get_error( 'user-with-token-invalid-response' ); $this->errors->add( $error_data['code'], $error_data['message'] ); return false; } $data = json_decode( wp_remote_retrieve_body( $response ) ); $data = $this->convert_user_info_to_old_structure( $data ); } if ( ! empty( $data->data ) ) { set_transient( $transient, wp_json_encode( $data ), $this->get_transient_lifetime( $this->feed_id ) ); } else { set_transient( $transient, wp_json_encode( false ), MINUTE_IN_SECONDS ); $error_data = $this->get_error( 'user-with-token-invalid-data-structure' ); $this->errors->add( $error_data['code'], $error_data['message'] ); return false; } return $data; } public static function get_basic_user_info_from_token( $access_token ) { $output = false; if ( ! empty( $access_token ) ) { $request_url = add_query_arg( array( 'access_token' => $access_token, 'fields' => 'account_type,username', ), 'https://graph.instagram.com/me' ); $response = self::remote_get( $request_url ); if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) { $output = json_decode( wp_remote_retrieve_body( $response ) ); } } return $output; } function convert_user_info_to_old_structure( $user_info ) { $converted = new stdClass(); $user_info_from_settings = WPZOOM_Instagram_Widget_Settings::get_instance()->get_settings(); $avatar = property_exists( $user_info, 'profile_picture' ) ? $user_info->profile_picture : null; if ( ! empty( $user_info_from_settings['user-info-avatar'] ) ) { $img_src = wp_get_attachment_image_src( $user_info_from_settings['user-info-avatar'] ); if ( ! empty( $img_src ) && is_array( $img_src ) ) { $avatar = $img_src[0]; } } $fullname = ! empty( $user_info->username ) ? $user_info->username : null; if ( ! empty( $user_info_from_settings['user-info-fullname'] ) ) { $fullname = $user_info_from_settings['user-info-fullname']; } $converted->data = (object) array( 'bio' => ! empty( $user_info_from_settings['user-info-biography'] ) ? $user_info_from_settings['user-info-biography'] : null, 'counts' => (object) array( 'followed_by' => null, 'follows' => null, 'media' => null, ), 'full_name' => $fullname, 'id' => ! empty( $user_info->id ) ? $user_info->id : '', 'is_business' => null, 'profile_picture' => $avatar, 'username' => ! empty( $user_info->username ) ? $user_info->username : '', 'website' => null, ); return $converted; } public function is_configured() { $transient = 'zoom_instagram_is_configured'; if ( false !== ( $result = json_decode( get_transient( $transient ) ) ) ) { if ( 'yes' === $result ) { return true; } if ( 'no' === $result ) { return false; } if ( ! empty( $result ) ) { return true; } } $condition = $this->is_access_token_valid( $this->access_token ); if ( true === $condition ) { set_transient( $transient, wp_json_encode( 'yes' ), DAY_IN_SECONDS ); return true; } set_transient( $transient, wp_json_encode( 'no' ), DAY_IN_SECONDS ); return false; } /** * Check if given access token is valid for Instagram Api. */ public static function is_access_token_valid( $access_token ) { if ( empty( $access_token ) ) { return false; } $request_url = add_query_arg( array( 'fields' => 'username', 'access_token' => $access_token, ), 'https://graph.instagram.com/me' ); $response = self::remote_get( $request_url ); if ( is_wp_error( $response ) ) { return $response; } if ( 200 != wp_remote_retrieve_response_code( $response ) ) { return false; } return true; } } Wpzoom_Instagram_Widget_API::getInstance(); /** * * Enqueue CSS/JS of the plugin. * * @since 2.0.2 * @package WPZOOM_Instagram_Widget */ // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; } if ( ! class_exists( 'WPZOOM_Instagram_Widget_Assets ' ) ) { /** * Main WPZOOM_Instagram_Widget_Assets Class. * * @since 2.0.2 */ class WPZOOM_Instagram_Widget_Assets { /** * This plugin's instance. * * @var WPZOOM_Instagram_Widget_Assets * @since 2.0.2 */ private static $instance; /** * Provides singleton instance. * * @since 2.0.2 * @return self instance */ public static function instance() { if ( null === self::$instance ) { self::$instance = new WPZOOM_Instagram_Widget_Assets(); } return self::$instance; } /** * The base directory path. * * @var string $_dir */ private $_dir; /** * The base URL path. * * @var string $_url */ private $_url; /** * The Constructor. */ public function __construct() { add_action( 'enqueue_block_assets', array( $this, 'frontend_register_scripts' ), 5 ); add_action( 'enqueue_block_assets', array( $this, 'widget_styles' ), 5 ); add_action( 'enqueue_block_editor_assets', array( $this, 'register_block_assets' ) ); add_action( 'enqueue_block_editor_assets', array( $this, 'widget_styles' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'widget_styles' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'register_widget_scripts' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_widget_scripts' ) ); /** * Enqueue styles and scripts for SiteOrigin Page Builder. */ add_action( 'siteorigin_panel_enqueue_admin_scripts', array( $this, 'widget_styles' ) ); add_action( 'siteorigin_panel_enqueue_admin_scripts', array( $this, 'register_widget_scripts' ) ); add_action( 'siteorigin_panel_enqueue_admin_scripts', array( $this, 'enqueue_widget_scripts' ) ); } public function frontend_register_scripts() { global $post; $general_options = get_option( 'wpzoom-instagram-general-settings' ); $should_enqueue = has_block( 'wpzoom/instagram-block' ); $has_reusable_block = self::has_reusable_block( 'wpzoom/instagram-block' ); $is_active_widget = is_active_widget( false, false, 'wpzoom_instagram_widget', false ); $has_shortcode = ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'instagram' ) ); $has_widget_block = self::is_active_block_widget( 'wpzoom/instagram-block' ); $load_css_js = isset( $general_options['load-css-js'] ) ? true : false; $script_asset_file = include( plugin_dir_path( __FILE__ ) . 'dist/scripts/backend/block.asset.php' ); $style_asset_file = include( plugin_dir_path( __FILE__ ) . 'dist/styles/frontend/index.asset.php' ); if( is_admin() || $load_css_js || $should_enqueue || $has_reusable_block || $is_active_widget || $has_shortcode || $has_widget_block || isset( $_GET['wpz-insta-widget-preview'] ) ) { wp_register_script( 'magnific-popup', plugins_url( 'dist/scripts/library/magnific-popup.js', __FILE__ ), array( 'jquery', 'underscore', 'wp-util' ), filemtime( plugin_dir_path( __FILE__ ) . 'dist/scripts/library/magnific-popup.js' ), true ); wp_register_script( 'swiper-js', plugins_url( 'dist/scripts/library/swiper.js', __FILE__ ), array(), '7.4.1' ); wp_register_script( 'wpz-insta_block-frontend-script', plugins_url( 'dist/scripts/frontend/block.js', __FILE__ ), array( 'jquery', 'underscore', 'magnific-popup', 'swiper-js' ), $script_asset_file['version'] ); wp_register_style( 'magnific-popup', plugins_url( 'dist/styles/library/magnific-popup.css', __FILE__ ), array( 'dashicons' ), WPZOOM_INSTAGRAM_VERSION ); wp_register_style( 'wpz-insta_block-frontend-style', plugins_url( 'dist/styles/frontend/index.css', __FILE__ ), array( 'magnific-popup', 'swiper-css' ), $style_asset_file['version'] ); } } public function register_block_assets() { $script_asset_file = include( plugin_dir_path( __FILE__ ) . 'dist/scripts/backend/block.asset.php' ); $style_asset_file = include( plugin_dir_path( __FILE__ ) . 'dist/styles/frontend/index.asset.php' ); wp_register_script( 'wpz-insta_block-backend-script', plugins_url( 'dist/scripts/backend/block.js', __FILE__ ), $script_asset_file['dependencies'], $script_asset_file['version'] ); } /** * Load widget specific styles. */ public function widget_styles() { global $post; $general_options = get_option( 'wpzoom-instagram-general-settings' ); $should_enqueue = has_block( 'wpzoom/instagram-block' ); $has_reusable_block = self::has_reusable_block( 'wpzoom/instagram-block' ); $is_active_widget = is_active_widget( false, false, 'wpzoom_instagram_widget', false ); $has_shortcode = ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'instagram' ) ); $has_widget_block = self::is_active_block_widget( 'wpzoom/instagram-block' ); $load_css_js = isset( $general_options['load-css-js'] ) ? true : false; if( is_admin() || $load_css_js || $should_enqueue || $has_reusable_block || $is_active_widget || $has_shortcode || $has_widget_block || isset( $_GET['wpz-insta-widget-preview'] ) ) { wp_enqueue_style( 'swiper-css', plugin_dir_url( __FILE__ ) . 'dist/styles/library/swiper.css', array(), '7.4.1' ); wp_enqueue_style( 'wpz-insta_block-frontend-style', plugin_dir_url( __FILE__ ) . 'dist/styles/frontend/index.css', array( 'dashicons' ), WPZOOM_INSTAGRAM_VERSION ); wp_enqueue_style( 'magnific-popup', plugin_dir_url( __FILE__ ) . 'dist/styles/library/magnific-popup.css', array( 'dashicons' ), WPZOOM_INSTAGRAM_VERSION ); } } /** * Register widget specific scripts. */ public function register_widget_scripts() { wp_register_script( 'zoom-instagram-widget-lazy-load', plugin_dir_url( __FILE__ ) . 'dist/scripts/library/lazy.js', array( 'jquery' ), filemtime( plugin_dir_path( __FILE__ ) . 'dist/scripts/library/lazy.js' ), true ); wp_register_script( 'magnific-popup', plugin_dir_url( __FILE__ ) . 'dist/scripts/library/magnific-popup.js', array( 'jquery', 'underscore', 'wp-util' ), filemtime( plugin_dir_path( __FILE__ ) . 'dist/scripts/library/magnific-popup.js' ), true ); wp_register_script( 'swiper-js', plugin_dir_url( __FILE__ ) . 'dist/scripts/library/swiper.js', array(), '7.0.0-alpha.21', true ); wp_register_script( 'zoom-instagram-widget', plugin_dir_url( __FILE__ ) . 'dist/scripts/frontend/index.js', array( 'jquery', 'underscore', 'wp-util', 'magnific-popup', 'swiper-js' ), WPZOOM_INSTAGRAM_VERSION, true ); } /** * Load widget specific scripts. */ public function enqueue_widget_scripts() { global $post; $general_options = get_option( 'wpzoom-instagram-general-settings' ); $should_enqueue = has_block( 'wpzoom/instagram-block' ); $has_reusable_block = self::has_reusable_block( 'wpzoom/instagram-block' ); $is_active_widget = is_active_widget( false, false, 'wpzoom_instagram_widget', false ); $has_shortcode = ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'instagram' ) ); $has_widget_block = self::is_active_block_widget( 'wpzoom/instagram-block' ); $load_css_js = isset( $general_options['load-css-js'] ) ? true : false; if( is_admin() || $load_css_js || $should_enqueue || $has_reusable_block || $is_active_widget || $has_shortcode || $has_widget_block || isset( $_GET['wpz-insta-widget-preview'] ) ) { wp_enqueue_script( 'zoom-instagram-widget-lazy-load' ); wp_enqueue_script( 'magnific-popup' ); wp_enqueue_script( 'swiper-js' ); wp_enqueue_script( 'zoom-instagram-widget' ); wp_enqueue_script( 'wpz-insta_block-frontend-script' ); } } /** * Check the widget block based area has the block * * @since 2.0.2 * @param string $block_name The block name. * @return boolean Return true if post content has provided block name as reusable block, else return false. */ public static function is_active_block_widget( $blockname ) { $allwidgets = []; $widget_blocks = get_option( 'widget_block' ); $sidebars_widgets = get_option('sidebars_widgets'); if( is_array( $sidebars_widgets ) ) { foreach ( $sidebars_widgets as $key => $value ) { if( is_array( $value ) ) { foreach ($value as $widget_id) { $pieces = explode( '-', $widget_id ); $multi_number = array_pop( $pieces ); $id_base = implode( '-', $pieces ); $widget_data = get_option( 'widget_' . $id_base ); // Remove inactive widgets if( $key != 'wp_inactive_widgets' ) { unset( $widget_data['_multiwidget'] ); $allwidgets[ $key ] = $widget_data; } } } } } foreach( (array) $allwidgets as $widget ) { foreach( (array) $widget as $widget_element ) { foreach( (array)$widget_element as $value ) { if( is_string( $value ) && has_shortcode( $value, 'instagram' ) ) { return true; } } } } foreach( (array) $widget_blocks as $widget_block ) { if ( ! empty( $widget_block['content'] ) && ( has_block( $blockname, $widget_block['content'] ) || has_shortcode( $widget_block['content'], 'instagram' ) ) ) { return true; } } return false; } /** * Check the post content has reusable block * * @since 2.0.2 * @param string $block_name The block name. * @param int $post_id The post ID. * @param int $reusable_block_id The reusable block post ID. * @param boolean|int $content The post content. * @return boolean Return true if post content has provided block name as reusable block, else return false. */ public static function has_reusable_block( $block_name, $post_id = 0, $reusable_block_id = 0, $content = '' ) { $has_reusable_block = false; $post_id = $post_id > 0 ? $post_id : get_the_ID(); /** * Loop reusable blocks to get needed block * * @since 2.0.2 */ if ( ! empty( self::get_reusable_block( absint( $reusable_block_id ) ) ) ) { $args = array( 'post_type' => 'wp_block', 'posts_per_page' => -1, 'post_status' => 'publish', ); $query = new WP_Query( $args ); while ( $query->have_posts() ) { $query->the_post(); if ( absint( $reusable_block_id ) === get_the_ID() ) { $content = get_post_field( 'post_content', get_the_ID() ); if ( has_block( $block_name, $content ) ) { $has_reusable_block = true; return $has_reusable_block; } } } // Reset global post variable. After this point, we are back to the Main Query object. wp_reset_postdata(); } // Early return if $has_reusable_block is true. if ( true === $has_reusable_block ) { return; } if ( empty( $content ) ) { $content = get_post_field( 'post_content', $post_id ); } if ( $content ) { if ( has_block( 'block', $content ) ) { // Check reusable blocks. $blocks = parse_blocks( $content ); if ( ! is_array( $blocks ) || empty( $blocks ) ) { return false; } foreach ( $blocks as $block ) { if ( $block['blockName'] === 'core/block' && ! empty( $block['attrs']['ref'] ) ) { $reusable_block_id = absint( $block['attrs']['ref'] ); if ( has_block( $block_name, $reusable_block_id ) ) { return true; } elseif ( ! empty( self::get_reusable_block( $reusable_block_id ) ) ) { return true; } } } } elseif ( has_block( $block_name, $content ) ) { return true; } elseif ( has_shortcode( $content, 'reblex' ) ) { return true; } else { return false; } } return false; } /** * Get reusable block. * * @since 2.0.2 * @param int $id Reusable block id. * @return string Reusable block post content. */ public static function get_reusable_block( $id ) { $post = ''; if ( ! is_string( $id ) && $id > 0 ) { $wp_post = get_post( $id ); if ( $wp_post instanceof WP_Post ) { $post = $wp_post->post_content; } } return $post; } } } WPZOOM_Instagram_Widget_Assets::instance(); /** * WPZOOM Portfolio * * @package WPZOOM_Portfolio * @author WPZOOM * @copyright 2022 WPZOOM * @license GPL-2.0-or-later * * @wordpress-plugin * Plugin Name: WPZOOM Portfolio * Plugin URI: https://www.wpzoom.com/plugins/wpzoom-portfolio/ * Description: The ultimate solution for creatives, designers, photographers, and businesses looking to showcase their work in an elegant, professional, and fully customizable way. * Author: WPZOOM * Author URI: https://www.wpzoom.com * Text Domain: wpzoom-portfolio * Version: 1.4.2 * License: GPL2+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt */ // Exit if accessed directly defined( 'ABSPATH' ) || exit; if ( ! defined( 'WPZOOM_PORTFOLIO_VERSION' ) ) { define( 'WPZOOM_PORTFOLIO_VERSION', get_file_data( __FILE__, [ 'Version' ] )[0] ); // phpcs:ignore } // settings page url attribute define( 'WPZOOM_PORTFOLIO_SETTINGS_PAGE', 'wpzoom-portfolio-settings' ); define( 'WPZOOM_PORTFOLIO__FILE__', __FILE__ ); define( 'WPZOOM_PORTFOLIO_PLUGIN_BASE', plugin_basename( WPZOOM_PORTFOLIO__FILE__ ) ); define( 'WPZOOM_PORTFOLIO_PLUGIN_DIR', dirname( WPZOOM_PORTFOLIO_PLUGIN_BASE ) ); define( 'WPZOOM_PORTFOLIO_PATH', plugin_dir_path( WPZOOM_PORTFOLIO__FILE__ ) ); define( 'WPZOOM_PORTFOLIO_URL', plugin_dir_url( WPZOOM_PORTFOLIO__FILE__ ) ); // Instance the plugin $wpzoom_blocks = new WPZOOM_Blocks(); // Register plugin activation hook register_activation_hook( __FILE__, array( $wpzoom_blocks, 'activate' ) ); // Hook the plugin into WordPress add_action( 'init', array( $wpzoom_blocks, 'init' ) ); /** * Class WPZOOM_Blocks * * Main container class of the WPZOOM Blocks WordPress plugin. * * @since 1.0.0 */ class WPZOOM_Blocks { /** * Whether the plugin has been initialized. * * @var boolean * @access public * @since 1.0.0 */ public $initialized = false; /** * The path to this plugin's root directory. * * @var string * @access public * @since 1.0.0 */ public $plugin_dir_path; /** * The URL to this plugin's root directory. * * @var string * @access public * @since 1.0.0 */ public $plugin_dir_url; /** * The path to this plugin's "main" directory. * * @var string * @access public * @since 1.0.0 */ public $main_dir_path; /** * The URL to this plugin's "main" directory. * * @var string * @access public * @since 1.0.0 */ public $main_dir_url; /** * The path to this plugin's "blocks" directory. * * @var string * @access public * @since 1.0.0 */ public $blocks_dir_path; /** * The URL to this plugin's "blocks" directory. * * @var string * @access public * @since 1.0.0 */ public $blocks_dir_url; /** * Initializes the plugin and sets up needed hooks and features. * * @access public * @return void * @since 1.0.0 * @see WPZOOM_Blocks::load_assets() */ public function init() { // If the plugin has not already been initialized... if ( false === $this->initialized ) { // Assign the values for the plugins 'root' dir/url $this->plugin_dir_path = plugin_dir_path( __FILE__ ); $this->plugin_dir_url = plugin_dir_url( __FILE__ ); // Assign the values for the plugins 'main' dir/url $this->main_dir_path = trailingslashit( $this->plugin_dir_path . 'build' ); $this->main_dir_url = trailingslashit( $this->plugin_dir_url . 'build' ); // Assign the values for the plugins 'blocks' dir/url $this->blocks_dir_path = trailingslashit( $this->main_dir_path . 'blocks' ); $this->blocks_dir_url = trailingslashit( $this->main_dir_url . 'blocks' ); // Load the correct translation files for the plugin load_plugin_textdomain( 'wpzoom-portfolio', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); // Filter the Gutenberg block categories to add our custom 'WPZOOM Blocks' category if needed add_filter( 'block_categories_all', array( $this, 'filter_block_categories' ), 10, 2 ); // Load in all needed assets for the plugin $this->load_assets(); // Enqueue the main/root scripts and styles in the Gutenberg editor add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_portfolio_block_editor_assets' ) ); add_action( 'enqueue_block_assets', array( $this, 'enqueue_portfolio_block_assets' ) ); // Hook into the REST API in order to add some custom things add_action( 'rest_api_init', array( $this, 'rest_api_routes' ) ); // Add some extra needed styles on the frontend add_action( 'wp_enqueue_scripts', function() { wp_enqueue_script( 'jquery' ); wp_enqueue_style( 'dashicons' ); } ); // Mark the plugin as initialized $this->initialized = true; } } /** * Runs once during the activation of the plugin to run some one-time setup functions. * * @access public * @return void * @since 1.0.0 */ public function enqueue_portfolio_block_editor_assets() { wp_enqueue_script( 'masonry' ); $options = get_option( 'wpzoom-portfolio-settings' ); wp_enqueue_script( 'wpzoom-blocks-js-index-main' ); wp_localize_script( 'wpzoom-blocks-js-index-main', 'wpzoomPortfolioBlock', array( 'setting_options' => ( !empty( $options ) ? $options : array() ) ) ); wp_enqueue_style( 'wpzoom-blocks-css-editor-main' ); } /** * Runs once during the activation of the plugin to run some one-time setup functions. * * @access public * @return void * @since 1.0.0 */ public function enqueue_portfolio_block_assets() { $should_enqueue = has_block( 'wpzoom-blocks/portfolio' ) || has_block( 'wpzoom-blocks/portfolio-layouts' ) || WPZOOM_Portfolio_Assets_Manager::has_wpzoom_portfolio_shortcode(); if( ! $should_enqueue ) { return; } wp_enqueue_script( 'masonry' ); wp_enqueue_script( 'wpzoom-blocks-js-script-main' ); wp_enqueue_style( 'wpzoom-blocks-css-style-main' ); } /** * Runs once during the activation of the plugin to run some one-time setup functions. * * @access public * @return void * @since 1.0.0 * @see WPZOOM_Blocks::init() */ public function activate() { // Make sure the plugin is initialized $this->init(); // Flush the rewrite rules so any custom post types work correctly flush_rewrite_rules(); } /** * Loads in all the needed assets for the plugin. * * @access public * @return void * @since 1.0.0 * @see register_block_type() */ public function load_assets() { // Set a fallback for files with no version/dependency info $no_asset = array( 'dependencies' => array( 'wp-blocks', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill' ), 'version' => '-1' ); // Go through the main directory and each sub-directory in the blocks directory... foreach ( array_merge( array( $this->main_dir_path ), glob( $this->blocks_dir_path . '*', GLOB_ONLYDIR | GLOB_NOSORT ) ) as $path ) { // Get the slug for the directory in the current iteration $slug = 0 === substr_compare( $path, 'build/', -strlen( 'build/' ) ) ? 'main' : str_replace( $this->blocks_dir_path, '', $path ); // Get a version of the slug with dashes replaced by underscores $slug_ = str_replace( '-', '_', $slug ); // Consistent slashing $path = trailingslashit( $path ); // Go through every possible script/style there could be in the directory from the current iteration... foreach ( array( 'index' => 'js', 'script' => 'js', 'editor' => 'css', 'style' => 'css' ) as $name => $ext ) { // If a script/style with the given name exists in the directory from the current iteration... if ( file_exists( "$path$name.$ext" ) ) { // Get the version/dependency info $asset_file = "$path$name.asset.php"; $asset = file_exists( $asset_file ) ? require_once( $asset_file ) : $no_asset; // Register the script/style so it can be enqueued later $func = 'js' == $ext ? 'wp_register_script' : 'wp_register_style'; $url = trailingslashit( 'main' == $slug_ ? $this->main_dir_url : $this->blocks_dir_url . $slug ) . "$name.$ext"; $depends = 'js' == $ext ? $asset[ 'dependencies' ] : array(); $func( "wpzoom-blocks-$ext-$name-$slug_", $url, $depends, $asset[ 'version' ], ( 'main' != $slug_ && 'js' == $ext ) ); // If the file in the current iteration is a script... if ( 'js' == $ext && function_exists( 'wp_set_script_translations' ) ) { // Setup the translations for it wp_set_script_translations( "wpzoom-blocks-js-$name-$slug_", 'wpzoom-portfolio', plugin_dir_path( __FILE__ ) . 'languages' ); } } } // If the file in the current iteration is in a block... if ( 'main' != $slug_ ) { // Include the index.php file if the block has one if ( file_exists( $path . 'index.php' ) ) { require_once( $path . 'index.php' ); } // Construct the arguments array $args = array( 'editor_script' => "wpzoom-blocks-js-index-$slug_", 'editor_style' => "wpzoom-blocks-css-editor-$slug_", 'script' => "wpzoom-blocks-js-script-$slug_", 'style' => "wpzoom-blocks-css-style-$slug_" ); // Construct the class name to use below $class_name = 'WPZOOM_Blocks_' . ucwords( $slug_, '_' ); // If a class with the given name exists... if ( class_exists( $class_name ) ) { // Instantiate the class $class = new $class_name(); // Add attributes if they have been declared in the class if ( property_exists( $class, 'attributes' ) ) { $args[ 'attributes' ] = $class->attributes; } // Add a render callback if one is specified in the class if ( method_exists( $class, 'render' ) ) { $args[ 'render_callback' ] = array( $class, 'render' ); } } // Register the block with Gutenberg using the given arguments register_block_type( "wpzoom-blocks/$slug", $args ); } } } /** * Adds the WPZOOM category to the Gutenberg block categories, if not already present. * * @access public * @param array $categories Array containing all registered Gutenberg block categories. * @param WP_Post $post A WP_Post object representing the post being loaded. * @return array * @since 1.0.0 */ public function filter_block_categories( $categories, $post ) { // Get a list of all the block category slugs $category_slugs = wp_list_pluck( $categories, 'slug' ); // Return the list of categories with our custom category included return in_array( 'wpzoom-blocks', $category_slugs, true ) ? $categories : array_merge( $categories, array( array( 'slug' => 'wpzoom-blocks', 'title' => esc_html__( 'WPZOOM - Blocks', 'wpzoom-portfolio' ) ) ) ); } /** * Adds extra needed routes in the WordPress REST API. * * @access public * @return void * @since 1.0.0 * @see register_rest_route() * @see register_rest_field() * @see WPZOOM_Blocks::get_rest_image_sizes() * @see WPZOOM_Blocks::get_featured_media_urls() */ public function rest_api_routes() { // Register the 'image-sizes' REST API route register_rest_route( 'wpzoom-blocks/v1', '/image-sizes', array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_rest_image_sizes' ), 'permission_callback' => function() { return current_user_can( 'edit_posts' ); } ) ); // Register the 'featured_media_urls' REST API field on all post types register_rest_field( get_post_types(), 'featured_media_urls', array( 'get_callback' => array( $this, 'get_featured_media_urls' ), 'update_callback' => null, 'schema' => array( 'description' => esc_html__( 'Different sized featured images', 'wpzoom-portfolio' ), 'type' => 'array' ) ) ); } /** * Returns a REST response containing all available media library image sizes. * * @access public * @return array * @since 1.0.0 * @see get_intermediate_image_sizes() */ public function get_rest_image_sizes() { // Call the built-in get_intermediate_image_sizes() WordPress function to get an array of sizes $raw_sizes = get_intermediate_image_sizes(); // Build an array with sizes and their labels $sizes = array(); foreach ( $raw_sizes as $raw_size ) { $sizes[] = array( 'label' => ucwords( preg_replace( '/[_-]/', ' ', $raw_size ) ), 'value' => $raw_size ); } // Return the sizes array properly formatted for a rest response return rest_ensure_response( $sizes ); } /** * Returns an array of all the available image size URLs for the featured media from the given post object. * * @access public * @param WP_Post|Object $object The object that is the context to get the featured media ID from. * @return array * @since 1.0.0 * @see get_intermediate_image_sizes() * @see wp_get_attachment_image_src() */ function get_featured_media_urls( $object ) { // Initialize the array that will be returned $featured_media_urls = array(); // If the given object has attached featured media... if ( isset( $object[ 'featured_media' ] ) ) { // Keep track of the featured media ID $featured_media_id = $object[ 'featured_media' ]; // Call wp_get_attachment_image_src() with the default options for the best chance to get a fallback $thumb = wp_get_attachment_image_src( $featured_media_id ); // If the size above was found... if ( is_array( $thumb ) ) { // Set it so it will be present as a fallback if no other sizes can be found $featured_media_urls[ 'thumbnail' ] = $thumb; } // Go through every available image size... foreach ( get_intermediate_image_sizes() as $size ) { // Get the featured media source attached to the given object in the size from the current iteration $src = wp_get_attachment_image_src( $featured_media_id, $size, false ); // If the size was found... if ( is_array( $src ) ) { // Add it to the array of size URLs $featured_media_urls[ $size ] = $src; } } } // Return the array return $featured_media_urls; } } function wpzoom_theme_has_portfolio() { $wpzoom_themes = array( 'angle', 'inspiro', 'wpzoom-inspiro-pro', 'wpzoom-reel', 'wpzoom-rezzo' ); $current_theme = get_option( 'stylesheet' ); if( ! in_array( $current_theme, $wpzoom_themes ) ) { return false; } else { if( 'inspiro' == $current_theme ) { $theme = wp_get_theme(); if( 'https://www.wpzoom.com/free-wordpress-themes/inspiro-lite/' == $theme->get( 'ThemeURI' ) ) { return false; } } } return true; } if( ! function_exists( 'wpzoom_portfolio_load_files' ) ) { function wpzoom_portfolio_load_files() { //Add Portfolio Shortcode require_once 'classes/class-wpzoom-portfolio-shortcode.php'; require_once 'classes/class-wpzoom-portfolio-admin-menu.php'; require_once 'classes/class-wpzoom-portfolio-custom-posts.php'; require_once 'classes/class-wpzoom-portfolio-assets-manager.php'; require_once 'classes/class-wpzoom-wptt-webfont-loader.php'; //Load Settings Panel require_once 'classes/class-wpzoom-settings-fields.php'; require_once 'classes/class-wpzoom-portfolio-settings-page.php'; if( ! wpzoom_theme_has_portfolio() ) { //Load Archive template require_once 'classes/class-wpzoom-portfolio-template.php'; } if( ! wpzoom_theme_has_portfolio() ) { //Load Archive template require_once 'classes/class-wpzoom-portfolio-template.php'; } if( ! class_exists( 'WPZOOM_Portfolio_Pro' ) && ! wpzoom_theme_has_portfolio() ) { require_once 'classes/class-wpzoom-portfolio-metaboxes-upsell.php'; } } add_action( 'plugin_loaded', 'wpzoom_portfolio_load_files' ); } function load_reorder_portfolio_items() { if( ! current_user_can( 'edit_posts' ) || current_theme_supports( 'zoom-portfolio' ) ) { return; } //Load Re-Order feature require_once 'classes/featured-posts/class-wpzoom-portfolio-featured-posts.php'; $wpzoom_portfrolio_reorder_settings = array( //Unique Id that is used to add the new column in posts list table. 'id' => 'wpzoom_is_featured_id', //Label that appears in the submenu of post types 'menu_title' => __( 'Re-order', 'wpzoom-portfolio' ), //Post type in which this feature will be added. 'post_type' => 'portfolio_item', ); $featured_posts_plugin_uri = WPZOOM_PORTFOLIO_URL . '/classes/featured-posts/'; $list_table_checkbox_directory_uri = WPZOOM_PORTFOLIO_URL . '/classes/featured-posts/list-table-checkbox'; new WPZOOM_Featured_Posts( $wpzoom_portfrolio_reorder_settings, $featured_posts_plugin_uri ); } add_action( 'init', 'load_reorder_portfolio_items' ); add_action( 'init', 'WPZOOM_Blocks_Portfolio_Shortcode::instance' );/** * Plugin Name: Video Popup Block by WPZOOM * Plugin URI: https://wordpress.org/plugins/wpzoom-video-popup-block/ * Description: Quickly add a button displaying a YouTube, Vimeo or Self-Hosted (MP4) video in a popup when clicked. * Version: 1.1.1 * Author: WPZOOM * Author URI: https://www.wpzoom.com/ * Text Domain: wpzoom-video-popup-block * Domain Path: /languages * License: GPLv2 or later * License URI: https://www.gnu.org/licenses/gpl-2.0.html * Requires at least: 6.0 * Requires PHP: 7.2 * Tested up to: 6.4 * * @package Wpzoom_Video_Popup_Block */ namespace WPZOOM\Video_Popup_Block; // Exit if accessed directly. defined( 'ABSPATH' ) || exit; // Intitalize the plugin. new Plugin(); /** * Main WPZOOM Video Popup Block class. * * The entry point into WordPress for this plugin. * * @since 1.0.0 */ class Plugin { /** * The version of this plugin. * * @since 1.0.0 * @var int */ public const VERSION = '1.1.1'; /** * Path to the plugin directory. * * @since 1.0.0 * @var string */ public $plugin_path; /** * URL to the plugin directory. * * @since 1.0.0 * @var string */ public $plugin_url; /** * Main directory name of the plugin. * * @since 1.0.0 * @var string */ public $plugin_dirname; /** * Main file name of the plugin. * * @since 1.0.0 * @var string */ public $plugin_filename; /** * The name of the block this plugin adds. * * @since 1.0.0 * @var string */ public $block_name; /** * Plugin class constructor. * * @since 1.0.0 * @return void */ public function __construct() { $this->plugin_path = plugin_dir_path( __FILE__ ); $this->plugin_url = plugin_dir_url( __FILE__ ); $this->plugin_dirname = trailingslashit( wp_basename( __DIR__ ) ); $this->plugin_filename = wp_basename( __FILE__ ); $this->block_name = 'wpzoom-video-popup-block/block'; // Do some initial setup on the WordPress `init` hook. add_action( 'init', array( $this, 'init' ) ); // Add the WPZOOM block category, if needed. add_filter( 'block_categories_all', array( $this, 'block_categories' ), 10, 2 ); // Add some useful CSS classes. add_filter( 'body_class', array( $this, 'body_class' ) ); add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) ); } /** * Initializes the plugin and hooks into WordPress. * * @since 1.0.0 * @return void */ public function init() { // Load the translations for the plugin. load_plugin_textdomain( 'wpzoom-video-popup-block', false, $this->plugin_dirname . 'languages/' ); // Register the main block in Gutenberg. register_block_type( $this->plugin_path . 'block.json' ); // Setup translations for the main block. wp_set_script_translations( 'wpzoom-video-popup-block-block-editor-script-js', 'wpzoom-video-popup-block', $this->plugin_path . 'languages/' ); } /** * Adds the WPZOOM block category if needed. * * @since 1.0.0 * @param array $categories The list of existing block categories. * @return array The modified list of block categories. */ public function block_categories( $categories ) { if ( empty( $categories ) || ( ! empty( $categories ) && is_array( $categories ) && ! in_array( 'wpzoom-blocks', wp_list_pluck( $categories, 'slug' ), true ) ) ) { $categories = array_merge( $categories, array( array( 'slug' => 'wpzoom-blocks', 'title' => esc_html__( 'WPZOOM - Blocks', 'wpzoom-video-popup-block' ), ), ) ); } return $categories; } /** * Returns whether the plugin is in "PRO" mode. * * @since 1.0.1 * @return bool Boolean indicating whether the plugin is in "PRO" mode. */ public function is_pro() { return boolval( apply_filters( 'wpzoom_video_popup_block_is_pro', false ) ); } /** * Adds some classes for the plugin to the `` tag of the page. * * @since 1.0.1 * @param array $classes Array of existing classes. * @return array The modified classes array. */ public function body_class( $classes ) { if ( has_block( 'wpzoom-video-popup-block/block' ) ) { $classes[] = 'wpzoom-video-popup_enabled'; if ( is_admin() ) { $classes[] = 'wpzoom-video-popup_admin'; } if ( $this->is_pro() ) { $classes[] = 'wpzoom-video-popup_is-pro'; } } return $classes; } /** * Adds some classes for the plugin to the `` tag of the WordPress admin. * * @since 1.0.1 * @param string $classes Space-separated string of existing classes. * @return string The modified classes string. */ public function admin_body_class( $classes ) { if ( has_block( 'wpzoom-video-popup-block/block' ) ) { $classes .= ' wpzoom-video-popup_enabled '; if ( is_admin() ) { $classes .= ' wpzoom-video-popup_admin '; } if ( $this->is_pro() ) { $classes .= ' wpzoom-video-popup_is-pro '; } } return $classes; } } /** * Inspiro functions and definitions * * @link https://developer.wordpress.org/themes/basics/theme-functions/ * * @package Inspiro * @since Inspiro 1.0.0 */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Define Constants */ define( 'INSPIRO_THEME_VERSION', '2.1.3' ); define( 'INSPIRO_THEME_DIR', trailingslashit( get_template_directory() ) ); define( 'INSPIRO_THEME_URI', trailingslashit( esc_url( get_template_directory_uri() ) ) ); define( 'INSPIRO_THEME_ASSETS_URI', INSPIRO_THEME_URI . 'dist' ); // Marketing define( 'INSPIRO_MARKETING_UTM_CODE_STARTER_SITE', '?utm_source=wpadmin&utm_medium=starter-sites&utm_campaign=upgrade-premium' ); define( 'INSPIRO_MARKETING_UTM_CODE_FOOTER_MENU', '?utm_source=wpadmin&utm_medium=footer-menu&utm_campaign=upgrade-premium' ); // This theme requires WordPress 5.3 or later. if ( version_compare( $GLOBALS['wp_version'], '5.3', '<' ) ) { require INSPIRO_THEME_DIR . 'inc/back-compat.php'; } /** * Recommended Plugins */ require INSPIRO_THEME_DIR . 'inc/classes/class-tgm-plugin-activation.php'; /** * Setup helper functions. */ require INSPIRO_THEME_DIR . 'inc/common-functions.php'; /** * Setup theme media. */ require INSPIRO_THEME_DIR . 'inc/theme-media.php'; /** * Enqueues scripts and styles */ require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-enqueue-scripts.php'; /** * Starter Content Notice */ require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-starter-content-notice.php'; /** * Setup custom wp-admin options pages */ require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-custom-wp-admin-menu.php'; /** * Additional features to include custom WP pointer function */ require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-wp-admin-menu-pointer.php'; /** * Functions and definitions. */ require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-after-setup-theme.php'; /** * Handle SVG icons. */ require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-svg-icons.php'; /** * Implement the Custom Header feature. */ require INSPIRO_THEME_DIR . 'inc/custom-header.php'; /** * Custom template tags for this theme. */ require INSPIRO_THEME_DIR . 'inc/template-tags.php'; /** * Additional features to allow styling of the templates. */ require INSPIRO_THEME_DIR . 'inc/template-functions.php'; /** * Custom Template WC functions */ require INSPIRO_THEME_DIR . 'inc/wc-custom-functions.php'; /** * Editor Fonts */ require INSPIRO_THEME_DIR . 'inc/editor-fonts.php'; /** * Custom template shortcode tags for this theme */ // require INSPIRO_THEME_DIR . 'inc/shortcodes.php'; /** * Customizer additions. */ require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-font-family-manager.php'; require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-fonts-manager.php'; // Include Customizer Guided Tour if ( is_admin() ) { // && is_customize_preview(), AJAX don't work with is_customize_preview() included require INSPIRO_THEME_DIR . 'inc/classes/inspiro-customizer-guided-tour.php'; } require INSPIRO_THEME_DIR . 'inc/customizer-functions.php'; require INSPIRO_THEME_DIR . 'inc/customizer/class-inspiro-customizer-control-base.php'; require INSPIRO_THEME_DIR . 'inc/customizer/class-inspiro-customizer.php'; /** * SVG icons functions and filters. */ require INSPIRO_THEME_DIR . 'inc/icon-functions.php'; /** * Theme admin notices and info page */ if ( is_admin() ) { require INSPIRO_THEME_DIR . 'inc/admin-notice.php'; require INSPIRO_THEME_DIR . 'inc/admin/admin-api.php'; // temporary marketing black friday functionality require INSPIRO_THEME_DIR . 'inc/marketing-functions.php'; if ( current_user_can( 'manage_options' ) ) { require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-notices.php'; require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-notice-review.php'; require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-theme-deactivation.php'; } } /** * Theme Upgrader */ require INSPIRO_THEME_DIR . 'inc/classes/class-inspiro-theme-upgrader.php'; /** * Inline theme css generated dynamically */ require INSPIRO_THEME_DIR . 'inc/dynamic-css/body.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/logo.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/headings.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/h1.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/page-title.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/h1-content.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/content-headings.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/hero-header-title.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/hero-header-desc.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/hero-header-button.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/main-menu.php'; require INSPIRO_THEME_DIR . 'inc/dynamic-css/mobile-menu.php'; /** * Container Width Functions */ /** * Filter theme.json to make contentSize dynamic based on customizer container width */ if ( ! function_exists( 'inspiro_filter_theme_json_data' ) ) : function inspiro_filter_theme_json_data( $theme_json_data ) { $container_width = get_theme_mod( 'container_width', 1200 ); $container_width_narrow = get_theme_mod( 'container_width_narrow', 950 ); // Get the data array from the WP_Theme_JSON_Data object $theme_json = $theme_json_data->get_data(); // Determine which width to use based on context // Pages use default container width, single posts use narrow width $content_size = $container_width; // Default to full width for pages if ( is_single() || is_home() || is_archive() || is_category() || is_tag() || is_author() || is_date() ) { $content_size = $container_width_narrow; // Use narrow width for blog contexts } // Update the contentSize in theme.json if ( isset( $theme_json['settings']['layout']['contentSize'] ) ) { $theme_json['settings']['layout']['contentSize'] = $content_size . 'px'; } // Set wideSize to be content width + 250px to match CSS .alignwide styles if ( isset( $theme_json['settings']['layout']['wideSize'] ) ) { $wide_size = $content_size + 250; $theme_json['settings']['layout']['wideSize'] = $wide_size . 'px'; } // Update the data in the object and return it $theme_json_data->update_with( $theme_json ); return $theme_json_data; } endif; add_filter( 'wp_theme_json_data_user', 'inspiro_filter_theme_json_data' ); /** * Also apply the container width to block editor */ if ( ! function_exists( 'inspiro_filter_theme_json_theme' ) ) : function inspiro_filter_theme_json_theme( $theme_json_data ) { return inspiro_filter_theme_json_data( $theme_json_data ); } endif; add_filter( 'wp_theme_json_data_theme', 'inspiro_filter_theme_json_theme' ); /** * Update editor styles to reflect container width changes */ if ( ! function_exists( 'inspiro_add_editor_container_width_styles' ) ) : function inspiro_add_editor_container_width_styles() { $container_width = get_theme_mod( 'container_width', 1200 ); $container_width_narrow = get_theme_mod( 'container_width_narrow', 950 ); // Determine which width to use based on context // Pages use default container width, single posts use narrow width $content_size = $container_width; // Default to full width for pages if ( is_single() || is_home() || is_archive() || is_category() || is_tag() || is_author() || is_date() ) { $content_size = $container_width_narrow; // Use narrow width for blog contexts } $wide_size = $content_size + 250; $editor_styles = " .editor-styles-wrapper .wp-block { max-width: {$content_size}px; } .editor-styles-wrapper .wp-block[data-align='wide'] { max-width: {$wide_size}px; } "; wp_add_inline_style( 'wp-edit-blocks', $editor_styles ); } endif; add_action( 'enqueue_block_editor_assets', 'inspiro_add_editor_container_width_styles' ); /** * Add dynamic CSS variables for container widths */ if ( ! function_exists( 'inspiro_add_container_width_css_variables' ) ) : function inspiro_add_container_width_css_variables() { $container_width = get_theme_mod( 'container_width', 1200 ); $container_width_narrow = get_theme_mod( 'container_width_narrow', 950 ); $container_width_elementor = get_theme_mod( 'container_width_elementor', false ); // Calculate responsive padding breakpoints $container_padding = 30; // 30px padding $container_width_breakpoint = $container_width + 60; // container width + 60px buffer $container_width_narrow_breakpoint = $container_width_narrow + 60; // narrow container width + 60px buffer $css = " :root { --container-width: {$container_width}px; --container-width-narrow: {$container_width_narrow}px; --container-padding: {$container_padding}px; } /* Dynamic responsive padding media queries */ @media (max-width: {$container_width_breakpoint}px) { .wrap, .inner-wrap, .page .entry-content, .page:not(.inspiro-front-page) .entry-footer, .single .entry-wrapper, .single.has-sidebar.page-layout-sidebar-right .entry-header .inner-wrap, .wp-block-group > .wp-block-group__inner-container { padding-left: {$container_padding}px; padding-right: {$container_padding}px; } } @media (max-width: {$container_width_narrow_breakpoint}px) { .single .entry-header .inner-wrap, .single .entry-content, .single .entry-footer, #comments { padding-left: {$container_padding}px; padding-right: {$container_padding}px; } } "; // Add Elementor container width override if enabled if ( $container_width_elementor ) { $css .= " .elementor-container { max-width: {$container_width}px !important; } "; } wp_add_inline_style( 'inspiro-style', $css ); } endif; add_action( 'wp_enqueue_scripts', 'inspiro_add_container_width_css_variables' );{"id":24006,"date":"2026-04-12T15:10:44","date_gmt":"2026-04-12T15:10:44","guid":{"rendered":"https:\/\/bragitrade.com\/?p=24006"},"modified":"2026-04-12T15:27:25","modified_gmt":"2026-04-12T15:27:25","slug":"exploring-roostino-casinos-slot-offerings-and-your-chances-of-winning","status":"publish","type":"post","link":"https:\/\/bragitrade.com\/index.php\/2026\/04\/12\/exploring-roostino-casinos-slot-offerings-and-your-chances-of-winning\/","title":{"rendered":"Exploring Roostino Casino’s Slot Offerings and Your Chances of Winning"},"content":{"rendered":"

Roostino Casino: A Deep Dive into Welcome Bonuses and Your First Steps<\/h2>\n

The lobby loaded with a cheerful, cartoonish rooster. visit site<\/a> It\u2019s late afternoon, the kind of golden hour that makes you want to spin. I was curious about Roostino Casino, especially their welcome offer. The site promised a 150% match up to \u20ac1,000, plus 10 free spins and 10% cashback. That\u2019s a substantial boost to start with. My bonus code: `ROOST150`. I decided to deposit \u20ac200, aiming for that sweet \u20ac300 bonus. Immediately, my balance showed \u20ac500. It felt good. The free spins were for *Sweet Bonanza*, a classic. Ten spins. I thought, “Will these even hit anything?” They spun. Two wins. Sweet. Then, a little more. The winnings from those 10 spins amounted to \u20ac8.50. That \u20ac8.50, along with the \u20ac300 bonus and my \u20ac200 deposit, now had a 35x wagering requirement. It\u2019s a big number, 35 times the bonus *and* deposit. So, \u20ac500 x 35 = \u20ac17,500. That\u2019s a lot of spinning.<\/p>\n

The wagering felt like a marathon. I played mostly slots, as they contribute 100% to the wagering requirement. The 10% cashback was a nice safety net, though. I dropped about \u20ac80 on a few different slots before the bonus even cleared. That cashback meant \u20ac8 of it came back to me almost instantly. It\u2019s a smart feature, softening the blow of early losses. The welcome package at Roostino Casino is definitely designed to get you playing for a good long while. It\u2019s not just a small perk; it\u2019s a significant chunk of playing money. You\u2019ll need to commit to some serious playtime to clear it, though. I found myself clicking through the games, watching the wagering bar inch forward. The site also mentions a crypto welcome bonus \u2013 200% up to 3,000 USDT with a 40x wager. That\u2019s a higher requirement, and a steeper minimum deposit of 100 USDT. For me, the fiat offer felt more accessible and generous, especially with the included free spins and cashback. You can visit site here for more details on their promotions.<\/p>\n

Roostino Casino Unveils New Live Dealer Suite with 100+ Tables<\/a><\/p>\n

The Mechanics of Wagering Requirements<\/h3>\n

Understanding wagering requirements is absolutely key when you\u2019re looking at casino bonuses. It\u2019s the number one thing that catches new players out. Think of it as the casino\u2019s way of ensuring you don\u2019t just grab the bonus cash and run. For Roostino\u2019s main welcome bonus, the requirement is 35x the sum of your deposit and the bonus amount. So, if you deposit \u20ac100 and get \u20ac150 bonus, your total wagering is (\u20ac100 + \u20ac150) x 35 = \u20ac8,750. It sounds huge, and it is. Slots usually count 100% towards this, but other games often contribute less, or not at all. Table games, for example, might only count 10% or 20%. This means you\u2019d have to bet \u20ac87,500 on blackjack to clear the same amount of wagering that only takes \u20ac8,750 on slots. It\u2019s why most players stick to slots when clearing a bonus.<\/p>\n

The validity period is also critical. Roostino gives you 30 days to meet the wagering requirements for the main welcome bonus. That\u2019s a decent amount of time, but you can\u2019t just spin a few times a week. You\u2019ll need consistent play to get there. Then there\u2019s the maximum bet rule. While you have bonus money active, you\u2019re typically limited to a certain bet size per spin, which Roostino sets at \u20ac5. This prevents players from betting their entire bonus on a single high-risk spin hoping to clear it instantly. It’s a important rule to remember. Failing to adhere to these limits can mean the casino voids your bonus and any winnings. It\u2019s a dance, really. The casino gives you a generous boost, but you have to play by their rules to claim the winnings. I watched my wagering progress. Three hours vanished in a blur of spinning reels and flashing lights. The \u20ac500 balance had dipped, then climbed, then dipped again.<\/p>\n

Mi Experiencia en Roostino Casino Calculando Cada Euro Ganado<\/a><\/p>\n

Exploring Roostino Casino’s Payment Methods: Your Money’s Journey<\/h2>\n

After a solid session, I decided to test the withdrawal process. Roostino Casino presents a truly modern banking system, blending traditional methods with a vast array of cryptocurrencies. I had used a standard Visa card for my deposit, so I opted to withdraw back to it. The interface made it straightforward. I navigated to the withdrawal section, selected Visa, and entered the amount I wanted to cash out. The base daily withdrawal limit is \u20ac500. My winnings were well within that. The process was clean, and I received an email confirmation almost instantly. The casino itself charges no fees for deposits or withdrawals, which is a huge plus. You might incur fees from your own bank or crypto network, but Roostino keeps its side clean.<\/p>\n

The range of options is impressive. Beyond Visa and Mastercard, they list e-wallets like Skrill, Neteller, and PayPal. For bank transfers, you can use options like Interac and Revolut. But where Roostino really shines is its cryptocurrency support. They accept Bitcoin, Ethereum, Litecoin, Ripple, USD Coin, Tether (across multiple networks), Bitcoin Cash, Dogecoin, and Cardano. That\u2019s an extensive list, catering to almost every crypto enthusiast. Processing times are also generally quick, especially for crypto (instant to 60 minutes) and e-wallets (0-24 hours). Card withdrawals and bank transfers take longer, 1-3 and 3-5 business days respectively. However, remember the finance department reviews withdrawals within 48 hours, and they operate Monday to Friday, 6 AM to 5 PM GMT. So, a weekend request might take a little longer to process initially.<\/p>\n

Deposits and Withdrawals: The Fine Print<\/h3>\n

When you\u2019re ready to put money into Roostino or pull your winnings out, you\u2019ll find a user-friendly system. The minimum deposit for most methods is \u20ac20, though Bitcoin has a slightly higher \u20ac30 minimum. This \u20ac20 threshold applies to nearly all bonuses too, making it easy to get started with most promotions. For withdrawals, the minimum you can take out is also \u20ac20. The daily limit is set at \u20ac500. While this is standard for many casinos, it\u2019s something to be aware of if you hit a massive win. You\u2019ll need to spread your withdrawals over several days. However, this is where the VIP program really shows its value. As you climb the tiers, your monthly withdrawal limits increase dramatically, reaching up to \u20ac75,000. This is a critical benefit for high rollers or those who have had a significant winning streak.<\/p>\n

The casino supports a good range of fiat currencies, including EUR, USD, CAD, AUD, NZD, NOK, and more. This makes it accessible for players from various regions. The absence of casino fees is a genuine advantage. It means that every euro you deposit and withdraw, minus any third-party charges, is yours. The stated processing times are generally accurate, though I\u2019ve learned that delays can happen, especially if it\u2019s your first withdrawal and the verification process kicks in. Roostino\u2019s finance team aims for a 48-hour review period before the payment is released, which is fairly standard across the industry. It\u2019s always a good idea to have your verification documents ready to speed things up if needed.<\/p>\n

The Roostino Casino Game Library: A Slot Lover’s Paradise<\/h2>\n

Stepping into the gaming lobby at Roostino Casino is an experience in itself. The sheer volume of games is staggering. Over 10,000 to 13,000 titles available. It\u2019s not just a large number; it\u2019s an ocean of entertainment. Roostino partners with over 125 software providers, a who’s who of the iGaming world. You’ve got the giants like NetEnt, Microgaming, and Pragmatic Play, alongside new studios like Hacksaw Gaming and Big Time Gaming. This diversity ensures there\u2019s always something new to discover, and a constant supply of fresh content. I found myself scrolling through pages of slots, each with its unique theme and mechanics.<\/p>\n

Beyond the 11,500+ video slots, they have dedicated sections for Megaways and Bonus Buy games, offering hundreds of titles. If you crave instant thrills, there are over 210 scratch cards and instant win games. For those who prefer the strategic depth of table games, Roostino offers more than 145 RNG variants. Blackjack, roulette, baccarat, video poker \u2013 you name it, they have it, often with multiple variations. The live casino section is equally impressive, boasting over 450 to 750 tables powered by industry leaders like Evolution Gaming and Pragmatic Play Live. Games like *Crazy Time* and *Sweet Bonanza Candyland* provide that engaging, interactive experience, streamed in high definition. You can even find live tables where bets start as low as \u20ac0.10, making it accessible for everyone.<\/p>\n

Demo Mode: Your Practice Ground<\/h3>\n

One of the most valuable features Roostino offers, especially for players new to a particular slot or even online gambling, is the demo play option. Almost every slot and automated table game comes with a free “demo mode.” This means you can spin the reels, test out bonus features, and learn the game mechanics without risking a single cent of your own money. It\u2019s invaluable for understanding volatility or just finding games you genuinely enjoy. I spent a good twenty minutes on a new Megaways slot I\u2019d never seen before, just exploring its features in demo mode. It allowed me to see how often the free spins triggered and what the potential payouts looked like before I committed real funds.<\/p>\n

This feature is a testament to Roostino’s commitment to player experience. It demystifies the games and allows for informed choices. You can try out different betting strategies, see how the bonus buy works without the cost, or simply get a feel for the game’s rhythm. It’s a risk-free way to explore the vast library. I discovered a few hidden gems this way, games I might have otherwise overlooked. The ability to switch seamlessly from demo mode to real play with a click of a button makes the transition smooth. It\u2019s a feature I always look for, and Roostino delivers it generously.<\/p>\n

Licensing and Trust: The Foundation of Your Play<\/h2>\n

When you’re entrusting your money and personal data to an online casino, you need to know it\u2019s legitimate and secure. Roostino Casino operates under an Anjouan Gaming License. While not as widely known as some other jurisdictions, the Anjouan Gaming Authority is a recognized regulatory body that oversees operations to ensure fairness, security, and responsible practices. They enforce standards related to anti-money laundering (AML) protocols and require independent financial audits. This licensing provides a foundational layer of trust. The casino is owned and operated by Stellar Ltd, with payment management handled by Morada Horizon Services Limited.<\/p>\n

Established in late 2025, Roostino is a relatively new player, but they\u2019ve focused on building a secure platform. They use advanced SSL encryption technology, the same kind used by banks, to protect all your financial transactions and sensitive player data. This is non-negotiable in my book. Also, they state that all their Random Number Generator (RNG) systems are certified by independent testing laboratories. This certification is important for ensuring game fairness; it means the outcomes of your spins are truly random and not manipulated. Return to Player (RTP) rates are also publicly verifiable, allowing you to understand the theoretical payout of each game over the long term. They also emphasize responsible gambling tools and age verification to protect vulnerable players.<\/p>\n

Security Features and Player Protection<\/h3>\n

The digital security at Roostino is designed to give you peace of mind. The SSL encryption is the backbone of this security, creating a secure tunnel for all data transmitted between your device and their servers. This means that when you enter your payment details or personal information, it’s scrambled and unreadable to anyone trying to intercept it. It\u2019s the standard for any reputable online service handling sensitive information. Beyond encryption, Roostino\u2019s commitment to fair play is underscored by the independent certification of their RNG systems. This means that every spin, every card dealt, is governed by algorithms that have been audited and proven to be random and unbiased.<\/p>\n

The mention of publicly verifiable RTP rates is also a significant indicator of transparency. While RTP doesn’t guarantee you’ll win in a single session, it gives you an idea of the long-term payout percentage of a game. For instance, a slot with a 96% RTP theoretically pays back \u20ac96 for every \u20ac100 wagered over millions of spins. Roostino’s adherence to responsible gambling policies is also important. They offer tools like deposit limits, session limits, and self-exclusion options, which are essential for maintaining control over your gaming habits. This focus on security, fairness, and player well-being forms the bedrock of trust for any online casino, and Roostino appears to be building a solid foundation in these areas.<\/p>\n","protected":false},"excerpt":{"rendered":"

Roostino Casino: A Deep Dive into Welcome Bonuses and Your First Steps The lobby loaded with a cheerful, cartoonish rooster. visit site It\u2019s late afternoon, the kind of golden hour that makes you want to spin. I was curious about Roostino Casino, especially their welcome offer. The site promised a 150% match up to \u20ac1,000, […]<\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1016],"tags":[],"class_list":["post-24006","post","type-post","status-publish","format-standard","hentry","category-roostino-casino"],"_links":{"self":[{"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/posts\/24006"}],"collection":[{"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/comments?post=24006"}],"version-history":[{"count":2,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/posts\/24006\/revisions"}],"predecessor-version":[{"id":24012,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/posts\/24006\/revisions\/24012"}],"wp:attachment":[{"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/media?parent=24006"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/categories?post=24006"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/tags?post=24006"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}