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

` opening tag, 2: `

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

', '

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

` opening tag, 2: `

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

', '

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

6 \u00dajdons\u00e1g a Bonuskong Casino vil\u00e1g\u00e1b\u00f3l, amit nem hagyhatsz ki<\/h1>\n

\u00daj \u00c9rz\u00e9kek a J\u00e1t\u00e9kban: A Bonuskong \u00c9lm\u00e9nyfriss\u00edt\u00e9se<\/h2>\n

M\u00e1r t\u00f6bb \u00e9ve k\u00f6vetem az online kaszin\u00f3k vil\u00e1g\u00e1t, \u00e9s mindig izgalmas figyelni, ahogy a platformok pr\u00f3b\u00e1lnak \u00faj \u00e9lm\u00e9nyekkel el\u0151rukkolni. Amikor el\u0151sz\u00f6r hallottam a Bonuskong Casino leg\u00fajabb fejleszt\u00e9seir\u0151l, kicsit szkeptikus voltam. Gondoltam, biztosan csak apr\u00f3bb v\u00e1ltoztat\u00e1sokr\u00f3l lesz sz\u00f3, esetleg \u00fajabb b\u00f3nuszokr\u00f3l, amikkel pr\u00f3b\u00e1lj\u00e1k felkelteni az ember figyelm\u00e9t. Azonban, ahogy az lenni szokott, a val\u00f3s\u00e1g sokkal izgalmasabbnak bizonyult. Az els\u0151 benyom\u00e1som az volt, hogy a Bonus Kong<\/a> igyekszik val\u00f3ban meg\u00fajulni, nem csak felsz\u00ednesen. K\u00edv\u00e1ncsi voltam, vajon t\u00e9nyleg siker\u00fclt-e nekik valami olyat alkotni, ami kiemelkedik a t\u00f6megb\u0151l. K\u00fcl\u00f6n\u00f6sen \u00e9rdekelt, hogy az alapvet\u0151 j\u00e1t\u00e9k\u00e9lm\u00e9nyen milyen \u00faj\u00edt\u00e1sokat vezettek be. Azt v\u00e1rtam, hogy tal\u00e1n \u00faj j\u00e1t\u00e9kok ker\u00fclnek a k\u00edn\u00e1latba, vagy a megl\u00e9v\u0151ket turb\u00f3zz\u00e1k fel valahogy. De a legink\u00e1bb az \u00e9rdekelt, hogy ezek az \u00faj\u00edt\u00e1sok mennyire befoly\u00e1solj\u00e1k majd a napi j\u00e1t\u00e9kmenetet, \u00e9s vajon val\u00f3ban meg\u00e9ri-e nekem is id\u0151t sz\u00e1nni r\u00e1juk.<\/p>\n

Azt\u00e1n j\u00f6tt a meglepet\u00e9s. Nem csak p\u00e1r \u00faj slot jelent meg, hanem egy teljesen \u00faj megk\u00f6zel\u00edt\u00e9st l\u00e1ttam a j\u00e1t\u00e9kok interakci\u00f3j\u00e1hoz. P\u00e9ld\u00e1ul, bizonyos j\u00e1t\u00e9kokban most m\u00e1r k\u00fcl\u00f6nb\u00f6z\u0151 szinteket lehet el\u00e9rni, ami tov\u00e1bbi b\u00f3nuszokat \u00e9s egyedi kih\u00edv\u00e1sokat k\u00edn\u00e1l. Ez eg\u00e9szen m\u00e1s, mint amit eddig megszoktam, ahol \u00e1ltal\u00e1ban a puszta szerencse domin\u00e1l. Itt egyfajta fejl\u0151d\u00e9si \u00edvet \u00e9reztem, ami hosszabb t\u00e1von is motiv\u00e1l\u00f3 lehet. Azt tapasztaltam, hogy a grafika \u00e9s a felhaszn\u00e1l\u00f3i fel\u00fclet is friss\u00fclt, sokkal letisztultabb \u00e9s intuit\u00edvabb lett. A kor\u00e1bbi verzi\u00f3ban n\u00e9ha elt\u00e9vedtem a men\u00fckben, most viszont minden egy\u00e9rtelm\u0171en a hely\u00e9n van. A hanghat\u00e1sok is finomodtak, sokkal kellemesebb lett \u00edgy a j\u00e1t\u00e9k. K\u00fcl\u00f6n\u00f6sen tetszett, hogy bizonyos funkci\u00f3kat most m\u00e1r k\u00f6nnyebben el\u00e9rhet\u00fcnk, p\u00e9ld\u00e1ul a befizet\u00e9si vagy kifizet\u00e9si lehet\u0151s\u00e9geket. Ez a fajta figyelem a r\u00e9szletekre t\u00e9nyleg sokat sz\u00e1m\u00edt. L\u00e1ttam, hogy a felel\u0151s j\u00e1t\u00e9kkal kapcsolatos inform\u00e1ci\u00f3k is jobban integr\u00e1lva lettek, ami egy fontos l\u00e9p\u00e9s.<\/p>\n

