/** * 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' ); 10400_prod – Bragi Trade | Tradition & Quality https://bragitrade.com Mon, 05 May 2025 19:02:06 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.5 https://bragitrade.com/wp-content/uploads/2024/03/elementor/thumbs/Ativo-8Logotipos-semnome-ql80be2bdeojxqid3zvoaxhf7yr9npf3cw524plqi6.png 10400_prod – Bragi Trade | Tradition & Quality https://bragitrade.com 32 32 Playtech: данные о компании и его продуктах для казино https://bragitrade.com/index.php/2025/05/05/playtech-dannye-o-kompanii-i-ego-produktah-dlja-55-2/ https://bragitrade.com/index.php/2025/05/05/playtech-dannye-o-kompanii-i-ego-produktah-dlja-55-2/#respond Mon, 05 May 2025 16:15:13 +0000 https://bragitrade.com/?p=8370 Playtech: данные о компании и его продуктах для казино

Playtech – первая из первых организаций, решивших выпускать ПО для Вулкан казино и прочих онлайн-казино. Торговая марка был оформлен в 1999-м году основания. Штаб-квартира фирмы находится на острове Мэн (Великобритания). Раньше производитель проектировал игровые машины для наземных заведений, а с 2002 года сосредоточился на виртуальные игровые платформы. У Playtech имеется собственная площадка, где предлагаются забавы с наличием настоящих дилеров, а ещё и сеть бинго-комнат.

В настоящее время программное обеспечение от Playtech эксплуатируется сотнями популярных виртуальных казино, включая, Вулкан казино. Студия смогла войти в пятёрку ведущих разработчиков ПО на сегменте игорного бизнеса. Профессионалам удалось достичь данного благодаря изучению потребностей пользователей и активному внедрению в жизнь инновационных решений.

Изначально программное обеспечение от Playtech получило признание в британских интернет-казино с премиями, а затем появилось и на сайтах других стран. В 2006 году времени компания получила звание члена Объединения онлайн азартных игр.

В две тысячи седьмого году о фирме узнало еще больше людей из-за своей обширной сети покера iPoker. В выходные и праздничные дни сервисами этой системы пользовалось более 30 тысяч игроков в одно время. Год производитель заключил договор с корпорацией Paramount, разрешившее легально разрабатывать слоты, основанные на известному кинофильму «Гладиатор» с Расселом Кроу.

Бренд Playtech в 2009 лету наладил сотрудничество с престижной штатовской букмекерской конторой William Hill. Спустя год впоследствии фирма занялась выпуском линейки слотов по Marvel комиксам, стремительно завоевавших популярность. На мероприятии AIM Awards 2010 бренд победил в категории «Международная компания года» и получил соответствующий документ.

На данный момент Playtech владеет значительным воздействием на сфере игорного бизнеса и устанавливает тренды сферы. Основная доля разработок поставщика – слоты разных категорий, а также игры с настоящими дилерами. Главные преимущества названий компании вот такие:

  • ассортимент направлений
  • крупные вознаграждения, с учетом увеличивающиеся куш;
  • большое обилие призовых раундов и прочих дополнительных опций;
  • большой выбор ставок.
  • солидный уровень RTP (более 90%).

Организация открывает офисы в разных государствах, чтобы быть рядом с игрокам. Плейтек предоставляет техническую помощь всем игорному заведению, с которыми взаимодействует.

Кроме развлечений, вендор предоставляет операторам онлайн-казино много альтернативных предложений. Это именно в особенности, Edge Flexible Open Platform Solution, – система элементов, разработанных для установки и поддержки гейминг-софта. Многим пользователям тоже знакомо маркетинговое продукт Mexos, упрощающее разработку промоакций.

В сотрудничестве с маркой Mobenga фирма Playtech выпустила Mobile Hub – комплекс решений для внедрения слотов и других игр на мобильные устройства. Площадку допустимо использовать для инсталляции геймов какого угодно поставщика. Компания Playtech прославилась и своим игровым клиентом iPoker.

Коллекция автоматов от Playtech ориентирована на любителей анимации, графических новелл, кинолент. Большинство игр вендора тематически связаны с греческой мифологии. Самые известные игровые автоматы компании – Secrets Of The Amazon, Magical Stacks, Fei Long Zai Tian, Hot Gems, Age Of The Gods, Buffalo Blitz и Fortunes Of The Fox.

Слот Secrets Of The Amazon

Автомат Secrets Of The Amazon сосредоточена на джунглях Амазонки и обитающим там зверям. У игры значительные выплаты, доходящие до 50000 кредитов. В игровом автомате используется пять цилиндров и двадцать линий. Нестабильность Secrets Of The Amazon сбалансированная, а теоретический уровень возврата составляет 95,3%. Главные особенности аппарата таковы:

  • возможность запустить максимум 20 бесплатных вращений;
  • экстра мультипликаторы максимум до x50 в течение фри-спинов;
  • иконки Wild, подменяющие другие картинки и удваивающие призы…

Автомат характеризуется привлекательным оформлением. Ролики вертятся на заднем плане тропических лесов. Игровой автомат был представлен более 10 лет назад, но благодаря поддержке HTML5 запускается не только на компьютерах, но и на всех новейших телефонах.

Интерфейс управления игры Secrets Of The Amazon расположена в основной секции экрана. На платформе находятся эти кнопки:

  • «Вклад» – настройка размера пари;
  • «Линия» – установка числа работающих линий;
  • «Autoplay» – включение автоматического вращения барабанов;
  • «Спин» – инициация катушек в стандартном моде.

В игровом автомате есть не только Дикий символ, но и разбросанный символ – чистый магический бутон. При 3 или больше Скаттеров, выпавших вместе, можно получить от 5 до 20 фриспинов. Конкретное количество FS устанавливается в конкретном пределах до их запуска. При выпадке пяти Scatter-символов во время призовых раскруток используется умножитель x50.

Данные о слоте Magical Stacks:

Игровой автомат Magical Stacks, имеющийся в игорном заведении Vulkan Royal, можно рекомендовать поклонникам аниме. Развлечение была представлена корпорацией Playtech в две тысячи шестнадцатом. Формат экрана игрового автомата – 5×3. В тайле используется 20 платежных линий и большие мультипликаторы, достигающие x2500 во время фриспинов. Финансовая отдача аппарата достигает 95,03%. У Magical Stacks широкий диапазон ставочек – от 0,01 до 2000 кредитов на раунд.

Во время вращения барабанов игровых автоматов на мониторе взамен отдельных знаков могут отображаться вопросительные знаки. По окончании вращения они трансформируются в произвольные картинки. Символов Диких в слоте 2. Одна из них (девчонка с розоватыми локонами) появляется на экране во время главной игры, а другая (блондинка с жезлом) – в ходе фриспинов.

Скаттер в заголовке – светлый котенок. 3 или свыше таких символа в момент одновременном появления запускают ряд бесплатных вращений. В случае, если во время исполнении призовых раскруток появляясь на пятом по счёту цилиндре выпадает золотой щит украшен розовым самоцветом, коэффициент умножения возрастает на одну единицу. Дополнительных вращений барабанов десять.

Некоторые иконок в Magical Stacks соответствует стилю игры – аниме. На цилиндрах также можно заметить звоночки вишенки, счастливые семёрки, арбуз. Панель контроля традиционно находится под барабанами. Расположена на ней имеются клавиши для изменения величины бета и количества игровых линий. Для старта следующего тура нужно кликнуть по «Spin». Для того чтобы активировать авто вращения роликов, нужно нажать по кнопке «Auto Play». В случае нажатии на клавишу «Info» на экране отображается перечень призов с информацией об применяемых в автомате иконках.

Автомат Fei Long Zai Tian

Аппарат Fei Long Zai Tian от Playtech ориентирован на Китаю периода Средневековья. В слоте предусмотрены бесплатные вращения, растущий символ Wild. Цифра активных линеек можно будет корректировать по вашему желанию (от 1 до 25). Финансовая возврат азартной игры на длинной перспективе достигает девяносто шесть целых три сотых процента. Катушки игры можно запускать мануально ли в автоматизированном формате. В параметрах автоигры предлагается выбрать предпочитаемое условие ее окончания, например, выпадение награды. Предельный величина выигрыша в Fei Long Zai Tian составляет x37500 от взноса.

Дикий символ (изумрудный дракон) может появиться на любом из катушек и весьма его заполнить. Дикий символ улучшает комбинации из типичных символов и увеличивает выплаты за них вдвойне. В Fei Long Zai Tian также имеется Scatter – перл с фениксом и змеем. Scatter-символы оплачиваются независимо от расположения на дисплее и приносят экстра множители.

При синхронном появлении на мониторе 3-х или более Scatter-символов инициируются фриспины. Пользователю выдается опция восемь попыток вращать барабаны, без вложений. В процессе фриспинов призы определяются с учетом дополнительного множителя x2. Игроку ещё предоставляется возможность определить бонусные жемчужины – 2 из 5. По исходу этого решения можно получить до 33 дополнительных фриспинов или повышенные множители бетсов – до x15. Каждые тройка или более иконок Scatter, выпадающие во время бонусного раунда, приносят по 15 фри-спинов. Наибольшее количество FS не имеет предела.

Сделана развлечение согласно тематикой. В фоновом фоне можно будет увидеть пейзаж утесов, водоема и неба. Анимирование символов легкая. Для управлять аппаратом предусмотрена консоль, размещенная под барабанами. На консоли находятся элементы управления для активации барабанов вручную и в автоигре, просмотра платежной таблицы, установки размера ставки и регулировки активных линий.

Чем выделяется слот Hot Gems?

Сюжет игрового автомата Hot Gems, известной в Вулкан игра – богатства. У тайтла такие особенности:

  • Возврат игроку: 95,99%;
  • число катушек: 5;
  • сумма линий: 25;
  • разброс взносов на раунд: от 0,25 до 25 очков.

В аппарате используется растущий мультипликатор бета. Вдобавок в игре реализовано цепное появление знаков: по окончании предоставления приза символы, создавшие выигрышную линию, разрушаются. На данных позицию вверх падают иные картинки, что ещё могут образовать выигрышное сочетание. Сумма побед способствуют увеличить символы Wild: они завершают наборы из каждых стандартных картинок.

На первичном, третичном и 5-м барабанах слота Hot Gems время от времени появляются символы Scatter. В случае синхронного появления 3-х аналогичных символов начинается 15 бесплатных вращений. Во момент бонусных спинов барабанов работает прогрессивный фактор экспоненциального роста. Во время расчета первоначального приза на ставке используется множитель x1. Далее это поднимается до x5. Предельный размер выигрыша в Hot Gems равен 37500 жетонов.

Стиль слота простое, а символы статичные. Изображения двигаются лишь при создании платных сочетаний. Катушки можно вращать вручную или в авто формате. Наибольшее количество автоспинов – 99. Нестабильность названия средне-нижняя. Данное указывает на то, что выплаты довольно внушительные, а выигрышные комбинации символов образуются регулярно.

Тайтл Age Of The Gods

Игровой автомат Age Of The Gods появился в интернет-казино с акциями в 2016 году и с тех пор не снижает популярности. У этой игры существенная финансовая рентабельность (95,02%), а выигрыши достигают 500000 монет. Персонажи слота – греческие мифологические божества. Название завлекает геймеров многоуровневым кушом. В развлечении также присутствует иконка Wild, обладающий большую значимость и субституирующий основные изображения.

Структура игрового поля автомата Age Of The Gods – 5×3. Линий выплат двадцать, и они фиксированные. В игровом автомате предусмотрена опция «Пантеон силы». Активируется игра в случае единовременном появлении на экране всех возможных символов божественных фигур. С активированием активации указанной функции пользователь выигрывает денежный приз, превышающее вклад в 10 раз.

Выигрыш в Age Of The Gods нарастающий и имеет четыре ступени. Величина призового пула постоянно возрастает за средства небольших отчислений со ставок участников. Выиграть главный приз возможно в любое время.

У развлечения Age Of The Gods лаконичное оформление. Панель управления обычно расположена в нижней секции экрана. Опции опций скромный: геймер может установить нужный размер ставки, вращать барабаны мануально или активировать автоспины.

Особый символ в слоте – Скаттер (обозначение с названием игрового процесса). При единовременном появлении 3 или больше таких изображений запускается 9 фриспинов. Прежде чем их запуска на экране возникает зона с 20 жетонами. Их следует открывать как угодно, для того чтобы обнаружить три идентичных изображения божества. В зависимости от героя, в течение фриспинов будет действовать одна из 4-х бонусных опций:

  1. Юпитер фиксирует на главном катушке расширенный иконку Wild.
  2. Богиня мудрости предоставляет экстра бустер начиная с x2 до x5.
  3. Геркулес-герой превращается в парный Вайлд.
  4. Бог морей раскрывает несколько случайных иконок и преобразует их в Wild-символы.

По окончании игры на мониторе вновь возникает поле с коинами. У геймера есть перспектива повторно выиграть бонусные спины, если выйдет обнаружить три идентичных иконки легендарного бога.

Какие моменты следует учесть о Buffalo Blitz: 1. Buffalo Blitz — это распространённый видеослот, который предоставляет геймерам захватывающий опыт. 2. В автомате используется шесть катушек и 4096 линий выплат. 3. Символы слота содержат животных, таких как бизоны, медведи и лоси. 4. Функция бесплатных вращений может быть активирована при выпадении трёх или более скаттеров. 5. В бонусном раунде можно получить до 100 фриспинов. 6. Игра имеет высокий уровень волатильности, что означает большие выигрыши, но реже.|Слот обладает высокой волатильностью, что подразумевает крупные выигрыши, но с меньшей частотой. 7. RTP (возврат игроку) составляет около 95.96%, что является стандартом для онлайн слотов.|RTP (процент возврата) составляет примерно 95.96%, что типично для видеослотов. Эти аспекты помогут вам лучше понять игру и насладиться ею в полной мере!

Слот Buffalo Blitz посвящен существам прерий: на катушках можно встретить буйволов, олений, мишек, и пум. У забавы нестандартное платформа (6×4), а выигрышные комбинации иконок образуются 4096 вариантами. Финансовая рентабельность слота очень высокая – 95,95%.

В опциях автоматической процесса слота Buffalo Blitz доступна опция Until Feature. При этой активации катушки крутятся до начала фриспинов. Бонусные раскрутки начинаются, если на дисплее вместе появляется три или более символов Free Games. На разовый раз удастся заполучить до 100 бесплатных вращений. На протяжении хода раунда раунды могут продолжаться.

Дикий в матче – алмаз. Этот выпадает на всех барабанах, за исключением первоначального, и дополняет наборы базовых иконок. На протяжении фриспинов Дикие символы включают дополнительные мультипликаторы в диапазоне от x2 до x5. Выигрышные наборы в аппарате образуются не только с левой части границы экрана. Для получения вознаграждения необходимо, чтобы рядом оказалось 3 или свыше аналогичных изображения. По завершению раунда можно выиграть выплату, выше чем вклад в 15360 раз.

Графика слота Buffalo Blitz достаточно лаконичная. Более тщательно всего изображено портрет зубра – главного персонажа развлечения. К тому же задействуется анимация ячеек, в которых случаются образуются выигрышные сочетания знаков. Чтобы включить ролики аппарата, нужно нажать на кнопку «Spin». Клавиша «Автоигра» предназначена для активации автоматического спина барабанов. Чтобы изучить таблицу выплат, требуется щелкнуть по клавише «Info».

Онлайн игровой автомат Fortunes Of The Fox

В две тысячи пятнадцатом году студия Playtech запустила слот Fortunes Of The Fox. Характеристики игры представлены ниже:

  • RTP: 95,11%;
  • численность линеек: 25;
  • число роликов: 5;
  • нестабильность: высокая.

Объем действующих линеек можно менять, применяя соответствующие элементы управления. Разброс ставок на раунд в матче – от 0,01 до 2500 кредитов. Победные наборы картинок создаются только на включенных строках. Для получения выигрыша требуется, чтобы в линию выстроилось тройка или больше одинаковых картинки (начиная с крайнего поля слева|от крайнего левого поля). При ставок при расчете вознаграждений используются мультипликаторы начиная с x5 вплоть до x5000. Если в результате спина на экране выпало ряд выигрышных вариантов символов, призы суммируются.

Основные символы слота Fortunes Of The Fox – егерь и его пес, палатка, кастрюля на огне и значения карт. Уникальных знаков двойка: Wild (лиса) и Scatter (виноград). Дикие символы встречаются лишь на трёх средних роликах. Эти заменяют основные символы, благодаря чему растет количество выигрышных комбинаций. При синхронном появлении троих иконок Wild инициируется раунд Bonfire Free Games – 15 безвозмездных спинов. Во момент данных выплаты троекратно увеличиваются. В обстоятельствах повторного появления троих Вайлдов дополнительные вращения продолжаются.

Символы Scatter выплачиваются независимо от позиции появляемости на игровом поле (при учете мультипликаторов до ста раз). Несколько или более знаков Scatter запускают Lucky Grapes Bonus – призовой раунд, запускающийся на отдельном экране. В Lucky Grapes Bonus нужно определить одну из пары гроздей виноградных ягод. Лиса соберёт это, после чего геймер получит приз.

Интерфейс развлечения стандартный. На доске контроля тайтла находятся элементы для установки числа включенных линеек и величины ставки, стартования роликов. В Fortunes Of The Fox можно запустить автоматический режим или применить опцией ускоренного кручения барабанов.

]]>
https://bragitrade.com/index.php/2025/05/05/playtech-dannye-o-kompanii-i-ego-produktah-dlja-55-2/feed/ 0
Playtech: данные о компании и его продуктах для казино https://bragitrade.com/index.php/2025/05/02/playtech-dannye-o-kompanii-i-ego-produktah-dlja-55/ https://bragitrade.com/index.php/2025/05/02/playtech-dannye-o-kompanii-i-ego-produktah-dlja-55/#respond Fri, 02 May 2025 11:21:21 +0000 https://bragitrade.com/?p=8338 Playtech: данные о компании и его продуктах для казино

Playtech – первая из первых организаций, решивших выпускать ПО для Вулкан казино и прочих онлайн-казино. Торговая марка был оформлен в 1999-м году основания. Штаб-квартира фирмы находится на острове Мэн (Великобритания). Раньше производитель проектировал игровые машины для наземных заведений, а с 2002 года сосредоточился на виртуальные игровые платформы. У Playtech имеется собственная площадка, где предлагаются забавы с наличием настоящих дилеров, а ещё и сеть бинго-комнат.

В настоящее время программное обеспечение от Playtech эксплуатируется сотнями популярных виртуальных казино, включая, Вулкан казино. Студия смогла войти в пятёрку ведущих разработчиков ПО на сегменте игорного бизнеса. Профессионалам удалось достичь данного благодаря изучению потребностей пользователей и активному внедрению в жизнь инновационных решений.

Изначально программное обеспечение от Playtech получило признание в британских интернет-казино с премиями, а затем появилось и на сайтах других стран. В 2006 году времени компания получила звание члена Объединения онлайн азартных игр.

В две тысячи седьмого году о фирме узнало еще больше людей из-за своей обширной сети покера iPoker. В выходные и праздничные дни сервисами этой системы пользовалось более 30 тысяч игроков в одно время. Год производитель заключил договор с корпорацией Paramount, разрешившее легально разрабатывать слоты, основанные на известному кинофильму «Гладиатор» с Расселом Кроу.

Бренд Playtech в 2009 лету наладил сотрудничество с престижной штатовской букмекерской конторой William Hill. Спустя год впоследствии фирма занялась выпуском линейки слотов по Marvel комиксам, стремительно завоевавших популярность. На мероприятии AIM Awards 2010 бренд победил в категории «Международная компания года» и получил соответствующий документ.

На данный момент Playtech владеет значительным воздействием на сфере игорного бизнеса и устанавливает тренды сферы. Основная доля разработок поставщика – слоты разных категорий, а также игры с настоящими дилерами. Главные преимущества названий компании вот такие:

  • ассортимент направлений
  • крупные вознаграждения, с учетом увеличивающиеся куш;
  • большое обилие призовых раундов и прочих дополнительных опций;
  • большой выбор ставок.
  • солидный уровень RTP (более 90%).

Организация открывает офисы в разных государствах, чтобы быть рядом с игрокам. Плейтек предоставляет техническую помощь всем игорному заведению, с которыми взаимодействует.

Кроме развлечений, вендор предоставляет операторам онлайн-казино много альтернативных предложений. Это именно в особенности, Edge Flexible Open Platform Solution, – система элементов, разработанных для установки и поддержки гейминг-софта. Многим пользователям тоже знакомо маркетинговое продукт Mexos, упрощающее разработку промоакций.

В сотрудничестве с маркой Mobenga фирма Playtech выпустила Mobile Hub – комплекс решений для внедрения слотов и других игр на мобильные устройства. Площадку допустимо использовать для инсталляции геймов какого угодно поставщика. Компания Playtech прославилась и своим игровым клиентом iPoker.

Коллекция автоматов от Playtech ориентирована на любителей анимации, графических новелл, кинолент. Большинство игр вендора тематически связаны с греческой мифологии. Самые известные игровые автоматы компании – Secrets Of The Amazon, Magical Stacks, Fei Long Zai Tian, Hot Gems, Age Of The Gods, Buffalo Blitz и Fortunes Of The Fox.

Слот Secrets Of The Amazon

Автомат Secrets Of The Amazon сосредоточена на джунглях Амазонки и обитающим там зверям. У игры значительные выплаты, доходящие до 50000 кредитов. В игровом автомате используется пять цилиндров и двадцать линий. Нестабильность Secrets Of The Amazon сбалансированная, а теоретический уровень возврата составляет 95,3%. Главные особенности аппарата таковы:

  • возможность запустить максимум 20 бесплатных вращений;
  • экстра мультипликаторы максимум до x50 в течение фри-спинов;
  • иконки Wild, подменяющие другие картинки и удваивающие призы…

Автомат характеризуется привлекательным оформлением. Ролики вертятся на заднем плане тропических лесов. Игровой автомат был представлен более 10 лет назад, но благодаря поддержке HTML5 запускается не только на компьютерах, но и на всех новейших телефонах.

Интерфейс управления игры Secrets Of The Amazon расположена в основной секции экрана. На платформе находятся эти кнопки:

  • «Вклад» – настройка размера пари;
  • «Линия» – установка числа работающих линий;
  • «Autoplay» – включение автоматического вращения барабанов;
  • «Спин» – инициация катушек в стандартном моде.

В игровом автомате есть не только Дикий символ, но и разбросанный символ – чистый магический бутон. При 3 или больше Скаттеров, выпавших вместе, можно получить от 5 до 20 фриспинов. Конкретное количество FS устанавливается в конкретном пределах до их запуска. При выпадке пяти Scatter-символов во время призовых раскруток используется умножитель x50.

Данные о слоте Magical Stacks:

Игровой автомат Magical Stacks, имеющийся в игорном заведении Vulkan Royal, можно рекомендовать поклонникам аниме. Развлечение была представлена корпорацией Playtech в две тысячи шестнадцатом. Формат экрана игрового автомата – 5×3. В тайле используется 20 платежных линий и большие мультипликаторы, достигающие x2500 во время фриспинов. Финансовая отдача аппарата достигает 95,03%. У Magical Stacks широкий диапазон ставочек – от 0,01 до 2000 кредитов на раунд.

Во время вращения барабанов игровых автоматов на мониторе взамен отдельных знаков могут отображаться вопросительные знаки. По окончании вращения они трансформируются в произвольные картинки. Символов Диких в слоте 2. Одна из них (девчонка с розоватыми локонами) появляется на экране во время главной игры, а другая (блондинка с жезлом) – в ходе фриспинов.

Скаттер в заголовке – светлый котенок. 3 или свыше таких символа в момент одновременном появления запускают ряд бесплатных вращений. В случае, если во время исполнении призовых раскруток появляясь на пятом по счёту цилиндре выпадает золотой щит украшен розовым самоцветом, коэффициент умножения возрастает на одну единицу. Дополнительных вращений барабанов десять.

Некоторые иконок в Magical Stacks соответствует стилю игры – аниме. На цилиндрах также можно заметить звоночки вишенки, счастливые семёрки, арбуз. Панель контроля традиционно находится под барабанами. Расположена на ней имеются клавиши для изменения величины бета и количества игровых линий. Для старта следующего тура нужно кликнуть по «Spin». Для того чтобы активировать авто вращения роликов, нужно нажать по кнопке «Auto Play». В случае нажатии на клавишу «Info» на экране отображается перечень призов с информацией об применяемых в автомате иконках.

Автомат Fei Long Zai Tian

Аппарат Fei Long Zai Tian от Playtech ориентирован на Китаю периода Средневековья. В слоте предусмотрены бесплатные вращения, растущий символ Wild. Цифра активных линеек можно будет корректировать по вашему желанию (от 1 до 25). Финансовая возврат азартной игры на длинной перспективе достигает девяносто шесть целых три сотых процента. Катушки игры можно запускать мануально ли в автоматизированном формате. В параметрах автоигры предлагается выбрать предпочитаемое условие ее окончания, например, выпадение награды. Предельный величина выигрыша в Fei Long Zai Tian составляет x37500 от взноса.

Дикий символ (изумрудный дракон) может появиться на любом из катушек и весьма его заполнить. Дикий символ улучшает комбинации из типичных символов и увеличивает выплаты за них вдвойне. В Fei Long Zai Tian также имеется Scatter – перл с фениксом и змеем. Scatter-символы оплачиваются независимо от расположения на дисплее и приносят экстра множители.

При синхронном появлении на мониторе 3-х или более Scatter-символов инициируются фриспины. Пользователю выдается опция восемь попыток вращать барабаны, без вложений. В процессе фриспинов призы определяются с учетом дополнительного множителя x2. Игроку ещё предоставляется возможность определить бонусные жемчужины – 2 из 5. По исходу этого решения можно получить до 33 дополнительных фриспинов или повышенные множители бетсов – до x15. Каждые тройка или более иконок Scatter, выпадающие во время бонусного раунда, приносят по 15 фри-спинов. Наибольшее количество FS не имеет предела.

Сделана развлечение согласно тематикой. В фоновом фоне можно будет увидеть пейзаж утесов, водоема и неба. Анимирование символов легкая. Для управлять аппаратом предусмотрена консоль, размещенная под барабанами. На консоли находятся элементы управления для активации барабанов вручную и в автоигре, просмотра платежной таблицы, установки размера ставки и регулировки активных линий.

Чем выделяется слот Hot Gems?

Сюжет игрового автомата Hot Gems, известной в Вулкан игра – богатства. У тайтла такие особенности:

  • Возврат игроку: 95,99%;
  • число катушек: 5;
  • сумма линий: 25;
  • разброс взносов на раунд: от 0,25 до 25 очков.

В аппарате используется растущий мультипликатор бета. Вдобавок в игре реализовано цепное появление знаков: по окончании предоставления приза символы, создавшие выигрышную линию, разрушаются. На данных позицию вверх падают иные картинки, что ещё могут образовать выигрышное сочетание. Сумма побед способствуют увеличить символы Wild: они завершают наборы из каждых стандартных картинок.

На первичном, третичном и 5-м барабанах слота Hot Gems время от времени появляются символы Scatter. В случае синхронного появления 3-х аналогичных символов начинается 15 бесплатных вращений. Во момент бонусных спинов барабанов работает прогрессивный фактор экспоненциального роста. Во время расчета первоначального приза на ставке используется множитель x1. Далее это поднимается до x5. Предельный размер выигрыша в Hot Gems равен 37500 жетонов.

Стиль слота простое, а символы статичные. Изображения двигаются лишь при создании платных сочетаний. Катушки можно вращать вручную или в авто формате. Наибольшее количество автоспинов – 99. Нестабильность названия средне-нижняя. Данное указывает на то, что выплаты довольно внушительные, а выигрышные комбинации символов образуются регулярно.

Тайтл Age Of The Gods

Игровой автомат Age Of The Gods появился в интернет-казино с акциями в 2016 году и с тех пор не снижает популярности. У этой игры существенная финансовая рентабельность (95,02%), а выигрыши достигают 500000 монет. Персонажи слота – греческие мифологические божества. Название завлекает геймеров многоуровневым кушом. В развлечении также присутствует иконка Wild, обладающий большую значимость и субституирующий основные изображения.

Структура игрового поля автомата Age Of The Gods – 5×3. Линий выплат двадцать, и они фиксированные. В игровом автомате предусмотрена опция «Пантеон силы». Активируется игра в случае единовременном появлении на экране всех возможных символов божественных фигур. С активированием активации указанной функции пользователь выигрывает денежный приз, превышающее вклад в 10 раз.

Выигрыш в Age Of The Gods нарастающий и имеет четыре ступени. Величина призового пула постоянно возрастает за средства небольших отчислений со ставок участников. Выиграть главный приз возможно в любое время.

У развлечения Age Of The Gods лаконичное оформление. Панель управления обычно расположена в нижней секции экрана. Опции опций скромный: геймер может установить нужный размер ставки, вращать барабаны мануально или активировать автоспины.

Особый символ в слоте – Скаттер (обозначение с названием игрового процесса). При единовременном появлении 3 или больше таких изображений запускается 9 фриспинов. Прежде чем их запуска на экране возникает зона с 20 жетонами. Их следует открывать как угодно, для того чтобы обнаружить три идентичных изображения божества. В зависимости от героя, в течение фриспинов будет действовать одна из 4-х бонусных опций:

  1. Юпитер фиксирует на главном катушке расширенный иконку Wild.
  2. Богиня мудрости предоставляет экстра бустер начиная с x2 до x5.
  3. Геркулес-герой превращается в парный Вайлд.
  4. Бог морей раскрывает несколько случайных иконок и преобразует их в Wild-символы.

По окончании игры на мониторе вновь возникает поле с коинами. У геймера есть перспектива повторно выиграть бонусные спины, если выйдет обнаружить три идентичных иконки легендарного бога.

Какие моменты следует учесть о Buffalo Blitz: 1. Buffalo Blitz — это распространённый видеослот, который предоставляет геймерам захватывающий опыт. 2. В автомате используется шесть катушек и 4096 линий выплат. 3. Символы слота содержат животных, таких как бизоны, медведи и лоси. 4. Функция бесплатных вращений может быть активирована при выпадении трёх или более скаттеров. 5. В бонусном раунде можно получить до 100 фриспинов. 6. Игра имеет высокий уровень волатильности, что означает большие выигрыши, но реже.|Слот обладает высокой волатильностью, что подразумевает крупные выигрыши, но с меньшей частотой. 7. RTP (возврат игроку) составляет около 95.96%, что является стандартом для онлайн слотов.|RTP (процент возврата) составляет примерно 95.96%, что типично для видеослотов. Эти аспекты помогут вам лучше понять игру и насладиться ею в полной мере!

Слот Buffalo Blitz посвящен существам прерий: на катушках можно встретить буйволов, олений, мишек, и пум. У забавы нестандартное платформа (6×4), а выигрышные комбинации иконок образуются 4096 вариантами. Финансовая рентабельность слота очень высокая – 95,95%.

В опциях автоматической процесса слота Buffalo Blitz доступна опция Until Feature. При этой активации катушки крутятся до начала фриспинов. Бонусные раскрутки начинаются, если на дисплее вместе появляется три или более символов Free Games. На разовый раз удастся заполучить до 100 бесплатных вращений. На протяжении хода раунда раунды могут продолжаться.

Дикий в матче – алмаз. Этот выпадает на всех барабанах, за исключением первоначального, и дополняет наборы базовых иконок. На протяжении фриспинов Дикие символы включают дополнительные мультипликаторы в диапазоне от x2 до x5. Выигрышные наборы в аппарате образуются не только с левой части границы экрана. Для получения вознаграждения необходимо, чтобы рядом оказалось 3 или свыше аналогичных изображения. По завершению раунда можно выиграть выплату, выше чем вклад в 15360 раз.

Графика слота Buffalo Blitz достаточно лаконичная. Более тщательно всего изображено портрет зубра – главного персонажа развлечения. К тому же задействуется анимация ячеек, в которых случаются образуются выигрышные сочетания знаков. Чтобы включить ролики аппарата, нужно нажать на кнопку «Spin». Клавиша «Автоигра» предназначена для активации автоматического спина барабанов. Чтобы изучить таблицу выплат, требуется щелкнуть по клавише «Info».

Онлайн игровой автомат Fortunes Of The Fox

В две тысячи пятнадцатом году студия Playtech запустила слот Fortunes Of The Fox. Характеристики игры представлены ниже:

  • RTP: 95,11%;
  • численность линеек: 25;
  • число роликов: 5;
  • нестабильность: высокая.

Объем действующих линеек можно менять, применяя соответствующие элементы управления. Разброс ставок на раунд в матче – от 0,01 до 2500 кредитов. Победные наборы картинок создаются только на включенных строках. Для получения выигрыша требуется, чтобы в линию выстроилось тройка или больше одинаковых картинки (начиная с крайнего поля слева|от крайнего левого поля). При ставок при расчете вознаграждений используются мультипликаторы начиная с x5 вплоть до x5000. Если в результате спина на экране выпало ряд выигрышных вариантов символов, призы суммируются.

Основные символы слота Fortunes Of The Fox – егерь и его пес, палатка, кастрюля на огне и значения карт. Уникальных знаков двойка: Wild (лиса) и Scatter (виноград). Дикие символы встречаются лишь на трёх средних роликах. Эти заменяют основные символы, благодаря чему растет количество выигрышных комбинаций. При синхронном появлении троих иконок Wild инициируется раунд Bonfire Free Games – 15 безвозмездных спинов. Во момент данных выплаты троекратно увеличиваются. В обстоятельствах повторного появления троих Вайлдов дополнительные вращения продолжаются.

Символы Scatter выплачиваются независимо от позиции появляемости на игровом поле (при учете мультипликаторов до ста раз). Несколько или более знаков Scatter запускают Lucky Grapes Bonus – призовой раунд, запускающийся на отдельном экране. В Lucky Grapes Bonus нужно определить одну из пары гроздей виноградных ягод. Лиса соберёт это, после чего геймер получит приз.

Интерфейс развлечения стандартный. На доске контроля тайтла находятся элементы для установки числа включенных линеек и величины ставки, стартования роликов. В Fortunes Of The Fox можно запустить автоматический режим или применить опцией ускоренного кручения барабанов.

]]>
https://bragitrade.com/index.php/2025/05/02/playtech-dannye-o-kompanii-i-ego-produktah-dlja-55/feed/ 0