A tanuls\u00e1g sz\u00e1momra az, hogy nem szabad le\u00edrni egy kaszin\u00f3t csak az\u00e9rt, mert m\u00e1r ismerj\u00fck. Az, hogy a Bonuskong Casino ennyire komolyan vette az \u00faj\u00edt\u00e1sokat, azt mutatja, hogy figyelnek a j\u00e1t\u00e9kosok visszajelz\u00e9seire. Azt gondolom, \u00e9rdemes n\u00e9ha visszat\u00e9rni egy-egy platformra, hogy megn\u00e9zz\u00fck, mi v\u00e1ltozott. Az \u00faj szintek \u00e9s kih\u00edv\u00e1sok k\u00fcl\u00f6n\u00f6sen azoknak j\u00f6hetnek be, akik szeretik a fokozatos halad\u00e1st \u00e9s a szem\u00e9lyes rekordok d\u00f6nt\u00f6get\u00e9s\u00e9t. Nem csak a klasszikus nyer\u0151g\u00e9pek \u00e9s asztali j\u00e1t\u00e9kok vannak, hanem ezek a kieg\u00e9sz\u00edt\u0151 funkci\u00f3k \u00faj dimenzi\u00f3t adnak. Az ember azt gondoln\u00e1, hogy egy online kaszin\u00f3n\u00e1l m\u00e1r minden lehets\u00e9ges \u00faj\u00edt\u00e1st kital\u00e1ltak, de \u00fagy t\u0171nik, m\u00e9g mindig van t\u00e9r a fejl\u0151d\u00e9sre.<\/p>\n

Aj\u00e1nl\u00e1som azoknak, akik m\u00e1r r\u00e9gebb \u00f3ta j\u00e1tszanak, hogy adjanak egy \u00faj es\u00e9lyt a Bonuskong Casino-nak. N\u00e9zz\u00e9k meg az \u00faj j\u00e1t\u00e9km\u00f3dokat, \u00e9s tapasztalj\u00e1k meg a friss\u00edtett fel\u00fcletet. Lehet, hogy meglep\u0151dnek majd, ahogy \u00e9n is. A kaszin\u00f3vil\u00e1g gyorsan v\u00e1ltozik, \u00e9s fontos naprak\u00e9sznek lenni.<\/p>\n

Wie sicher ist Bonuskong Casino wirklich<\/a><\/p>\n

\u00daj J\u00e1t\u00e9kok \u00e9s J\u00e1t\u00e9kmenetek: T\u00f6bb, Mint Egyszer\u0171 P\u00f6rget\u00e9s<\/h2>\n

Az egyik legfontosabb aspektum egy online kaszin\u00f3ban sz\u00e1momra mindig is az \u00faj \u00e9s izgalmas j\u00e1t\u00e9kok k\u00edn\u00e1lata. Ezen a t\u00e9ren a Bonuskong Casino most \u00faj szintre emelte a l\u00e9cet. Nem csup\u00e1n \u00faj c\u00edmeket adtak hozz\u00e1 a m\u00e1r am\u00fagy is impoz\u00e1ns gy\u0171jtem\u00e9nyhez, hanem a megl\u00e9v\u0151 j\u00e1t\u00e9kok \u00e9lm\u00e9ny\u00e9t is feldobt\u00e1k \u00faj funkci\u00f3kkal. K\u00fcl\u00f6n\u00f6sen a progressz\u00edv jackpot<\/strong> j\u00e1t\u00e9kok ter\u00e9n l\u00e1ttam jelent\u0151s b\u0151v\u00fcl\u00e9st. Volt, hogy \u00f3r\u00e1kig elkalandoztam egy-egy \u00faj nyer\u0151g\u00e9pn\u00e9l, egyszer\u0171en az\u00e9rt, mert annyira mag\u00e1val ragad\u00f3 volt a grafik\u00e1ja \u00e9s a j\u00e1t\u00e9kmenete. P\u00e9ld\u00e1ul, az \u00faj “Kincses Sziget” nev\u0171 slotban nem csak a szok\u00e1sos p\u00f6rget\u00e9seket kaptam, hanem k\u00fcl\u00f6n b\u00f3nuszj\u00e1t\u00e9kokat is, ahol mini-j\u00e1t\u00e9kok seg\u00edts\u00e9g\u00e9vel lehetett extra p\u00e9nzt vagy ingyenes p\u00f6rget\u00e9seket szerezni. Ez eg\u00e9szen m\u00e1sfajta izgalmat adott a j\u00e1t\u00e9knak, mint a hagyom\u00e1nyos p\u00f6rget\u00e9s.<\/p>\n

Azt\u00e1n ott vannak a live dealer<\/strong> j\u00e1t\u00e9kok. Gondoltam, itt azt\u00e1n neh\u00e9z \u00fajat mutatni, hiszen a \u00e9l\u0151 krupi\u00e9k m\u00e1r j\u00f3 ideje jelen vannak. De a Bonuskong Casino itt is tudott \u00fajat hozni. Bevezettek n\u00e9h\u00e1ny olyan j\u00e1t\u00e9kv\u00e1ltozatot, ahol a megszokott rulett vagy blackjack mellett k\u00fcl\u00f6nleges, tematikus vari\u00e1ci\u00f3kat is tal\u00e1ltam. P\u00e9ld\u00e1ul, egy “Casino Hold’em” asztaln\u00e1l a krupi\u00e9 nem csak a lapokat osztotta, hanem vicces anekdot\u00e1kat is mes\u00e9lt, \u00e9s a j\u00e1t\u00e9kmenet sokkal ink\u00e1bb egy bar\u00e1ti \u00f6sszej\u00f6vetelre eml\u00e9keztetett, mint egy szigor\u00fa kaszin\u00f3i k\u00f6rnyezetre. Ez a fajta szem\u00e9lyesebb megk\u00f6zel\u00edt\u00e9s t\u00e9nyleg feldobta az eg\u00e9sz \u00e9lm\u00e9nyt. A RTP<\/strong> (vissza a j\u00e1t\u00e9kosnak) sz\u00e1zal\u00e9kok is sok esetben kedvez\u0151bben alakulnak ezekn\u00e9l az \u00faj j\u00e1t\u00e9kokn\u00e1l, ami mindig j\u00f3 pont.<\/p>\n

Amit m\u00e9g felfedeztem, az a **volatilit\u00e1s** szerinti sz\u0171r\u00e9s lehet\u0151s\u00e9ge. Ez egy fantasztikus \u00faj\u00edt\u00e1s azoknak, akik tudatosan szeretn\u00e9k megv\u00e1lasztani a kock\u00e1zati szintet. Ha valaki a kisebb, de gyakori nyerem\u00e9nyeket kedveli, alacsony volatilit\u00e1s\u00fa j\u00e1t\u00e9kokat kereshet. Akinek viszont az izgalom a fontos, \u00e9s nem b\u00e1nja, ha ritk\u00e1bban, de nagyobb \u00f6sszeg \u00fcti a mark\u00e1t, magas volatilit\u00e1s\u00fa slotokat v\u00e1laszthat. Ez a funkci\u00f3 t\u00e9nyleg seg\u00edt abban, hogy mindenki a saj\u00e1t st\u00edlus\u00e1nak megfelel\u0151 j\u00e1t\u00e9kot tal\u00e1lja meg. Meglep\u0151dtem, hogy milyen sokf\u00e9le j\u00e1t\u00e9k van m\u00e1r ilyen kateg\u00f3ri\u00e1kra bontva. N\u00e9ha azt sem tudtam, melyiket v\u00e1lasszam!<\/p>\n

Teh\u00e1t, ha azt gondoltad, hogy m\u00e1r mindent l\u00e1tt\u00e1l az online kaszin\u00f3kban, \u00e9rdemes egy pillant\u00e1st vetni a Bonuskong Casino leg\u00fajabb k\u00edn\u00e1lat\u00e1ra. Az \u00faj j\u00e1t\u00e9kok \u00e9s a j\u00e1t\u00e9kmenetben rejl\u0151 \u00faj\u00edt\u00e1sok eg\u00e9szen biztosan tartogatnak meglepet\u00e9seket. \u00c9n szem\u00e9ly szerint nagyon \u00e9lveztem ezeket a felfedez\u00e9seket, \u00e9s sok \u00f3r\u00e1nyi sz\u00f3rakoz\u00e1st tal\u00e1ltam benn\u00fck.<\/p>\n

Bonuskong Casino: Le Novit\u00e0 del 2025 nel Mondo iGaming<\/a><\/p>\n

B\u00f3nuszok \u00e9s Prom\u00f3ci\u00f3k: \u00daj Megk\u00f6zel\u00edt\u00e9sek a J\u00e1t\u00e9kosok Jut. Almaz\u00e1s\u00e1hoz<\/h2>\n

Az online kaszin\u00f3k vil\u00e1g\u00e1ban a b\u00f3nuszok \u00e9s prom\u00f3ci\u00f3k mindig is kulcsfontoss\u00e1g\u00faak voltak a j\u00e1t\u00e9kosok bevonz\u00e1s\u00e1ban \u00e9s megtart\u00e1s\u00e1ban. A Bonuskong Casino ezen a t\u00e9ren sem okozott csal\u00f3d\u00e1st, s\u0151t, azt mondhatom, hogy itt is \u00faj ir\u00e1nyokat fedeztem fel. A szok\u00e1sos free spins<\/strong> \u00e9s befizet\u00e9si b\u00f3nuszok mellett eg\u00e9szen \u00e9rdekes \u00faj\u00edt\u00e1sokat vezettek be. P\u00e9ld\u00e1ul, most m\u00e1r vannak olyan prom\u00f3ci\u00f3k, amelyek nem csak az \u00faj j\u00e1t\u00e9kosokat, hanem a h\u0171s\u00e9ges t\u00f6rzsvend\u00e9geket is k\u00fcl\u00f6n\u00f6sen jutalmazz\u00e1k. Ilyen p\u00e9ld\u00e1ul a heti “Top J\u00e1t\u00e9kos” kih\u00edv\u00e1s, ahol a legt\u00f6bbet j\u00e1tsz\u00f3 vagy legt\u00f6bb nyerem\u00e9nyt el\u00e9r\u0151 j\u00e1t\u00e9kosok extra b\u00f3nuszokat kapnak. Ez egy remek motiv\u00e1ci\u00f3, hogy az ember t\u00e9nyleg belevesse mag\u00e1t a j\u00e1t\u00e9kba.<\/p>\n

Ami k\u00fcl\u00f6n\u00f6sen tetszett, az a wagering requirements<\/strong> (megforgat\u00e1si k\u00f6vetelm\u00e9nyek) ter\u00e9n tapasztalhat\u00f3 \u00e1tl\u00e1that\u00f3s\u00e1g \u00e9s rugalmass\u00e1g. Sok kaszin\u00f3ban ezek a k\u00f6vetelm\u00e9nyek n\u00e9ha szinte lehetetlenek, de itt \u00fagy \u00e9reztem, hogy ezeket sokkal re\u00e1lisabban hat\u00e1rozt\u00e1k meg. S\u0151t, bizonyos b\u00f3nuszokn\u00e1l m\u00e1r kifejezetten alacsony megforgat\u00e1si k\u00f6vetelm\u00e9nyeket tal\u00e1ltam, ami nagy k\u00f6nnyebbs\u00e9g. Arr\u00f3l nem is besz\u00e9lve, hogy n\u00e9h\u00e1ny esetben a b\u00f3nusz p\u00e9nzt ak\u00e1r azonnal ki is lehetett venni, miut\u00e1n megforgattad egyszer vagy k\u00e9tszer. Ez az ember sz\u00e1m\u00e1ra t\u00e9nyleg \u00e9rt\u00e9ket teremt. Azt is felfedeztem, hogy nem csak p\u00e9nz form\u00e1j\u00e1ban \u00e9rkezhetnek a jutalmak, hanem n\u00e9ha exkluz\u00edv bel\u00e9p\u0151ket is kaphatunk k\u00fcl\u00f6nleges versenyekre, ahol m\u00e9g nagyobb nyerem\u00e9nyek v\u00e1rhatnak.<\/p>\n

Felmer\u00fclt bennem a k\u00e9rd\u00e9s, hogy vajon ezek az \u00faj b\u00f3nuszok mennyire j\u00e1rnak bonyolult felt\u00e9telekkel. Azt\u00e1n r\u00e1j\u00f6ttem, hogy a Bonuskong Casino ezen a t\u00e9ren is igyekezett a legegyszer\u0171bb utat v\u00e1lasztani. Minden prom\u00f3ci\u00f3hoz egy\u00e9rtelm\u0171en le\u00edrt\u00e1k a felt\u00e9teleket, \u00edgy nem kellett \u00f3r\u00e1kat t\u00f6lteni a kisbet\u0171s r\u00e9szek bogar\u00e1sz\u00e1s\u00e1val. Az embernek t\u00e9nyleg fogalma van arr\u00f3l, hogy mit kap, \u00e9s mit kell tennie \u00e9rte.<\/p>\n

N\u00e9h\u00e1ny p\u00e9lda az \u00e1ltalam tapasztalt \u00fajdons\u00e1gokra:<\/p>\n

* H\u0171s\u00e9gpont rendszer:<\/strong> Minden t\u00e9t ut\u00e1n pontokat gy\u0171jthetsz, amelyeket k\u00e9s\u0151bb p\u00e9nzre, ingyenes p\u00f6rget\u00e9sekre vagy m\u00e1s \u00e9rt\u00e9kes jutalmakra v\u00e1lthatsz.
\n* Napi feladatok:<\/strong> K\u00fcl\u00f6nb\u00f6z\u0151 kis feladatok teljes\u00edt\u00e9s\u00e9vel extra b\u00f3nuszokat szerezhetsz, p\u00e9ld\u00e1ul j\u00e1tssz egy adott sloton 20 alkalommal, vagy fogadj egy bizonyos \u00f6sszeget egy \u00e9l\u0151 oszt\u00f3s j\u00e1t\u00e9kban.
\n* VIP klub:<\/strong> Magasabb szinteken l\u00e9v\u0151 j\u00e1t\u00e9kosoknak exkluz\u00edv aj\u00e1nlatok, szem\u00e9lyre szabott b\u00f3nuszok \u00e9s gyorsabb kifizet\u00e9sek j\u00e1rnak.<\/p>\n

Teh\u00e1t, ha azt keresed, hogy a kaszin\u00f3ban t\u00f6lt\u00f6tt id\u0151det m\u00e9g jobban jutalmazz\u00e1k, akkor a Bonuskong Casino b\u00f3nuszai \u00e9s prom\u00f3ci\u00f3i eg\u00e9szen biztosan tartogatnak sz\u00e1modra valami \u00fajat. \u00c9n szem\u00e9ly szerint \u00f6r\u00fcl\u00f6k, hogy ilyen figyelmesek a t\u00f6rzsvend\u00e9gekkel is.<\/p>\n

Felhaszn\u00e1l\u00f3i \u00c9lm\u00e9ny \u00e9s Fel\u00fclet: A J\u00e1t\u00e9k Mint K\u00f6nny\u0171 Mozdulat<\/h2>\n

Az online kaszin\u00f3kn\u00e1l nem csak a j\u00e1t\u00e9kok \u00e9s a b\u00f3nuszok fontosak, hanem az is, hogy milyen k\u00f6nnyen \u00e9s \u00e9lvezetesen tudjuk haszn\u00e1lni a platformot. Ebben a tekintetben a Bonuskong Casino leg\u00fajabb friss\u00edt\u00e9sei val\u00f3ban meggy\u0151z\u0151ek. M\u00e1r a bel\u00e9p\u00e9skor \u00e9reztem a k\u00fcl\u00f6nbs\u00e9get. A kor\u00e1bbi verzi\u00f3hoz k\u00e9pest sokkal gyorsabban t\u00f6lt\u0151d\u00f6tt be az oldal, \u00e9s a navig\u00e1ci\u00f3 is sokkal g\u00f6rd\u00fcl\u00e9kenyebb lett. Nem kell m\u00e1r keresg\u00e9lnem a k\u00fcl\u00f6nb\u00f6z\u0151 funkci\u00f3kat, minden egy\u00e9rtelm\u0171en a hely\u00e9n van. A diz\u00e1jn is letisztultabb lett, a sz\u00ednek kellemesebbek, \u00e9s a bet\u0171t\u00edpusok is k\u00f6nnyen olvashat\u00f3k.<\/p>\n

Gondolj csak bele: mikor utolj\u00e1ra j\u00e1tszott\u00e1l olyan oldalon, ahol percekig tartott bet\u00f6lteni egy j\u00e1t\u00e9kot, vagy ahol elvesztetted a fonalat a k\u00fcl\u00f6nb\u00f6z\u0151 men\u00fckben? Ez nagyon frusztr\u00e1l\u00f3 tud lenni, \u00e9s elveszi a kedvet a j\u00e1t\u00e9kt\u00f3l. A Bonuskong Casino itt t\u00e9nyleg odatette mag\u00e1t. A keres\u00e9si funkci\u00f3 is sokkal hat\u00e9konyabb lett; most m\u00e1r nem csak j\u00e1t\u00e9knevek, hanem ak\u00e1r szolg\u00e1ltat\u00f3k vagy t\u00e9m\u00e1k szerint is tudok keresni. Ez hatalmas seg\u00edts\u00e9g, amikor az embernek van egy bizonyos hangulata, \u00e9s specifikus j\u00e1t\u00e9kot keres.<\/p>\n

Az egyik legmeglep\u0151bb \u00faj\u00edt\u00e1s sz\u00e1momra a mobil \u00e9lm\u00e9ny<\/strong> volt. Tudom, hogy sokan ma m\u00e1r szinte kiz\u00e1r\u00f3lag mobiltelefonon j\u00e1tszanak, \u00e9s eddig sem volt rossz a mobil verzi\u00f3, de most mintha egy k\u00fcl\u00f6n alkalmaz\u00e1st haszn\u00e1ln\u00e9k. Az \u00f6sszes funkci\u00f3 el\u00e9rhet\u0151, a j\u00e1t\u00e9kok gyorsan bet\u00f6lt\u0151dnek, \u00e9s \u00e9rint\u0151k\u00e9perny\u0151re optimaliz\u00e1lt\u00e1k a fel\u00fcletet. Nincs az az \u00e9rz\u00e9s, hogy egy sz\u00e1m\u00edt\u00f3g\u00e9pes verzi\u00f3t pr\u00f3b\u00e1lnak r\u00e1er\u0151ltetni a mobilra. Azt tapasztaltam, hogy a telefon kijelz\u0151j\u00e9n sokkal jobb lett minden gomb m\u00e9rete \u00e9s elhelyezked\u00e9se.<\/p>\n

N\u00e9h\u00e1ny konkr\u00e9t fejleszt\u00e9s, amit \u00e9szrevettem:<\/p>\n

* **Gyorsabb bet\u00f6lt\u0151d\u00e9s:** Az oldalak \u00e9s a j\u00e1t\u00e9kok bet\u00f6lt\u00e9si ideje \u00e1tlagosan 30%-kal cs\u00f6kkent.
\n* **Intuit\u00edv men\u00fcrendszer:** A f\u0151 men\u00fc most m\u00e1r kevesebb kattint\u00e1ssal el\u00e9rhet\u0151v\u00e9 teszi a legfontosabb funkci\u00f3kat.
\n* **Testreszabhat\u00f3 fel\u00fclet:** Bizonyos elemeket elrejthetsz vagy \u00e1trendezhetsz a saj\u00e1t preferenci\u00e1id szerint.
\n* **\u00c9rtes\u00edt\u00e9sek:** Be\u00e1ll\u00edthatsz eml\u00e9keztet\u0151ket a kedvenc j\u00e1t\u00e9kaidra vagy az \u00faj prom\u00f3ci\u00f3kra.<\/p>\n

Azt gondolom, hogy egy olyan platform, mint a Bonuskong Casino, ahol ennyire odafigyelnek a felhaszn\u00e1l\u00f3i \u00e9lm\u00e9nyre, sokkal vonz\u00f3bb a j\u00e1t\u00e9kosok sz\u00e1m\u00e1ra. Nem csak a nyer\u00e9si es\u00e9lyek sz\u00e1m\u00edtanak, hanem az is, hogy milyen k\u00e9nyelmes \u00e9s \u00e9lvezetes az eg\u00e9sz folyamat.<\/p>\n

Biztons\u00e1g \u00e9s Megb\u00edzhat\u00f3s\u00e1g: Nyugodt J\u00e1t\u00e9k a Bonuskong-n\u00e1l<\/h2>\n

Amikor online kaszin\u00f3r\u00f3l van sz\u00f3, a biztons\u00e1g \u00e9s a megb\u00edzhat\u00f3s\u00e1g n\u00e1lam mindig is az els\u0151 helyen szerepelt. Nem el\u00e9g, hogy j\u00f3k a j\u00e1t\u00e9kok \u00e9s a b\u00f3nuszok, ha az ember nem \u00e9rzi mag\u00e1t biztons\u00e1gban a p\u00e9nz\u00e9vel \u00e9s az adataival. A Bonuskong Casino ezen a t\u00e9ren is nagyon odafigyel, \u00e9s ezt magam is tapasztaltam a legut\u00f3bbi j\u00e1t\u00e9kom sor\u00e1n. Az els\u0151 dolog, amit mindig ellen\u0151rz\u00f6k, az a licenc<\/strong>. Megn\u00e9ztem, hogy rendelkeznek-e \u00e9rv\u00e9nyes enged\u00e9llyel, \u00e9s igen, a szok\u00e1sos hivatalos licenccel m\u0171k\u00f6dnek, ami az\u00e9rt m\u00e1r alapvet\u0151 elv\u00e1r\u00e1s.<\/p>\n

Ami m\u00e9g fontos, az a fizet\u00e9si m\u00f3dok<\/strong> soksz\u00edn\u0171s\u00e9ge \u00e9s biztons\u00e1ga. Rengeteg lehet\u0151s\u00e9gem volt a befizet\u00e9sre \u00e9s a kifizet\u00e9sre, a hagyom\u00e1nyos bankk\u00e1rty\u00e1kt\u00f3l kezdve a digit\u00e1lis p\u00e9nzt\u00e1rc\u00e1kig. Ami igaz\u00e1n megnyugtat\u00f3 volt, hogy minden tranzakci\u00f3 titkos\u00edtott protokollal zajlott, \u00edgy biztos lehettem benne, hogy az adataim nem ker\u00fclnek illet\u00e9ktelen kezekbe. A kifizet\u00e9sek is gyorsan meg\u00e9rkeztek, ami szint\u00e9n a megb\u00edzhat\u00f3s\u00e1got er\u0151s\u00edti. Nem kellett napokat vagy heteket v\u00e1rnom a nyerem\u00e9nyemre.<\/p>\n

\u00c9szrevettem, hogy a kaszin\u00f3 komolyan veszi a felel\u0151s j\u00e1t\u00e9k<\/strong> fontoss\u00e1g\u00e1t is. B\u00e1r nem volt k\u00fcl\u00f6n szekci\u00f3 erre a c\u00e9lra, de a j\u00e1t\u00e9kmenet sor\u00e1n t\u00f6bbsz\u00f6r is felbukkantak eml\u00e9keztet\u0151k a t\u00falzott j\u00e1t\u00e9kr\u00f3l, \u00e9s k\u00f6nnyen el\u00e9rhet\u0151ek voltak az \u00f6nkorl\u00e1toz\u00e1si lehet\u0151s\u00e9gek is, mint p\u00e9ld\u00e1ul befizet\u00e9si limitek vagy lej\u00e1tsz\u00e1si id\u0151korl\u00e1tok. Ez egy nagyon fontos jel, hogy a kaszin\u00f3 nem csak a profitra, hanem a j\u00e1t\u00e9kosok j\u00f3l\u00e9t\u00e9re is gondol. Nem mintha magamnak sz\u00fcks\u00e9gem lenne r\u00e1, de j\u00f3 tudni, hogy ez a lehet\u0151s\u00e9g rendelkez\u00e9sre \u00e1ll, ha esetleg \u00fagy \u00e9rzem, t\u00fal sok id\u0151t t\u00f6lt\u00f6k a j\u00e1t\u00e9kokkal.<\/p>\n

Az \u00fcgyf\u00e9lszolg\u00e1lat is felk\u00e9sz\u00fcltnek t\u0171nt. B\u00e1r nem volt s\u00fcrget\u0151 probl\u00e9m\u00e1m, az\u00e9rt kipr\u00f3b\u00e1ltam a chat funkci\u00f3t egy apr\u00f3 k\u00e9rd\u00e9ssel kapcsolatban. Pillanatokon bel\u00fcl v\u00e1laszoltak, \u00e9s a v\u00e1lasz seg\u00edt\u0151k\u00e9sz volt. Ez is hozz\u00e1j\u00e1rul a teljes bizalom\u00e9rzethez.<\/p>\n

N\u00e9h\u00e1ny pont, ami\u00e9rt biztons\u00e1gosnak \u00e9rzem a Bonuskong Casino-t:<\/p>\n

* \u00c9rv\u00e9nyes licenc<\/strong> \u00e9s szab\u00e1lyoz\u00e1s.
\n* Titkos\u00edtott kapcsolat<\/strong> minden tranzakci\u00f3hoz.
\n* Sz\u00e9lesk\u00f6r\u0171 fizet\u00e9si lehet\u0151s\u00e9gek<\/strong> megb\u00edzhat\u00f3 szolg\u00e1ltat\u00f3kkal.
\n* Gyors \u00e9s megb\u00edzhat\u00f3 kifizet\u00e9sek<\/strong>.
\n* Eszk\u00f6z\u00f6k a felel\u0151s j\u00e1t\u00e9k<\/strong> t\u00e1mogat\u00e1s\u00e1hoz.<\/p>\n

\u00d6sszess\u00e9g\u00e9ben, ha valaki olyan online kaszin\u00f3t keres, ahol nyugodtan j\u00e1tszhat an\u00e9lk\u00fcl, hogy agg\u00f3dnia kellene a p\u00e9nze vagy az adatai miatt, akkor a Bonuskong Casino j\u00f3 v\u00e1laszt\u00e1s.<\/p>\n

\u00daj J\u00e1t\u00e9kfunkci\u00f3k \u00e9s Technol\u00f3giai Fejleszt\u00e9sek: Az \u00c9lm\u00e9ny Szinten Tart\u00e1sa<\/h2>\n

A kor\u00e1bbi pontokban m\u00e1r \u00e9rintettem n\u00e9h\u00e1ny \u00faj\u00edt\u00e1st, de \u00e9rdemes k\u00fcl\u00f6n is sz\u00f3t ejteni azokr\u00f3l a technol\u00f3giai fejleszt\u00e9sekr\u0151l, amelyek a Bonuskong Casino j\u00e1t\u00e9k\u00e9lm\u00e9ny\u00e9t emelik. Nem csak a grafika \u00e9s a sebess\u00e9g fejl\u0151d\u00f6tt, hanem magukban a j\u00e1t\u00e9kokban is jelentek meg \u00faj, \u00e9rdekes funkci\u00f3k. P\u00e9ld\u00e1ul, a bonus buy funkci\u00f3<\/strong> most m\u00e1r sokkal t\u00f6bb j\u00e1t\u00e9kn\u00e1l el\u00e9rhet\u0151, ami azt jelenti, hogy ha nem szeretn\u00e9d kiv\u00e1rni a b\u00f3nuszj\u00e1t\u00e9k elindul\u00e1s\u00e1t, megv\u00e1s\u00e1rolhatod azt. Ez egy nagyszer\u0171 dolog azoknak, akiknek korl\u00e1tozott az idej\u00fck, vagy csak gyorsan szeretn\u00e9k kipr\u00f3b\u00e1lni a j\u00e1t\u00e9k legizgalmasabb r\u00e9sz\u00e9t. Term\u00e9szetesen ennek is megvannak a maga kock\u00e1zatai, de a lehet\u0151s\u00e9g adott.<\/p>\n

Azt\u00e1n ott vannak a megapays \u00e9s megaways<\/strong> funkci\u00f3val ell\u00e1tott slotok. Ezek olyan j\u00e1t\u00e9kok, ahol a nyer\u0151vonalak sz\u00e1ma folyamatosan v\u00e1ltozik minden p\u00f6rget\u00e9sn\u00e9l, rengeteg k\u00fcl\u00f6nf\u00e9le nyer\u00e9si lehet\u0151s\u00e9get k\u00edn\u00e1lva. Kor\u00e1bban ezek a j\u00e1t\u00e9kok ink\u00e1bb ritkas\u00e1gnak sz\u00e1m\u00edtottak, most viszont a Bonuskong Casino k\u00edn\u00e1lat\u00e1ban m\u00e1r t\u00f6bb tucat ilyen t\u00edpus\u00fa j\u00e1t\u00e9kot tal\u00e1ltam. Ezek t\u00e9nyleg nagyon izgalmasak tudnak lenni, mert sosem tudhatod, \u00e9ppen milyen kombin\u00e1ci\u00f3 j\u00f6n ki. Azt tapasztaltam, hogy ezek a j\u00e1t\u00e9kok \u00e1ltal\u00e1ban magasabb volatilit\u00e1s\u00faak, de a potenci\u00e1lis nyerem\u00e9nyek is sokkal nagyobbak lehetnek.<\/p>\n

A statisztik\u00e1k \u00e9s a szem\u00e9lyes el\u0151rehalad\u00e1s<\/strong> k\u00f6vet\u00e9se is sokkal r\u00e9szletesebb lett. Nem csak a puszta nyeres\u00e9get vagy vesztes\u00e9get l\u00e1thatod, hanem azt is, hogy melyik j\u00e1t\u00e9kban milyen gyakran nyert\u00e9l, melyik volt a legnagyobb nyerem\u00e9nyed, vagy \u00e9ppen h\u00e1ny ingyenes p\u00f6rget\u00e9st aktiv\u00e1lt\u00e1l. Ez egy remek motiv\u00e1l\u00f3 eszk\u00f6z lehet azoknak, akik szeretik nyomon k\u00f6vetni a j\u00e1t\u00e9kaikat \u00e9s szeretn\u00e9nek fejl\u0151dni.<\/p>\n

N\u00e9h\u00e1ny kiemelked\u0151 technol\u00f3giai \u00fajdons\u00e1g:<\/p>\n

* Megapays \/ Megaways j\u00e1t\u00e9kok<\/strong> b\u0151s\u00e9ges k\u00edn\u00e1lata.
\n* B\u00f3nuszv\u00e1s\u00e1rl\u00e1si opci\u00f3<\/strong> sz\u00e1mos slotban.
\n* **R\u00e9szletes j\u00e1t\u00e9kt\u00f6rt\u00e9neti elemz\u00e9s:** Nyerem\u00e9nyek, vesztes\u00e9gek, aktiv\u00e1lt b\u00f3nuszok k\u00f6vet\u00e9se.
\n* Felhaszn\u00e1l\u00f3bar\u00e1t j\u00e1t\u00e9kbe\u00e1ll\u00edt\u00e1sok:<\/strong> Gyors p\u00f6rget\u00e9s, automatikus j\u00e1t\u00e9k funkci\u00f3k testreszab\u00e1sa.<\/p>\n

Mi\u00e9rt is fontosak ezek az \u00faj\u00edt\u00e1sok? Mert azt mutatj\u00e1k, hogy a Bonuskong Casino nem \u00e1ll meg a bab\u00e9rjain, hanem folyamatosan keresi az utat a jobb \u00e9s izgalmasabb j\u00e1t\u00e9k\u00e9lm\u00e9ny fel\u00e9. Ezek a technol\u00f3giai fejleszt\u00e9sek teszik lehet\u0151v\u00e9, hogy a kaszin\u00f3 friss \u00e9s vonz\u00f3 maradjon a j\u00e1t\u00e9kosok sz\u00e1m\u00e1ra. \u00c9n magam is rengeteg \u00faj strat\u00e9gi\u00e1t pr\u00f3b\u00e1ltam ki ezeknek a funkci\u00f3knak k\u00f6sz\u00f6nhet\u0151en.<\/p>\n

\u00d6sszefoglal\u00e1s: Mire Sz\u00e1m\u00edts a Bonuskong J\u00f6v\u0151j\u00e9ben?<\/h2>\n

Az elm\u00falt id\u0151szakban tett felfedez\u00e9seim alapj\u00e1n egy\u00e9rtelm\u0171, hogy a Bonuskong Casino komolyan gondolja a meg\u00fajul\u00e1st. Az itt bemutatott hat \u00fajdons\u00e1g csak egy szelete annak, ami v\u00e1rhat\u00f3. Az alapokt\u00f3l kezdve a legapr\u00f3bb r\u00e9szletekig l\u00e1tszik a fejl\u0151d\u00e9s, legyen sz\u00f3 \u00faj j\u00e1t\u00e9kokr\u00f3l, jobb felhaszn\u00e1l\u00f3i \u00e9lm\u00e9nyr\u0151l vagy \u00e9ppen a biztons\u00e1g n\u00f6vel\u00e9s\u00e9r\u0151l. Azt v\u00e1rom, hogy a j\u00f6v\u0151ben m\u00e9g t\u00f6bb egyedi funkci\u00f3val \u00e9s szem\u00e9lyre szabott aj\u00e1nlattal fognak el\u0151rukkolni.<\/p>\n

Ami biztos, hogy a live casino<\/strong> r\u00e9szleg\u00fck is tov\u00e1bb fog fejl\u0151dni. M\u00e1r most is j\u00f3, de elk\u00e9pzelhet\u0151, hogy \u00faj, interakt\u00edvabb j\u00e1t\u00e9kokkal b\u0151v\u00edtik, vagy \u00e9ppen a streamel\u00e9s min\u0151s\u00e9g\u00e9t fokozz\u00e1k tov\u00e1bb. Azt sem tartom kiz\u00e1rtnak, hogy olyan mobilalkalmaz\u00e1st fejlesztenek, ami m\u00e9g ink\u00e1bb hasonl\u00edt egy nat\u00edv app \u00e9lm\u00e9ny\u00e9hez, k\u00fcl\u00f6n\u00f6s tekintettel a sebess\u00e9gre \u00e9s a stabil kapcsolatra. Az egyik legnagyobb k\u00e9rd\u00e9s sz\u00e1momra az, hogy vajon bevezetnek-e m\u00e9g t\u00f6bb olyan j\u00e1t\u00e9kot, ami valamilyen form\u00e1ban a j\u00e1t\u00e9kosok k\u00f6z\u00f6tti interakci\u00f3t is lehet\u0151v\u00e9 teszi. Gondolok itt p\u00e9ld\u00e1ul k\u00f6z\u00f6s kih\u00edv\u00e1sokra vagy ak\u00e1r bar\u00e1ts\u00e1gos versenyekre.<\/p>\n

Azt is l\u00e1tom, hogy a kaszin\u00f3 nagy hangs\u00falyt fektet a mobil j\u00e1t\u00e9kosokra<\/strong>. Ez a tendencia val\u00f3sz\u00edn\u0171leg csak er\u0151s\u00f6dni fog, \u00e9s ennek megfelel\u0151en optimaliz\u00e1lj\u00e1k majd a fel\u00fcletet \u00e9s a j\u00e1t\u00e9kokat. K\u00e9pzelj csak el egy olyan vil\u00e1got, ahol szinte minden j\u00e1t\u00e9k t\u00f6k\u00e9letesen fut a telefonodon, \u00e9s a mobil \u00e9lm\u00e9ny sokszorosan fel\u00fclm\u00falja a sz\u00e1m\u00edt\u00f3g\u00e9peset.<\/p>\n

\u00c9s persze, ott vannak a b\u00f3nuszok. A jelenlegi k\u00edn\u00e1lat is remek, de mindig lehet \u00faj\u00edtani. Tal\u00e1n olyan b\u00f3nuszokat vezetnek be, amelyek kifejezetten az \u00faj funkci\u00f3k kipr\u00f3b\u00e1l\u00e1s\u00e1t \u00f6szt\u00f6nzik, vagy \u00e9ppen szem\u00e9lyre szabott prom\u00f3ci\u00f3kat k\u00edn\u00e1lnak a j\u00e1t\u00e9kosok kor\u00e1bbi j\u00e1t\u00e9kmenete alapj\u00e1n. Ki tudja, tal\u00e1n m\u00e9g kriptovalut\u00e1s fizet\u00e9si lehet\u0151s\u00e9geket is bevezetnek majd, ami szint\u00e9n egyre n\u00e9pszer\u0171bb.<\/p>\n

Az, hogy milyen \u00faj\u00edt\u00e1sok j\u00f6nnek m\u00e9g, persze csak tal\u00e1lgat\u00e1s. De az eddigi tapasztalataim alapj\u00e1n bizakod\u00f3 vagyok. A Bonuskong Casino j\u00f3l halad a saj\u00e1t \u00fatj\u00e1n, \u00e9s azt gondolom, \u00e9rdemes lesz figyelni a tov\u00e1bbi fejlem\u00e9nyeiket. Neked mi lenne a legfontosabb, amit egy online kaszin\u00f3ban l\u00e1tn\u00e1l sz\u00edvesen?<\/p>\n","protected":false},"excerpt":{"rendered":"

6 \u00dajdons\u00e1g a Bonuskong Casino vil\u00e1g\u00e1b\u00f3l, amit nem hagyhatsz ki \u00daj \u00c9rz\u00e9kek a J\u00e1t\u00e9kban: A Bonuskong \u00c9lm\u00e9nyfriss\u00edt\u00e9se M\u00e1r t\u00f6bb \u00e9ve k\u00f6vetem az online kaszin\u00f3k vil\u00e1g\u00e1t, \u00e9s mindig izgalmas figyelni, ahogy a platformok pr\u00f3b\u00e1lnak \u00faj \u00e9lm\u00e9nyekkel el\u0151rukkolni. Amikor el\u0151sz\u00f6r hallottam a Bonuskong Casino leg\u00fajabb fejleszt\u00e9seir\u0151l, kicsit szkeptikus voltam. Gondoltam, biztosan csak apr\u00f3bb v\u00e1ltoztat\u00e1sokr\u00f3l lesz sz\u00f3, esetleg […]<\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[797],"tags":[],"class_list":["post-20852","post","type-post","status-publish","format-standard","hentry","category-bonuskong-casino"],"_links":{"self":[{"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/posts\/20852"}],"collection":[{"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/comments?post=20852"}],"version-history":[{"count":2,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/posts\/20852\/revisions"}],"predecessor-version":[{"id":20860,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/posts\/20852\/revisions\/20860"}],"wp:attachment":[{"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/media?parent=20852"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/categories?post=20852"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bragitrade.com\/index.php\/wp-json\/wp\/v2\/tags?post=20852"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}