[ 'base' => false, 'version' => '1.0.0', 'requires' => '1.5.2', 'class' => 'wpforo\classes\Topics', 'deps' => [], 'title' => 'Topic Tags', 'thumb' => '', 'desc' => __( 'Adds Tags Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'subscriptions' => [ 'base' => true, 'version' => '1.0.0', 'requires' => '1.0.2', 'class' => 'wpforo\modules\subscriptions\Subscriptions', 'deps' => [], 'title' => 'Subscriptions', 'thumb' => '', 'desc' => __( 'Adds Subscriptions & Mentioning Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'mentioning' => [ 'base' => true, 'version' => '1.0.0', 'requires' => '2.0.0', 'class' => 'wpforo\modules\mentioning\Mentioning', 'deps' => [ 'wpforo\modules\subscriptions\Subscriptions' ], 'title' => 'User Mentioning System', 'thumb' => '', 'desc' => __( 'Adds User Following System Feature For Users', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'follows' => [ 'base' => true, 'version' => '1.0.0', 'requires' => '2.0.0', 'class' => 'wpforo\modules\follows\Follows', 'deps' => [ 'wpforo\modules\subscriptions\Subscriptions' ], 'title' => 'User Following System', 'thumb' => '', 'desc' => __( 'Adds User Following System Feature For Users', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'notifications' => [ 'base' => false, 'version' => '1.0.0', 'requires' => '1.7.0', 'class' => 'wpforo\classes\Activity', 'deps' => [], 'title' => 'Forum Notifications', 'thumb' => '', 'desc' => __( 'Adds Forum Notifications Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'logging' => [ 'base' => false, 'version' => '1.0.0', 'requires' => '1.0.0', 'class' => 'wpforo\classes\Logs', 'deps' => [], 'title' => 'Action Logging & Views', 'thumb' => '', 'desc' => __( 'Adds Action Logging & Views Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'seo' => [ 'base' => false, 'version' => '1.0.0', 'requires' => '1.0.0', 'class' => 'wpforo\classes\SEO', 'deps' => [], 'title' => 'wpForo SEO', 'thumb' => '', 'desc' => __( 'Adds wpForo SEO Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'antispam' => [ 'base' => false, 'version' => '1.0.0', 'requires' => '1.0.0', 'class' => 'wpforo\classes\Moderation', 'deps' => [], 'title' => 'Spam Protection', 'thumb' => '', 'desc' => __( 'Adds Spam Protection Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'akismet' => [ 'base' => false, 'version' => '1.0.0', 'requires' => '1.0.0', 'class' => 'wpforo\classes\Moderation', 'deps' => [], 'title' => 'Akismet Antispam Integration', 'thumb' => WPFORO_URL . '/assets/images/dashboard/akismet.png', 'desc' => __( 'Adds Akismet Antispam Integration Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'rss' => [ 'base' => false, 'version' => '1.0.0', 'requires' => '1.0.0', 'class' => '', 'deps' => [], 'title' => 'Forum Feed / RSS', 'thumb' => '', 'desc' => __( 'Adds Forum Feed / RSS Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'social' => [ 'base' => false, 'version' => '1.0.0', 'requires' => '1.0.0', 'class' => 'wpforo\classes\API', 'deps' => [], 'title' => 'Social Share', 'thumb' => '', 'desc' => __( 'Adds Social Share Feature For Topics', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'revisions' => [ 'base' => false, 'version' => '1.0.0', 'requires' => '1.0.0', 'class' => 'wpforo\modules\revisions\Revisions', 'deps' => [], 'title' => 'Post Preview and Auto Drafting', 'thumb' => '', 'desc' => __( 'Adds Post Preview and Auto Drafting Feature For Topics And Posts', 'wpforo' ), 'url' => 'https://wpforo.com', ], 'bookmarks' => [ 'base' => true, 'version' => '1.0.0', 'requires' => '2.0.0', 'class' => 'wpforo\modules\bookmarks\Bookmarks', 'deps' => [], 'title' => 'Post Bookmark', 'thumb' => '', 'desc' => __( 'Adds Post Bookmark Feature For Posts', 'wpforo' ), 'url' => 'https://wpforo.com', ], ]; if( ! is_null( $base ) ) { $modules = array_filter( $modules, function( $module ) use ( $base ) { return $module['base'] === $base; } ); } return $modules; } function wpforo_get_addons_info( $base = null ): array { $addons = [ 'wpforo-user-custom-fields' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-user-custom-fields/wpforo-ucf.php' ), 'base' => true, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'WpforoUcf', 'deps' => [], 'title' => 'User Custom Fields', 'thumb' => WPFORO_URL . '/assets/addons/ucf/header.png', 'desc' => 'Advanced user profile builder system. Allows to add new fields and manage profile. Creates custom Registration, Account, Member Search forms.', 'url' => 'https://gvectors.com/product/wpforo-user-custom-fields/', ], 'wpforo-topic-custom-fields' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-topic-custom-fields/wpforotcf.php' ), 'base' => false, 'version' => '3.0.1', 'requires' => '2.0.0', 'class' => 'wpForoTcf', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoTcf' ) && function_exists( 'wpforotcf_activation' ) && version_compare( WPFORO_VERSION, WPFOROTCF_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforotcf_activation(); } }, 'title' => 'Topic Custom Fields', 'thumb' => WPFORO_URL . '/assets/addons/tcf/header.png', 'desc' => 'Allows to create topic custom fields and manage topic form layout with a form builder. Adds topic search options by custom fields', 'url' => 'https://gvectors.com/product/wpforo-topic-custom-fields/', ], 'wpforo-private-messages' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-private-messages/wpforopm.php' ), 'base' => true, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoPMs', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoPMs' ) && function_exists( 'wpforopm_activation' ) && version_compare( WPFORO_VERSION, WPFOROPM_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforopm_activation(); } }, 'title' => 'Private Messages', 'thumb' => WPFORO_URL . '/assets/addons/pm/header.png', 'desc' => 'Provides a safe way to communicate directly with other members. Messages are private and can only be viewed by conversation participants.', 'url' => 'https://gvectors.com/product/wpforo-private-messages/', ], 'wpforo-topic-prefix' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-topic-prefix/wpforotpx.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoTopicPrefix', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoTopicPrefix' ) && function_exists( 'wpforotpx_activation' ) && version_compare( WPFORO_VERSION, WPFOROTPX_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforotpx_activation(); } }, 'title' => 'Topic Prefix & Tag Manager', 'thumb' => WPFORO_URL . '/assets/addons/prefix/header.png', 'desc' => 'Allows you to create topic prefixes and prefix groups to categorize topics. Also, it allows you to add, edit, delete topic tags and convert them to prefixes.', 'url' => 'https://gvectors.com/product/wpforo-topic-prefix/', ], 'wpforo-advanced-reactions' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo_reactions/Main.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.3.2', 'class' => '\wpforo_reactions\Main', 'deps' => [], 'title' => 'Advanced Reactions', 'thumb' => WPFORO_URL . '/assets/addons/reactions/header.png', 'desc' => 'Allows users to add new types of reactions and provides a frontend dialog to view each post\'s currently reacted users', 'url' => 'https://gvectors.com/product/wpforo_reactions/', ], 'wpforo-advanced-attachments' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-advanced-attachments/wpforoattach.php' ), 'base' => false, 'version' => '3.0.1', 'requires' => '2.0.0', 'class' => 'wpForoAttachments', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoAttachments' ) && function_exists( 'wpforoattach_activation' ) && version_compare( WPFORO_VERSION, WPFOROATTACH_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforoattach_activation(); } }, 'title' => 'Advanced Attachments', 'thumb' => WPFORO_URL . '/assets/addons/attachments/header.png', 'desc' => 'Adds an advanced file attachment system to forum. AJAX powered media uploading and displaying system with user specific library.', 'url' => 'https://gvectors.com/product/wpforo-advanced-attachments/', ], 'wpforo-embeds' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-embeds/wpforoembeds.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoEmbeds', 'deps' => [], 'title' => 'Embeds', 'thumb' => WPFORO_URL . '/assets/addons/embeds/header.png', 'desc' => 'Allows to embed hundreds of video, social network, audio and photo content providers in forum topics and posts.', 'url' => 'https://gvectors.com/product/wpforo-embeds/', ], 'wpforo-memberpress' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-memberpress/wpforo_mempress.php' ), 'base' => true, 'version' => '1.0.0', 'requires' => '2.2.2', 'class' => 'wpForoMemberPress', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoMemberPress' ) && function_exists( 'wpforomp_activation' ) && version_compare( WPFORO_VERSION, WPFOROMP_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforomp_activation(); } }, 'title' => 'MemberPress Integration', 'thumb' => WPFORO_URL . '/assets/addons/wpforo-memberpress/header.png', 'desc' => 'Allows to setup membership access to your forums through MemberPress membership plugin.', 'url' => 'https://gvectors.com/product/wpforo-memberpress/', ], 'wpforo-groups' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-groups-membership/wpforo_groups.php' ), 'base' => true, 'version' => '1.0.0', 'requires' => '2.2.2', 'class' => 'wpForoGroups', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoGroups' ) && function_exists( 'wpforomp_activation' ) && version_compare( WPFORO_VERSION, WPFOROGRP_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforomp_activation(); } }, 'title' => 'Groups Plugin Integration', 'thumb' => WPFORO_URL . '/assets/addons/wpforo-groups/header.png', 'desc' => 'Allows to setup membership access to your forums through Groups plugin.', 'url' => 'https://gvectors.com/product/wpforo-groups-membership/', ], 'wpforo-suremembers' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-suremembers/wpforo_surmem.php' ), 'base' => true, 'version' => '1.0.0', 'requires' => '2.2.2', 'class' => 'wpForoSureMembers', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoSureMembers' ) && function_exists( 'wpforosm_activation' ) && version_compare( WPFORO_VERSION, WPFOROSM_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforosm_activation(); } }, 'title' => 'SureMembers Integration', 'thumb' => WPFORO_URL . '/assets/addons/wpforo-suremembers/header.png', 'desc' => 'Allows to setup membership access to your forums through SureMembers membership plugin.', 'url' => 'https://gvectors.com/product/wpforo-suremembers/', ], 'wpforo-paid-membership-pro' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-paid-membership-pro/wpforo_mempro.php' ), 'base' => true, 'version' => '1.0.0', 'requires' => '2.2.2', 'class' => 'wpForoPaidMembershipPro', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoPaidMembershipPro' ) && function_exists( 'wpforopmp_activation' ) && version_compare( WPFORO_VERSION, WPFOROPMP_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforopmp_activation(); } }, 'title' => 'Paid Membership Pro Integration', 'thumb' => WPFORO_URL . '/assets/addons/wpforo-paid-membership-pro/header.png', 'desc' => 'Allows to setup membership access to your forums through Paid Membership Pro plugin.', 'url' => 'https://gvectors.com/product/wpforo-paid-membership-pro/', ], 'wpforo-woocommerce-memberships' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-woocommerce-memberships/wpforo_woomem.php' ), 'base' => true, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoWooMembers', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoWooMembers' ) && function_exists( 'wpforowm_activation' ) && version_compare( WPFORO_VERSION, WPFOROWM_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforowm_activation(); } }, 'title' => 'WooCommerce Memberships Integration', 'thumb' => WPFORO_URL . '/assets/addons/wpforo-woocomerce-memberships/header.png', 'desc' => 'Allows to setup membership access to your forums and topics through WooCommerce Memberships plugin.', 'url' => 'https://gvectors.com/product/wpforo-woocommerce-memberships/', ], 'wpforo-mentioning' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo_mentioning/Main.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.2.9', 'class' => '\wpforo_mentioning\Main', 'deps' => [], 'title' => 'User Mentioning', 'thumb' => WPFORO_URL . '/assets/addons/wpforo-mentioning/header.png', 'desc' => 'Opens pop-up window to select users for mentioning by @nickname.', 'url' => 'https://gvectors.com/product/wpforo_mentioning/', ], 'wpforo-voice-posting' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-voice-posting/wpforoVoicePosting.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.2.8', 'class' => 'wpforoVoicePosting', 'deps' => [], 'title' => 'Voice Posting', 'thumb' => WPFORO_URL . '/assets/addons/wpforo-voice-posting/header.png', 'desc' => 'Allows to record and attach voice messages to forum posts and private messages.', 'url' => 'https://gvectors.com/product/wpforo-voice-posting/', ], 'wpforo-cross-posting' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-cross-posting/wpForoCrossPosting.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoCrossPosting', 'deps' => [], 'title' => '"Forum - Blog" Cross Posting', 'thumb' => WPFORO_URL . '/assets/addons/cross/header.png', 'desc' => 'Blog to Forum and Forum to Blog content synchronization. Blog posts with Forum topics and Blog comments with Forum replies.', 'url' => 'https://gvectors.com/product/wpforo-cross-posting/', ], 'wpforo-ad-manager' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-ad-manager/wpforoad.php' ), 'base' => false, 'version' => '3.0.1', 'requires' => '2.0.0', 'class' => 'wpForoAD', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoAD' ) && function_exists( 'wpforoad_activation' ) && version_compare( WPFORO_VERSION, WPFOROAD_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforoad_activation(); } }, 'title' => 'Ads Manager', 'thumb' => WPFORO_URL . '/assets/addons/ad-manager/header.png', 'desc' => 'Ads Manager is a powerful yet simple advertisement management system. Allows you to add adverting banners between forums, topics and posts.', 'url' => 'https://gvectors.com/product/wpforo-ad-manager/', ], 'wpforo-polls' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-polls/wpforopoll.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoPoll', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoPoll' ) && function_exists( 'wpforopoll_activation' ) && version_compare( WPFORO_VERSION, WPFOROPOLL_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforopoll_activation(); } }, 'title' => 'Polls', 'thumb' => WPFORO_URL . '/assets/addons/polls/header.png', 'desc' => 'wpForo Polls is a complete addon to help forum members create, vote and manage polls effectively. Comes with poll specific permissions and settings.', 'url' => 'https://gvectors.com/product/wpforo-polls/', ], 'wpforo-emoticons' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-emoticons/wpforosmile.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoSmiles', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoSmiles' ) && function_exists( 'wpforosmile_activation' ) && version_compare( WPFORO_VERSION, WPFOROSMILE_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpforosmile_activation(); } }, 'title' => 'wpForo Emoticons', 'thumb' => WPFORO_URL . '/assets/addons/wpforo-emoticons/header.png', 'desc' => 'Adds awesome Sticker and Emoticons packs to editor. Allows to create new custom emoticons packs.', 'url' => 'https://gvectors.com/product/wpforo-emoticons/', ], 'wpforo-tenor' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-tenor/wpforotenor.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoTenor', 'deps' => [], 'title' => 'Tenor GIFs Integration', 'thumb' => WPFORO_URL . '/assets/addons/tenor/header.png', 'desc' => 'Adds Tenor [GIF] button and opens popup where you can search for gifs and insert them in topic, post and private message content.', 'url' => 'https://gvectors.com/product/wpforo-tenor/', ], 'wpforo-giphy' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-giphy/wpforogiphy.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoGiphy', 'deps' => [], 'title' => 'GIPHY Integration', 'thumb' => WPFORO_URL . '/assets/addons/giphy/header.png', 'desc' => 'Adds GIPHY [GIF] button and opens popup where you can search for gifs and insert them in topic, post and private message content.', 'url' => 'https://gvectors.com/product/wpforo-giphy/', ], 'wpforo-mycred' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-mycred/wpforo-mc.php' ), 'base' => true, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'myCRED_Hook_wpForo', 'deps' => [], 'title' => 'MyCRED Integration', 'thumb' => WPFORO_URL . '/assets/addons/mycred/header.png', 'desc' => 'Awards myCRED points for forum activity. Integrates myCRED Badges and Ranks. Converts wpForo topic and posts, likes to myCRED points.', 'url' => 'https://gvectors.com/product/wpforo-mycred/', ], 'wpforo-syntax-highlighter' => [ 'ABSPATH' => wpforo_fix_dir_sep( WP_PLUGIN_DIR . '/wpforo-syntax-highlighter/wpForoSyntaxHighlighter.php' ), 'base' => false, 'version' => '3.0.0', 'requires' => '2.0.0', 'class' => 'wpForoSyntaxHighlighter', 'deps' => [], 'install_func' => function() { if( class_exists( 'wpForoSyntaxHighlighter' ) && function_exists( 'wpForoSyntaxActivation' ) && version_compare( WPFORO_VERSION, WPFOROSYNTAX_WPFORO_REQUIRED_VERSION, '>=' ) ) { wpForoSyntaxActivation(); } }, 'title' => 'Syntax Highlighter', 'thumb' => WPFORO_URL . '/assets/addons/syntax/header.png', 'desc' => 'Syntax highlighting for forum posts, automatic language detection and multi-language code highlighting.', 'url' => 'https://gvectors.com/product/wpforo-syntax-highlighter/', ], ]; if( ! is_null( $base ) ) { $addons = array_filter( $addons, function( $addon ) use ( $base ) { return $addon['base'] === $base; } ); } return $addons; } function wpforo_get_ajax_actions_list() { $nonces = []; global $wp_filter; if( WPF()->current_userid ) { foreach( $wp_filter as $key => $value ) { if( strpos( (string) $key, 'wp_ajax_wpf' ) === 0 ) $nonces[] = preg_replace( '#^wp_ajax_#iu', '', (string) $key, 1 ); } } else { foreach( $wp_filter as $key => $value ) { if( strpos( (string) $key, 'wp_ajax_nopriv_wpf' ) === 0 ) $nonces[] = preg_replace( '#^wp_ajax_nopriv_#iu', '', (string) $key, 1 ); } } return array_unique( (array) apply_filters( 'wpforo_get_ajax_actions_list', $nonces ) ); } function wpforo_generate_ajax_nonces() { $nonces = []; foreach( wpforo_get_ajax_actions_list() as $action ) { $nonces[ $action ] = wp_create_nonce( $action ); } return $nonces; } function wpforo_verify_form( $action = 'wpforo_verify_form', $query_arg = '_wpfnonce', $mode = 'full' ) { wpforo_verify_nonce( $action, $mode, $query_arg ); do_action( 'wpforo_verify_form_end' ); } function wpforo_verify_nonce( $action = 'wpforo_verify_form', $mode = 'ajax', $query_arg = '_wpfnonce' ) { if( $mode === 'full' && apply_filters( 'wpforo_check_request', true ) ) { if( ! wp_verify_nonce( wpfval( $_REQUEST, $query_arg ), $action ) ) { wpforo_phrase( 'Sorry, something is wrong with your data.' ); exit(); } } elseif( $mode === 'ajax' ) { check_ajax_referer( $action, $query_arg ); } if( apply_filters( 'wpforo_check_referer', true ) && in_array( $mode, [ 'ajax', 'full', 'ref' ] ) ) { if( ! wpfval( $_SERVER, 'HTTP_REFERER' ) ) { exit( 'Error 2252 | Please contact the forum administrator.' ); } if( wpforo_is_url_external( $_SERVER['HTTP_REFERER'] ) ) { exit( 'Error 2253 | Please contact the forum administrator.' ); } } do_action( 'wpforo_verify_nonce_end' ); } /** * @param string $path * @param string|null $route * @param string|null $scheme * * @return string */ function wpforo_url( $path = '', $route = null, $scheme = null ) { if( $route ) $route = wpforo_settings_get_slug( $route ); if( is_null( $route ) ) $route = WPF()->board->full_route; $path = trim( trim( (string) $route, '/\\' ) . '/' . trim( (string) $path, '/\\' ), '/\\' ); if( function_exists( 'pll_default_language' ) && function_exists( 'PLL' ) ) { if( ! PLL()->options['hide_default'] && $lng = pll_default_language() ) $path = $lng . '/' . $path; } $url = home_url( $path, $scheme ); //-START- check is url maybe WordPress home $maybe_home_url = trim( preg_replace( '#/?index\.php/?(\?.*)?$#isu', '', (string) $url ), '/\\' ); $home_url = trim( home_url( '', $scheme ), '/\\' ); if( $maybe_home_url === $home_url ) $url = preg_replace( '#index\.php/?#isu', '', (string) $url, 1 ); //-END- check is url maybe WordPress home $url = apply_filters( 'wpforo_url', $url, $path, $route, $scheme ); return WPF()->user_trailingslashit( $url ); } /** * @param string $path * @param string|null $scheme * * @return string */ function wpforo_home_url( $path = '', $scheme = null ) { if( strpos( (string) $path, 'http' ) === 0 ) { $path = wpforo_get_url_query_vars_str( $path ); $path = preg_replace( '#index\.php/?#isu', '', (string) $path, 1 ); $path = preg_replace( '#^/?' . preg_quote( trim( (string) WPF()->board->route, '/\\' ) ) . '#isu', '', (string) $path, 1 ); } return wpforo_url( $path, null, $scheme ); } function wpforo_is_ajax() { return defined( 'DOING_AJAX' ) && DOING_AJAX; } function wpforo_is_admin( $url = '' ) { $url = trim( (string) $url ); if( $url ) return strpos( (string) $url, trim( admin_url(), '/' ) ) === 0 || strpos( $url, trim( self_admin_url(), '/' ) ) === 0; return is_admin() && ! wpforo_is_ajax(); } function _is_wpforo_page( $url = '' ) { if( ! $url ) $url = wpforo_get_request_uri(); $result = ( ! ( wpforo_is_admin( $url ) || ( is_wpforo_exclude_url( $url ) && ! is_wpforo_url( $url ) && ! is_wpforo_shortcode_page( $url ) ) ) && ( is_wpforo_url( $url ) || is_wpforo_shortcode_page( $url ) ) ); return apply_filters( 'is_wpforo_page', $result, $url ); } function is_wpforo_page( $url = '' ) { return wpforo_ram_get( '_is_wpforo_page', $url ); } function _is_wpforo_exclude_url( $url = '' ) { $result = false; if( ! $url ) $url = wpforo_get_request_uri(); $url = urldecode( (string) $url ); $url = preg_replace( '#/page/\d*/?$#iu', '', (string) $url ); if( $current_url = wpforo_get_url_query_vars_str( $url ) ) { if( preg_match( '#^/?(?:([^\s/?&=<>:\'\"*\\\|]*/)(?1)*)?[^\s/?&=<>:\'\"*\\\|]+\.(?:php|js|css|jpe?g|png|gif|webp|svg|bmp|tiff)/?(?:\?[^/]*)?$#iu', $current_url ) ) { $result = true; } elseif( WPF()->board->get_current( 'is_standalone' ) && ( $excld_urls = WPF()->board->get_current( 'excld_urls' ) ) ) { foreach( $excld_urls as $excld_url ) { $excld_url = urldecode( (string) $excld_url ); if( wpforo_is_url_internal( $excld_url ) ) { $excld_url = wpforo_get_url_query_vars_str( $excld_url ); $pattern = preg_quote( $excld_url ); $pattern = str_replace( [ '/\*', '\*' ], [ '/?[^\r\n\t\s\0]*?', '[^\r\n\t\s\0]*?' ], $pattern ); if( preg_match( '#^' . $pattern . '$#iu', $current_url ) ) { $result = true; break; } } } } } return $result; } function is_wpforo_exclude_url( $url = '' ) { return wpforo_ram_get( '_is_wpforo_exclude_url', $url ); } function _is_wpforo_url( $url = '' ) { $result = false; if( ! wpforo_is_admin( $url ) ) { if( WPF()->board->get_current( 'is_standalone' ) && ! is_wpforo_exclude_url( $url ) ) { $result = true; } else { $current_url = wpforo_get_url_query_vars_str( $url ); $current_url = preg_replace( '#/?\?.*$#isu', '', $current_url ); foreach( WPF()->board->routes as $route ) { if( $route && ( $current_url === $route || strpos( (string) $current_url, $route . '/' ) === 0 ) ) { $result = true; break; } } } } return $result; } function is_wpforo_url( $url = '' ) { return wpforo_ram_get( '_is_wpforo_url', $url ); } /** * @param string $url * * @return bool */ function _is_wpforo_shortcode_page( $url = '' ) { $result = ! wpforo_is_admin( $url ) && ! is_wpforo_url( $url ) && has_shortcode( wpforo_get_wp_post_content( $url ), 'wpforo' ); return apply_filters( 'wpforo_is_shortcode_page', $result, $url ); } function is_wpforo_shortcode_page( $url = '' ) { return wpforo_ram_get( '_is_wpforo_shortcode_page', $url ); } function _wpforo_get_wp_post_content( $url = '' ) { if( ! $url ) $url = wpforo_get_request_uri(); $post_content = ''; global $post; if( $url === wpforo_get_request_uri() && is_a( $post, 'WP_Post' ) ) { $post_content = $post->post_content; } elseif( $postid = wpforo_wp_url_to_postid( $url ) ) { $post_content = get_post_field( 'post_content', $postid ); } return $post_content; } function wpforo_get_wp_post_content( $url = '' ) { return wpforo_ram_get( '_wpforo_get_wp_post_content', $url ); } /** * @param string $text * @param string $url * * @return array|string */ function get_wpforo_shortcode_atts( $text = '', $url = '' ) { if( ! $text ) $text = wpforo_get_wp_post_content( $url ); if( preg_match( '#\[[\r\n\t\s\0]*wpforo[\r\n\t\s\0]*([^\[\]]*?)]#iu', $text, $match ) ) { return shortcode_parse_atts( $match[1] ); } return ''; } function wpforo_get_url_query_vars_str( $url = '' ) { if( ! $url ) $url = wpforo_get_request_uri(); $home_url = preg_replace( '#/?\?.*$#isu', '', home_url( '/' ) ); $current_url = preg_replace( '#https?://[^/\?]+/?#isu', '', $url ); $site_url = preg_replace( '#https?://[^/\?]+/?#isu', '', $home_url ); if( strpos( (string) $current_url, '/' ) === false && $current_url === trim( (string) $site_url, '/' ) ) return ''; $current_url = preg_replace( '#^/?' . preg_quote( $site_url ) . '(?:/?index\.php/?)?#isu', '', $current_url, 1 ); $current_url = preg_replace( '#^/?' . preg_quote( wpforo_get_query_var_lang() ) . '/#isu', '', $current_url, 1 ); $current_url = preg_replace( '#^[\s\0/]*(.*?)[\s\0/]*$#isu', '$1', $current_url ); return wpforo_fix_url( $current_url ); } function wpforo_get_url_route( $url = '' ) { $route = ''; $query_vars_str = preg_replace( '#/?\?.*$#isu', '', wpforo_get_url_query_vars_str( (string) $url ) ); $query_vars = array_values( array_filter( explode( '/', trim( (string) $query_vars_str, '/' ) ) ) ); if( array_key_exists( 0, $query_vars ) && in_array( $query_vars[0], WPF()->board->routes ) ) $route = $query_vars[0]; return $route; } function wpforo_dir_size( $directory ) { $size = 0; if( is_dir( $directory ) && class_exists( 'RecursiveIteratorIterator' ) && class_exists( 'RecursiveDirectoryIterator' ) ) { foreach( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $directory ) ) as $file ) $size += $file->getSize(); } return $size; } function wpforo_make_hidden_fields_from_url( $url = '', $echo = true ) { if( ! $url ) $url = wpforo_get_request_uri(); $return = ''; if( $url_query = parse_url( $url, PHP_URL_QUERY ) ) { parse_str( $url_query, $url_query_arr ); if( ! empty( $url_query_arr ) ) { foreach( $url_query_arr as $key => $value ) { $return .= ''; } } } if( ! $echo ) return $return; echo $return; } /** * Returns merged arguments array from defined and default arguments. * * @param mixed $args * @param array $default * * @return array */ function wpforo_parse_args( $args, $default = [] ) { if( is_object( $args ) ) { $defined = get_object_vars( $args ); } elseif( is_array( $args ) ) { $defined = $args; } elseif( preg_match( '|^[\d,\s]+$|', (string) $args ) ) { $defined = explode( ',', trim( (string) $args ) ); } elseif( is_integer( $args ) || is_float( $args ) ) { $defined[0] = $args; } elseif( is_serialized( $args ) ) { // SECURITY: refuse to instantiate any class — only scalars and arrays // of scalars are recovered. Blocks PHP Object Injection via widget // AJAX (forumids etc.) and any other caller that may receive // attacker-controlled strings. $defined = unserialize( $args, [ 'allowed_classes' => false ] ); if( ! is_array( $defined ) ) $defined = (array) $defined; } elseif( strpos( (string) $args, '=' ) !== false ) { parse_str( $args, $defined ); } else { $defined = (array) $args; } if( ! empty( $default ) ) { return array_merge( $default, $defined ); } else { return $defined; } } /** * Detects serialized data * * @param string * * @return boolean * @since 1.0.0 * */ if( ! function_exists( 'is_serialized' ) ) { function is_serialized( $value ) { if( $value == '' ) return false; $value = trim( (string) $value ); // SECURITY: the very act of detecting a serialized payload must not // instantiate classes — @unserialize() with the default options runs // __wakeup() / __destruct() for any embedded object even when the // caller only wanted to test the format. Limit to scalars/arrays. $chsd = @unserialize( $value, [ 'allowed_classes' => false ] ); if( $chsd !== false || $value === 'b:0;' ) { return true; } else { return false; } } } function wpforo_get_request_uri( $with_port = false, $get_referer_when_ajax = true ) { if( $get_referer_when_ajax && wpforo_is_ajax() ) { if( $referer = wpfval( $_REQUEST, 'referer' ) ) { $referer = preg_replace( '#\#[^/?&]*$#iu', '', (string) $referer ); return esc_url_raw( $referer ); } if( $referer = wpfval( $_SERVER, 'HTTP_REFERER' ) ) { $url = preg_replace( '#\#[^/?&]*$#iu', '', (string) $referer ); return esc_url_raw( $url ); } } $s = is_ssl() ? 's' : ''; $sp = strtolower( (string) wpfval( $_SERVER, 'SERVER_PROTOCOL' ) ); $protocol = substr( $sp, 0, strpos( (string) $sp, "/" ) ) . $s; $server_port = intval( wpfval( $_SERVER, 'SERVER_PORT' ) ); $port = $server_port === 80 ? "" : ":" . $server_port; $host = preg_replace( '#^www\.#iu', '', (string) wpfval( $_SERVER, 'HTTP_HOST' ) ); if( strpos( home_url(), 'www.' ) !== false ) $host = 'www.' . $host; $requri = wpfval( $_SERVER, 'UNENCODED_URL' ) ?: wpfval( $_SERVER, 'REQUEST_URI' ); $url = $protocol . "://" . $host . ( $with_port && $server_port ? $port : '' ) . $requri; $url = wpforo_fix_url( $url ); return esc_url_raw( $url ); } function wpforo_arr_group_by( $array, $key_by ) { if( ! empty( $array ) ) { $fltrd = []; foreach( $array as $key => $arr ) { if( is_numeric( $key ) ) $fltrd[] = $arr[ $key_by ]; } $uniq_arr = array_unique( $fltrd ); asort( $uniq_arr ); return $uniq_arr; } } function wpforo_phrase( $key, $echo = true, $format = 'first-upper' ) { static $cache = []; $locale = WPF()->locale; $cache_key = $key . '|' . $locale . '|' . $format; // For English locale, we can safely cache (no domain/backtrace issues) if ( 'en_US' === $locale && isset( $cache[ $cache_key ] ) ) { if ( $echo ) { echo $cache[ $cache_key ]; } return $cache[ $cache_key ]; } // Normalize key once for phrase lookup $normalized_key = addslashes( strtolower( (string) $key ) ); $phrase = isset( WPF()->phrase->phrases[ $normalized_key ] ) ? WPF()->phrase->phrases[ $normalized_key ] : $key; if( 'en_US' !== $locale ) { $native = $phrase; $backtrace = wp_debug_backtrace_summary(); $mopo_domain = 'wpforo'; if( strpos( (string) $backtrace, '\plugins\wpforo-private-messages\\' ) !== false || strpos( (string) $backtrace, '/plugins/wpforo-private-messages/' ) !== false ) $mopo_domain = 'wpforo_pm'; if( strpos( (string) $backtrace, 'wpForoPolls' ) !== false ) $mopo_domain = 'wpforo_poll'; $key = preg_replace( "/(^\s+)|(\s+$)/u", "", (string) $key ); $phrase = preg_replace( "/(^\s+)|(\s+$)/u", "", (string) $phrase ); if( strtolower( (string) $key ) === strtolower( (string) $phrase ) ) { $phrase = __( $key, $mopo_domain ); if( strtolower( (string) $key ) === strtolower( (string) $phrase ) ) { $key = strtolower( (string) $key ); $phrase = __( $key, $mopo_domain ); if( strtolower( (string) $key ) === strtolower( (string) $phrase ) ) { $phrase = __( ucfirst( (string) $key ), $mopo_domain ); if( strtolower( (string) $key ) === strtolower( (string) $phrase ) ) { $phrase = __( $native, $mopo_domain ); //Try all, if no result pass the original text to translation again. } } } } } if( $format === 'first-upper' ) { if( 'en_US' !== $locale && function_exists( 'mb_strlen' ) && mb_strlen( (string) $phrase ) !== strlen( (string) $phrase ) && function_exists( 'mb_strtoupper' ) ) { $phrase = mb_strtoupper( mb_substr( (string) $phrase, 0, 1 ) ) . mb_substr( (string) $phrase, 1 ); } else { $phrase = ucfirst( (string) $phrase ); } } elseif( $format === 'upper' ) { if( function_exists( 'mb_strtoupper' ) ) { $phrase = mb_strtoupper( (string) $phrase ); } else { $phrase = strtoupper( (string) $phrase ); } } elseif( $format === 'lower' ) { if( function_exists( 'mb_strtolower' ) ) { $phrase = mb_strtolower( (string) $phrase ); } else { $phrase = strtolower( (string) $phrase ); } } $phrase = str_replace( '{number}', '', $phrase ); // Cache for English locale (safe - no domain dependency) if ( 'en_US' === $locale ) { $cache[ $cache_key ] = $phrase; } if( $echo ) echo $phrase; return $phrase; } function wpforo_screen_option() { ?>
]*)>(.*?class=[\'"]wpforo-auto-embeded[^\'"]*[\'"].*?)#isu', (string) $content, $matches, PREG_SET_ORDER ) ) { foreach( $matches as $match ) { $match[2] = preg_replace( '#
' . $match[2] . '', $content ); } } $content = preg_replace( '#(]*>[^<>]*)]*class=[\'"]wpforo-auto-embeded-link[\'"][^<>]*href=[\'"]([^\'"]*)[\'"][^<>]*>[^<>]*([^<>]*)#iu', '$1$2$3', (string) $content ); $content = apply_filters( 'wpforo_content_filter', $content, $post ); return wpautop( $content ); } function wpforo_remove_links( $content ) { return preg_replace( '#([^\'\"]|^)(https?://[^\s\'\"<>]+)([^\'\"]|$)#isu', '$1 [' . wpforo_phrase( 'removed link', false ) . '] $3', (string) $content ); } add_filter( 'wpforo_content_filter', 'wpforo_nofollow_tag', 20 ); function wpforo_nofollow_tag( $content ) { return preg_replace_callback( '#<]*?href=[\'\"]([^\'\"]+)[\'\"][^><]*?>#isu', 'wpforo_nofollow', (string) $content ); } function wpforo_nofollow( $match ) { $ret = $match[0]; if( apply_filters( 'wpforo_external_link_nofollow', true ) ) { $dofollow = wpforo_setting( 'seo', 'dofollow' ); $request_uri_parse = parse_url( wpforo_get_request_uri() ); $main_host = preg_replace( '#^.*?([^.]+?\.[^.]+?)$#isu', '$1', (string) $request_uri_parse['host'] ); $link_url = parse_url( $match[1] ); if( strpos( (string) $match[1], $main_host ) === false && ! ( ! empty( $dofollow ) && ! empty( $link_url['host'] ) && in_array( $link_url['host'], $dofollow ) ) ) { $ret = preg_replace_callback( '#\srel=[\'\"]([^\'\"]*?)[\'\"]#iu', function( $m ) { $rels = array_filter( preg_split( '#\s#u', $m[1] ) ); $rels = array_merge( [ 'nofollow' ], $rels ); return sprintf( 'rel="%1$s"', implode( ' ', $rels ) ); }, (string) $match[0], 1, $count ); if( ! $count ) $ret = str_replace( '>', ' rel="nofollow">', $match[0] ); } } return $ret; } add_action( 'wpforo_actions_end', 'wpforo_logs', 10 ); function wpforo_logs() { if( ! WPF()->current_object['is_404'] ) { WPF()->log->read(); WPF()->log->visit(); } } add_action( 'wpforo_bottom_hook', 'wpforo_user_logging' ); function wpforo_user_logging() { $data = WPF()->current_object; $filter_views = apply_filters( 'wpforo_filter_topic_views', true ); if( wpfval( $data, 'template' ) && $data['template'] == 'post' && wpfval( $data, 'topicid' ) ) { if( $filter_views ) { //to-do: don't increase views before all read point. if( wpforo_setting( 'legal', 'cookies' ) ) { $viwed_ids = wpforo_getcookie( wpforo_prefix( 'read_topics' ), false ); $has_viewed = ! empty( $viwed_ids ) && wpfval( $viwed_ids, $data['topicid'] ); if( ! $has_viewed && is_user_logged_in() ) { $viwed_db_ids = wpforo_current_usermeta( wpforo_prefix( 'read_topics' ) ); $has_viewed = ! empty( $viwed_db_ids ) && wpfval( $viwed_db_ids, $data['topicid'] ); } if( ! $has_viewed ) { WPF()->db->query( "UPDATE `" . WPF()->tables->topics . "` SET `views` = `views` + 1 WHERE `topicid` = " . intval( $data['topicid'] ) ); } } elseif( is_user_logged_in() ) { if( wpfval( WPF()->current_usermeta, wpforo_prefix( 'read_topics' ) ) ) { $viwed_db_ids = wpforo_current_usermeta( wpforo_prefix( 'read_topics' ) ); if( empty( $viwed_db_ids ) || ! wpfval( $viwed_db_ids, $data['topicid'] ) ) { WPF()->db->query( "UPDATE `" . WPF()->tables->topics . "` SET `views` = `views` + 1 WHERE `topicid` = " . intval( $data['topicid'] ) ); } } else { WPF()->db->query( "UPDATE `" . WPF()->tables->topics . "` SET `views` = `views` + 1 WHERE `topicid` = " . intval( $data['topicid'] ) ); } } } else { WPF()->db->query( "UPDATE `" . WPF()->tables->topics . "` SET `views` = `views` + 1 WHERE `topicid` = " . intval( $data['topicid'] ) ); } } } function wpforo_setcookie( $key, $args = [], $implode = false ) { if( ! wpforo_setting( 'legal', 'cookies' ) ) return; if( ! empty( $args ) && is_array( $args ) ) { $num = count( $args ); if( $num > 3 ) { $max = apply_filters( 'wpforo_cookie_max_logged_topics', 10 ); $delta = $num - $max; if( $delta > 0 ) $args = array_slice( $args, $delta, null, true ); } } if( ! empty( $args ) && is_array( $args ) && $implode ) { $value = trim( implode( ',', $args ), ',' ); } elseif( ! empty( $args ) && is_array( $args ) && ! $implode ) { $value = wp_json_encode( $args ); } if( ! isset( $value ) ) $value = ''; if( $key ) { $secure = is_ssl(); $secure_logged_in_cookie = $secure && 'https' === parse_url( get_option( 'home' ), PHP_URL_SCHEME ); if( COOKIEPATH != SITECOOKIEPATH ) { @setcookie( $key, $value, time() + 7776000, SITECOOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true ); } else { @setcookie( $key, $value, time() + 7776000, COOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true ); } } } function wpforo_getcookie( $key, $explode = false ) { if( ! wpforo_setting( 'legal', 'cookies' ) ) return false; if( $cookie = wpfval( $_COOKIE, $key ) ) { if( $explode ) { return explode( ',', $cookie ); } else { $cookie = wp_unslash( $cookie ); if( ! $data = json_decode( $cookie, true ) ) return $cookie; return $data; } } return false; } function wpforo_is_bot() { static $is_bot = null; if ( $is_bot !== null ) { return $is_bot; } if( ! $http_user_agent = wpfval( $_SERVER, 'HTTP_USER_AGENT' ) ) $http_user_agent = wpfval( $_SERVER, 'http_user_agent' ); if( $http_user_agent ) { $is_bot = (bool) preg_match( '#(abot|dbot|ebot|hbot|kbot|lbot|mbot|nbot|obot|pbot|rbot|sbot|tbot|vbot|ybot|zbot|bot\.|bot\/|_bot|\.bot|\/bot|\-bot|\:bot|\(bot|crawl|slurp|spider|seek|accoona|acoon|adressendeutschland|ah\-ha\.com|ahoy|altavista|ananzi|anthill|appie|arachnophilia|arale|araneo|aranha|architext|aretha|arks|asterias|atlocal|atn|atomz|augurfind|backrub|bannana_bot|baypup|bdfetch|big brother|biglotron|bjaaland|blackwidow|blaiz|blog|blo\.|bloodhound|boitho|booch|bradley|butterfly|calif|cassandra|ccubee|cfetch|charlotte|churl|cienciaficcion|cmc|collective|comagent|combine|computingsite|csci|curl|cusco|daumoa|deepindex|delorie|depspid|deweb|die blinde kuh|digger|ditto|dmoz|docomo|download express|dtaagent|dwcp|ebiness|ebingbong|e\-collector|ejupiter|emacs\-w3 search engine|esther|evliya celebi|ezresult|falcon|felix ide|ferret|fetchrover|fido|findlinks|fireball|fish search|fouineur|funnelweb|gazz|gcreep|genieknows|getterroboplus|geturl|glx|goforit|golem|grabber|grapnel|gralon|griffon|gromit|grub|gulliver|hamahakki|harvest|havindex|helix|heritrix|hku www octopus|homerweb|htdig|html index|html_analyzer|htmlgobble|hubater|hyper\-decontextualizer|ia_archiver|ibm_planetwide|ichiro|iconsurf|iltrovatore|image\.kapsi\.net|imagelock|incywincy|indexer|infobee|informant|ingrid|inktomisearch\.com|inspector web|intelliagent|internet shinchakubin|ip3000|iron33|israeli\-search|ivia|jack|jakarta|javabee|jetbot|jumpstation|katipo|kdd\-explorer|kilroy|knowledge|kototoi|kretrieve|labelgrabber|lachesis|larbin|legs|libwww|linkalarm|link validator|linkscan|lockon|lwp|lycos|magpie|mantraagent|mapoftheinternet|marvin\/|mattie|mediafox|mediapartners|mercator|merzscope|microsoft url control|minirank|miva|mj12|mnogosearch|moget|monster|moose|motor|multitext|muncher|muscatferret|mwd\.search|myweb|najdi|nameprotect|nationaldirectory|nazilla|ncsa beta|nec\-meshexplorer|nederland\.zoek|netcarta webmap engine|netmechanic|netresearchserver|netscoop|newscan\-online|nhse|nokia6682\/|nomad|noyona|nutch|nzexplorer|objectssearch|occam|omni|open text|openfind|openintelligencedata|orb search|osis\-project|pack rat|pageboy|pagebull|page_verifier|panscient|parasite|partnersite|patric|pear\.|pegasus|peregrinator|pgp key agent|phantom|phpdig|picosearch|piltdownman|pimptrain|pinpoint|pioneer|piranha|plumtreewebaccessor|pogodak|poirot|pompos|poppelsdorf|poppi|popular iconoclast|psycheclone|publisher|python|rambler|raven search|roach|road runner|roadhouse|robbie|robofox|robozilla|rules|salty|sbider|scooter|scoutjet|scrubby|search\.|searchprocess|semanticdiscovery|senrigan|sg\-scout|shai\'hulud|shark|shopwiki|sidewinder|sift|silk|simmany|site searcher|site valet|sitetech\-rover|skymob\.com|sleek|smartwit|sna\-|snappy|snooper|sohu|speedfind|sphere|sphider|spinner|spyder|steeler\/|suke|suntek|supersnooper|surfnomore|sven|sygol|szukacz|tach black widow|tarantula|templeton|\/teoma|t\-h\-u\-n\-d\-e\-r\-s\-t\-o\-n\-e|theophrastus|titan|titin|tkwww|toutatis|t\-rex|tutorgig|twiceler|twisted|ucsd|udmsearch|url check|updated|vagabondo|valkyrie|verticrawl|victoria|vision\-search|volcano|voyager\/|voyager\-hc|w3c_validator|w3m2|w3mir|walker|wallpaper|wanderer|wauuu|wavefire|web core|web hopper|web wombat|webbandit|webcatcher|webcopy|webfoot|weblayers|weblinker|weblog monitor|webmirror|webmonkey|webquest|webreaper|websitepulse|websnarf|webstolperer|webvac|webwalk|webwatch|webwombat|webzinger|wget|whizbang|whowhere|wild ferret|wordpress|worldlight|wwwc|wwwster|xenu|xget|xift|xirq|yandex|yanga|yeti|yodao|zao\/|zippp|zyborg|\.\.\.\.|InspectionTool)#i', (string) $http_user_agent ); return $is_bot; } $is_bot = true; return $is_bot; } //Option value filter and output function wpfo( $option = '', $echo = true, $esc = 'esc_attr' ) { if( is_string( $option ) ) { $option = stripslashes( (string) $option ); if( $esc === 'esc_attr' ) { $option = esc_attr( $option ); } elseif( $esc === 'esc_html' ) { $option = esc_html( $option ); } elseif( $esc === 'esc_url' ) { $option = esc_url( (string) $option ); } elseif( $esc === 'esc_textarea' ) { $option = esc_textarea( (string) $option ); } } if( $echo ) { echo $option; } else { return $option; } } //Option maker for checkbox, radio and select function wpfo_check( $option = '', $value = '', $type = 'checked', $echo = true ) { $option = ( isset( $option ) && isset( $value ) && $option == $value ) ? $type : ''; if( $echo ) { echo $option; } else { return $option; } } /** * Check if nested array keys exist. * * Traverses nested arrays to validate if a path of keys exists. * All arguments after $array are treated as keys to traverse - this function * does NOT support a default value parameter. * * @example * // Check if $arr['user']['profile']['name'] exists: * wpfkey( $arr, 'user', 'profile', 'name' ) // Returns true/false * * // WRONG - this tries to check $arr['key'][0], not use 0 as default: * wpfkey( $arr, 'key', 0 ) // Checks for $arr['key'][0], NOT a default! * * @param array $array The array to check * @param string|int $key First key to check * @param string|int ...$_ Additional keys to traverse (NOT a default value!) * * @return bool True if all keys exist in the nested path, false otherwise * * @see wpfval() To get the value at a nested path * @see wpffix() To get a value with a default fallback */ function wpfkey( &$array, $key ) { $a = $array; foreach( func_get_args() as $arg_num => $key ) { if( $arg_num === 0 ) continue; if( is_array( $a ) && ( is_string( $key ) || is_int( $key ) ) && array_key_exists( $key, $a ) ) { $a = $a[ $key ]; } else { return false; } } return true; } /** * Get value from nested array keys, or null if path doesn't exist. * * Traverses nested arrays to retrieve a value at a given key path. * All arguments after $array are treated as keys to traverse - this function * does NOT support a default value parameter. * * IMPORTANT: This function does NOT accept a default value! * Use wpffix() or the null coalescing operator for defaults. * * @example * // Get $arr['user']['profile']['name']: * wpfval( $arr, 'user', 'profile', 'name' ) // Returns value or null * * // WRONG - this tries to access $arr['key'][0], not use 0 as default: * wpfval( $arr, 'key', 0 ) // Accesses $arr['key'][0], NOT a default! * * // CORRECT - use ?: or ?? for defaults: * wpfval( $arr, 'key' ) ?: 'default' // Fallback for falsy values * wpfval( $arr, 'key' ) ?? 'default' // Fallback for null only * * // CORRECT - use wpffix() for defaults: * wpffix( 'default', $arr, 'key' ) // Returns 'default' if key missing * * @param mixed $array The array to traverse * @param string|int ...$_ Keys to traverse (NOT a default value!) * * @return mixed|null The value at the key path, or null if any key doesn't exist * * @see wpfkey() To check if a nested path exists * @see wpffix() To get a value with a default fallback */ function wpfval( $array ) { if( func_num_args() === 1 ) return $array; $a = $array; foreach( func_get_args() as $arg_num => $key ) { if( $arg_num === 0 ) continue; if( is_array( $a ) && ( is_string( $key ) || is_int( $key ) ) && array_key_exists( $key, $a ) ) { $a = $a[ $key ]; } else { return null; } } return $a; } /** * Always return the preferred default value if the array, or array index is undefined. * * @param mixed the default value if current index is undefined in the array * @param mixed the $array to be checked * @param string|int ... $_, ... [optional] more keys * * @return mixed|null */ function wpffix( $return, $array, $a = null, $b = null, $c = null ) { $value = wpfval( $array, $a, $b, $c ); if( ! is_null( $value ) ) { return $value; } return $return; } function wpforo_human_filesize( $bytes, $decimals = 2 ) { $size = [ 'B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ]; $factor = floor( ( strlen( (string) $bytes ) - 1 ) / 3 ); return sprintf( "%.{$decimals}f", $bytes / pow( 1024, $factor ) ) . ' ' . @$size[ $factor ]; } function wpforo_human_time_diff( int $from, bool $ago = true, int $to = 0 ): string { if( ! $to ) $to = time(); $d = human_time_diff( $from, $to ); if( $ago ) $d = sprintf( wpforo_phrase( '%s ago', false, false ), $d ); return $d; } /** * @param int | string $date * * @return int */ function wpforo_gmtimestamp( $date = 0 ): int { if( ! $date ) $date = time(); return intval( is_numeric( $date ) ? $date : strtotime( $date . ' GMT' ) ); } function wpforo_timezone( string $timezone = '' ): array { $timezone_string = ''; $current_offset = null; if( $timezone ) { if( $timezone === 'wp' ) { $timezone_string = get_option( 'timezone_string', '' ); $current_offset = get_option( 'gmt_offset', null ); } else { if( preg_match( '#UTC\s*([-+])\s*([\d.]+)#i', (string) $timezone, $timezone_array ) ) { $current_offset = $timezone_array[1] . $timezone_array[2]; } elseif( in_array( $timezone, timezone_identifiers_list() ) ) { $timezone_string = $timezone; } } } return compact( 'timezone_string', 'current_offset' ); } /** * @param int | string $date * @param string $timezone * * @return int */ function wpforo_timestamp( $date = 0, string $timezone = '' ): int { $timestamp = wpforo_gmtimestamp( $date ); $tmz = wpforo_timezone( $timezone ); if( is_numeric( $tmz['current_offset'] ) ) { $timestamp += $tmz['current_offset'] * 3600; } elseif( $tmz['timezone_string'] && class_exists( 'DateTime' ) && class_exists( 'DateTimeZone' ) ) { try { $dt = new DateTime( gmdate( 'Y-m-d H:i:s', $timestamp ), new DateTimeZone( $tmz['timezone_string'] ) ); $timestamp += $dt->getOffset(); } catch ( Exception $e ) { } } return (int) $timestamp; } /** * @param int $gmttime * @param string $format * @param bool $wp_date_format * * @return string */ function wpforo_date_format( int $gmttime, string $format, bool $wp_date_format = true ): string { if( $format === 'mysql' ) { return 'Y-m-d H:i:s'; } elseif( in_array( $format, [ 'human', 'ago', 'timestamp' ], true ) ) { return $format; } if( $format === 'ago-date' ) { $diff = time() - $gmttime; if( $diff > 31536000 ) { return apply_filters( 'wpforo_date_format_ago_date_year', 'M d, y' ); } elseif( $diff > 518400 ) { return apply_filters( 'wpforo_date_format_ago_date_month', 'M d' ); } else { return 'ago'; } } $sep = ' '; if( $wp_date_format ) { $date_format = get_option( 'date_format' ); $time_format = get_option( 'time_format' ); } else { $date_format = 'Y-m-d'; $time_format = 'H:i:s'; } if( $format === 'datetime' ) { $format = $date_format . $sep . $time_format; } elseif( $format === 'date' ) { $format = $date_format; } elseif( $format === 'time' ) { $format = $time_format; } elseif( $wp_date_format ) { $format = $date_format . $sep . $time_format; } return $format; } /** * @param $date string | int * @param $format string * @param $timezone string * * @return string | int */ function _wpforo_date( $date = 0, string $format = 'Y-m-d H:i:s', string $timezone = '' ) { if( in_array( $format, [ 'human', 'ago' ], true ) ) { $d = wpforo_human_time_diff( wpforo_gmtimestamp( $date ), $format === 'ago' ); } else { $timestamp = wpforo_timestamp( $date, $timezone ); if( $format === 'timestamp' ) { $d = $timestamp; } else { if( $format === 'mysql' ) $format = 'Y-m-d H:i:s'; $d = date_i18n( $format, $timestamp ); } } return $d; } /** * @param int | string $date * @param string $format * @param bool $echo * @param bool $wp_date_format * @param string|null $timezone * * @return string | int */ function wpforo_date( $date, $format = 'ago', $echo = true, $wp_date_format = true, $timezone = null ) { $wp_date_format = $wp_date_format && wpforo_setting( 'general', 'wp_date_format' ); $format = wpforo_date_format( wpforo_gmtimestamp( $date ), $format, $wp_date_format ); if( is_null( $timezone ) ) $timezone = ( (string) wpfval( WPF()->current_user, 'timezone' ) ?: ( (string) wpfval( $_COOKIE, 'wpforo_browser_timezone' ) ?: 'wp' ) ); $timezone = apply_filters( 'wpforo_date_timezone', $timezone ); $d = _wpforo_date( $date, $format, $timezone ); $d = apply_filters( 'wpforo_date', $d, $date, $format, $timezone ); if( $echo ) echo $d; return $d; } if( ! function_exists( 'wpforo_date_raw' ) ) { /** * @param string|int $date * @param string $format * @param bool $echo * @param string|null $timezone * * @return string | int */ function wpforo_date_raw( $date, $format = 'ago', $echo = true, $timezone = null ) { return wpforo_date( $date, $format, $echo, false, $timezone ); } } function wpforo_write_file( string $new_file, $content ): array { $return = [ 'error' => '', 'file' => '' ]; $new_file = wpforo_fix_dir_sep( $new_file ); $dir = dirname( $new_file ); if( ! is_dir( $dir ) ) wp_mkdir_p( $dir ); $ifp = @fopen( $new_file, 'wb' ); if( ! $ifp ) { if( is_resource( $ifp ) ) { @fclose( $ifp ); } $return = [ 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) ]; } else { @fwrite( $ifp, $content ); fclose( $ifp ); clearstatcache(); // Set correct file permissions $stat = @stat( dirname( $new_file ) ); $perms = $stat['mode'] & 0007777; $perms = $perms & 0000666; @chmod( $new_file, $perms ); clearstatcache(); $return['file'] = $new_file; } return $return; } function wpforo_get_file_content( $file ) { if( is_file( $file ) ) { $fp = @fopen( $file, 'r' ); if( ! $fp ) { if( is_resource( $fp ) ) { @fclose( $fp ); } } else { $size = @filesize( $file ); if( $size > 0 ) { $file_data = fread( $fp, $size ); fclose( $fp ); return $file_data; } @fclose( $fp ); } } return false; } ################################################################################ /** * Clears file basename and removes trailing slash * * @param string filename * * @return string * @since 1.0.0 * */ function wpforo_clear_basename( $file ) { $file = (string) $file; $file = str_replace( '\\', '/', $file ); $file = preg_replace( '|/+|', '/', $file ); $file = trim( (string) $file, '/' ); return $file; } ################################################################################# /** * Removes directory with all files and folders * * @param string directory name * * @since 1.0.0 * */ function _wpforo_remove_directory( $directory ) { $directory = (string) $directory; $directory = wpforo_fix_dir_sep( $directory ); $directory_ns = trim( $directory, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR; $directory_ws = DIRECTORY_SEPARATOR . trim( $directory, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR; $glob = glob( $directory_ns . '*' ); if( empty( $glob ) ) $glob = glob( $directory_ws . '*' ); foreach( $glob as $item ) { if( is_dir( $item ) ) { _wpforo_remove_directory( $item ); } else { unlink( $item ); } } return rmdir( $directory ); } ################################################################################# /** * Removes directory with all files and folders * * @param string directory name * * @since 1.0.0 * */ function wpforo_remove_directory( $file, $recursive = true ) { if( ! class_exists( 'WP_Filesystem_Direct' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php'; } $file = wpforo_fix_dir_sep( $file ); $WP_Filesystem_Direct = new WP_Filesystem_Direct( null ); return $WP_Filesystem_Direct->delete( $file, $recursive ); } ################################################################################# /** * Converts bytes to KB, MB, GB * * @param integer Bytes * * @return string * @since 1.0.0 * */ function wpforo_print_size( $value, $points = true ) { if( $value < 1024 ) { return $value . ( ( $points ) ? "B" : '' ); } elseif( $value >= 1024 && $value < ( 1024 * 1024 ) ) { $value = round( ( $value / 1024 ) * 10 ) / 10; return $value . ( ( $points ) ? "KB" : '' ); } elseif( $value >= 1024 * 1024 && $value < 1024 * 1024 * 1024 ) { $value = round( ( $value / ( 1024 * 1024 ) ) * 10 ) / 10; return $value . ( ( $points ) ? "MB" : '' ); } elseif( $value >= 1024 * 1024 * 1024 && $value <= 1024 * 1024 * 1024 * 1024 ) { $value = round( ( $value / ( 1024 * 1024 * 1024 ) ) * 10 ) / 10; return $value . ( ( $points ) ? "GB" : '' ); } else { $value = round( ( $value / ( 1024 * 1024 * 1024 * 1024 ) ) * 10 ) / 10; return $value . ( ( $points ) ? "TB" : '' ); } } function wpforo_human_size_to_bytes( $sSize ) { if( is_numeric( $sSize ) ) return $sSize; $sSuffix = substr( (string) $sSize, - 1 ); $iValue = substr( (string) $sSize, 0, - 1 ); switch( strtoupper( (string) $sSuffix ) ) { case 'M': $iValue *= 1024 * 1024; break; case 'K': $iValue *= 1024; break; case 'G': $iValue *= 1024 * 1024 * 1024; break; case 'T': $iValue *= 1024 * 1024 * 1024 * 1024; break; case 'P': $iValue *= 1024 * 1024 * 1024 * 1024 * 1024; break; } return $iValue; } function wpforo_print_number( $n, $echo = false ) { $x = str_replace( ",", "", $n ); $x = intval( $x ); $n = 0 + $x; $number = 0; if( ! is_numeric( $n ) ) return false; if( $n > 1000000000000 ) { $number = round( ( $n / 1000000000000 ), 1 ) . ' ' . str_replace( '{number}', '', wpforo_phrase( '{number}T', false ) ); } else if( $n > 1000000000 ) { $number = round( ( $n / 1000000000 ), 1 ) . ' ' . str_replace( '{number}', '', wpforo_phrase( '{number}B', false ) ); } else if( $n > 1000000 ) { $number = round( ( $n / 1000000 ), 1 ) . ' ' . str_replace( '{number}', '', wpforo_phrase( '{number}M', false ) ); } else if( $n > 10000 ) $number = round( ( $n / 1000 ), 1 ) . ' ' . str_replace( '{number}', '', wpforo_phrase( '{number}K', false ) ); $number = ( $number ) ? $number : number_format( $n ); if( $echo ) { echo $number; } else { return $number; } } function wpforo_bigintval( $value ) { $value = wpforo_settype( $value, 'string' ); if( is_string( $value ) ) { $value = trim( $value ); if( ! is_numeric( $value ) ) { $value = preg_replace( "#[^0-9].*#s", '', (string) $value ); if( ! is_numeric( $value ) ) $value = 0; } } else { $value = 0; } return ( strlen( (string) $value ) < strlen( (string) PHP_INT_MAX ) ) ? (int) $value : $value; } function wpforo_removebb( $string ) { if( isset( $string ) && $string ) { $string = preg_replace( '|\[/*[^]\[]+]|i', '', (string) $string ); } return $string; } function wpforo_file_upload_error( $code ): string { switch( $code ) { case UPLOAD_ERR_INI_SIZE: $message = wpforo_phrase( "The uploaded file exceeds the upload_max_filesize directive in php.ini", false ); break; case UPLOAD_ERR_FORM_SIZE: $message = wpforo_phrase( "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form", false ); break; case UPLOAD_ERR_PARTIAL: $message = wpforo_phrase( "The uploaded file was only partially uploaded", false ); break; case UPLOAD_ERR_NO_FILE: $message = wpforo_phrase( "No file was uploaded", false ); break; case UPLOAD_ERR_NO_TMP_DIR: $message = wpforo_phrase( "Missing a temporary folder", false ); break; case UPLOAD_ERR_CANT_WRITE: $message = wpforo_phrase( "Failed to write file to disk", false ); break; case UPLOAD_ERR_EXTENSION: $message = wpforo_phrase( "File upload stopped by extension", false ); break; default: $message = wpforo_phrase( "Unknown upload error", false ) . ": " . $code; break; } return $message; } //$key allowed values are post, strip, data, user_description entities or the name of a field filter such as pre_user_description. //More info https://core.trac.wordpress.org/browser/tags/4.5.2/src/wp-includes/kses.php#L624 function wpforo_kses( $string = '', $key = 'post' ) { if( ! $string || ! $key ) return $string; if( $key === 'email' ) { if( ! preg_match( '#
]*?>#iu', (string) $string ) ) $string = wpautop( $string );
$allowed_html = [
'a' => [ 'href' => true, 'title' => true, 'style' => true ],
'img' => [
'src' => true,
'width' => true,
'height' => true,
'align' => true,
'alt' => true,
'style' => true,
],
'blockquote' => [ 'style' => true ],
'h1' => [ 'style' => true ],
'h2' => [ 'style' => true ],
'h3' => [ 'style' => true ],
'h4' => [ 'style' => true ],
'h5' => [ 'style' => true ],
'h6' => [ 'style' => true ],
'hr' => [],
'br' => [],
'p' => [ 'style' => true ],
'strong' => [ 'style' => true ],
'em' => [ 'style' => true ],
'del' => [ 'style' => true ],
'style' => [],
];
$allowed_html = apply_filters( 'wpforo_kses_allowed_html_email', $allowed_html );
} elseif( $key === 'user_description' ) {
$allowed_html = wp_kses_allowed_html( $key );
$allowed_html['img'] = [
'alt' => true,
'align' => true,
'border' => true,
'height' => true,
'hspace' => true,
'longdesc' => true,
'vspace' => true,
'src' => true,
'usemap' => true,
'width' => true,
];
$allowed_html['br'] = [];
$allowed_html = apply_filters( 'wpforo_kses_allowed_html_user_description', $allowed_html );
} elseif( $key === 'svg' ) {
$allowed_tags = [
// HTML
'a',
'font',
'image',
'style',
// SVG
'svg',
'altglyph',
'altglyphdef',
'altglyphitem',
'animatecolor',
'animatemotion',
'animatetransform',
'circle',
'clippath',
'defs',
'desc',
'ellipse',
'filter',
'font',
'g',
'glyph',
'glyphref',
'hkern',
'image',
'line',
'lineargradient',
'marker',
'mask',
'metadata',
'mpath',
'path',
'pattern',
'polygon',
'polyline',
'radialgradient',
'rect',
'stop',
'switch',
'symbol',
'text',
'textpath',
'title',
'tref',
'tspan',
'use',
'view',
'vkern',
// SVG Filters
'feBlend',
'feColorMatrix',
'feComponentTransfer',
'feComposite',
'feConvolveMatrix',
'feDiffuseLighting',
'feDisplacementMap',
'feDistantLight',
'feFlood',
'feFuncA',
'feFuncB',
'feFuncG',
'feFuncR',
'feGaussianBlur',
'feMerge',
'feMergeNode',
'feMorphology',
'feOffset',
'fePointLight',
'feSpecularLighting',
'feSpotLight',
'feTile',
'feTurbulence',
//text
'#text',
];
$allowed_attrs = [
// HTML
'about',
'accept',
'action',
'align',
'alt',
'autocomplete',
'background',
'bgcolor',
'border',
'cellpadding',
'cellspacing',
'checked',
'cite',
'class',
'clear',
'color',
'cols',
'colspan',
'coords',
'crossorigin',
'datetime',
'default',
'dir',
'disabled',
'download',
'enctype',
'encoding',
'face',
'for',
'headers',
'height',
'hidden',
'high',
'href',
'hreflang',
'id',
'integrity',
'ismap',
'label',
'lang',
'list',
'loop',
'low',
'max',
'maxlength',
'media',
'method',
'min',
'multiple',
'name',
'noshade',
'novalidate',
'nowrap',
'open',
'optimum',
'pattern',
'placeholder',
'poster',
'preload',
'pubdate',
'radiogroup',
'readonly',
'rel',
'required',
'rev',
'reversed',
'role',
'rows',
'rowspan',
'spellcheck',
'scope',
'selected',
'shape',
'size',
'sizes',
'span',
'srclang',
'start',
'src',
'srcset',
'step',
'style',
'summary',
'tabindex',
'title',
'type',
'usemap',
'valign',
'value',
'version',
'width',
'xmlns',
// SVG
'accent-height',
'accumulate',
'additivive',
'alignment-baseline',
'ascent',
'attributename',
'attributetype',
'azimuth',
'basefrequency',
'baseline-shift',
'begin',
'bias',
'by',
'class',
'clip',
'clip-path',
'clip-rule',
'color',
'color-interpolation',
'color-interpolation-filters',
'color-profile',
'color-rendering',
'cx',
'cy',
'd',
'dx',
'dy',
'diffuseconstant',
'direction',
'display',
'divisor',
'dur',
'edgemode',
'elevation',
'end',
'fill',
'fill-opacity',
'fill-rule',
'filter',
'filterUnits',
'flood-color',
'flood-opacity',
'font-family',
'font-size',
'font-size-adjust',
'font-stretch',
'font-style',
'font-variant',
'font-weight',
'fx',
'fy',
'g1',
'g2',
'glyph-name',
'glyphref',
'gradientunits',
'gradienttransform',
'height',
'href',
'id',
'image-rendering',
'in',
'in2',
'k',
'k1',
'k2',
'k3',
'k4',
'kerning',
'keypoints',
'keysplines',
'keytimes',
'lang',
'lengthadjust',
'letter-spacing',
'kernelmatrix',
'kernelunitlength',
'lighting-color',
'local',
'marker-end',
'marker-mid',
'marker-start',
'markerheight',
'markerunits',
'markerwidth',
'maskcontentunits',
'maskunits',
'max',
'mask',
'media',
'method',
'mode',
'min',
'name',
'numoctaves',
'offset',
'operator',
'opacity',
'order',
'orient',
'orientation',
'origin',
'overflow',
'paint-order',
'path',
'pathlength',
'patterncontentunits',
'patterntransform',
'patternunits',
'points',
'preservealpha',
'preserveaspectratio',
'r',
'rx',
'ry',
'radius',
'refx',
'refy',
'repeatcount',
'repeatdur',
'restart',
'result',
'rotate',
'scale',
'seed',
'shape-rendering',
'specularconstant',
'specularexponent',
'spreadmethod',
'stddeviation',
'stitchtiles',
'stop-color',
'stop-opacity',
'stroke-dasharray',
'stroke-dashoffset',
'stroke-linecap',
'stroke-linejoin',
'stroke-miterlimit',
'stroke-opacity',
'stroke',
'stroke-width',
'style',
'surfacescale',
'tabindex',
'targetx',
'targety',
'transform',
'text-anchor',
'text-decoration',
'text-rendering',
'textlength',
'type',
'u1',
'u2',
'unicode',
'values',
'viewbox',
'visibility',
'vector-effect',
'vert-adv-y',
'vert-origin-x',
'vert-origin-y',
'width',
'word-spacing',
'wrap',
'writing-mode',
'xchannelselector',
'ychannelselector',
'x',
'x1',
'x2',
'xmlns',
'y',
'y1',
'y2',
'z',
'zoomandpan',
// MathML
'accent',
'accentunder',
'align',
'bevelled',
'close',
'columnsalign',
'columnlines',
'columnspan',
'denomalign',
'depth',
'dir',
'display',
'displaystyle',
'fence',
'frame',
'height',
// 'href',
'id',
'largeop',
'length',
'linethickness',
'lspace',
'lquote',
'mathbackground',
'mathcolor',
'mathsize',
'mathvariant',
'maxsize',
'minsize',
'movablelimits',
'notation',
'numalign',
'open',
'rowalign',
'rowlines',
'rowspacing',
'rowspan',
'rspace',
'rquote',
'scriptlevel',
'scriptminsize',
'scriptsizemultiplier',
'selection',
'separator',
'separators',
'slope',
'stretchy',
'subscriptshift',
'supscriptshift',
'symmetric',
'voffset',
'width',
'xmlns',
// XML
// 'xlink:href',
'xml:id',
'xlink:title',
'xml:space',
'xmlns:xlink',
];
$attrs = array_map( '__return_true', array_flip( $allowed_attrs ) );
$allowed_html = array_map( function() use ( $attrs ) {
return $attrs;
}, array_flip( $allowed_tags ) );
} else {
global $allowedposttags;
$allowed_html = $allowedposttags;
if( wpforo_setting( 'posting', 'content_do_shortcode' ) ) {
$allowed_html = wp_kses_allowed_html( $key );
}
$extra_html = wpforo_setting( 'posting', 'extra_html_tags' );
$allowed_html = wpforo_extra_html_parser( $extra_html, $allowed_html );
$allowed_html['a']['data-gallery'] = true;
$allowed_html['a']['download'] = true;
$allowed_html['blockquote']['class'] = true;
$allowed_html['blockquote']['data-width'] = true;
$allowed_html['blockquote']['data-userid'] = true;
$allowed_html['blockquote']['data-postid'] = true;
$allowed_html['p']['lang'] = true;
$allowed_html['p']['dir'] = true;
$allowed_html['pre']['contenteditable'] = true;
// Allow %2$s]*?src=[\'\"]([^\'\"]+\.(?:jpe?g|png|gif|bmp|webp|svg|tiff))[\'\"][^<>]*?>#iu', (string) $content, $matches, PREG_SET_ORDER ) ) {
foreach( $matches as $match ) {
if( preg_match( '#class=[\'\"]wpfem[^\'\"]*[\'\"][^<>]*?data-code=#isu', $match[0] ) ) continue;
if( strpos( (string) $match[1], 'http' ) === 0 ) {
$images[] = $match[1];
} else {
$images[] = 'http' . ( is_ssl() ? 's' : '' ) . ':' . $match[1];
}
}
} elseif( preg_match_all( '#https?://[^\r\n\t\s\'\"<>]+?\.(?:jpe?g|png|gif|bmp|webp|svg|tiff)#iu', (string) $content, $matches, PREG_SET_ORDER ) ) {
foreach( $matches as $match ) {
$images[] = $match[0];
}
} elseif( preg_match_all( '#//[^\r\n\t\s\'\"<>]+?\.(?:jpe?g|png|gif|bmp|webp|svg|tiff)#iu', (string) $content, $matches, PREG_SET_ORDER ) ) {
foreach( $matches as $match ) {
$images[] = 'http' . ( is_ssl() ? 's' : '' ) . ':' . $match[0];
}
}
}
if( $first && $images ) $images = wpfval( $images, 0 );
return apply_filters( 'wpforo_find_image_url', $images, $type, $first );
}
function wpforo_is_json( $string ) {
if( is_scalar( $string ) ) {
json_decode( $string );
return json_last_error() === JSON_ERROR_NONE;
}
return false;
}
function wpforo_ajax_response( $message ) {
wp_send_json( $message );
die();
}
function wpforo_unique_username( $username ) {
static $i;
if( ! $username ) $username = 'user_' . uniqid();
if( strpos( (string) $username, '@' ) !== false ) {
$parts = explode( "@", $username );
if( ! empty( $parts ) && isset( $parts[0] ) && $parts[0] ) {
$username = $parts[0];
} else {
$username = str_replace( '@', '', $username );
}
}
if( null === $i ) {
$i = 1;
} else {
$i ++;
}
if( ! username_exists( $username ) ) {
return $username;
}
$new_username = sprintf( '%s-%s', $username, $i );
if( ! username_exists( $new_username ) ) {
return $new_username;
} else {
return call_user_func( __FUNCTION__, $username );
}
}
function wpforo_is_session_started() {
if( php_sapi_name() !== 'cli' ) {
if( version_compare( phpversion(), '5.4.0', '>=' ) ) {
return session_status() === PHP_SESSION_ACTIVE ? true : false;
} else {
return session_id() === '' ? false : true;
}
}
return false;
}
function wpforo_current_guest( $email ) {
$guest = WPF()->member->get_guest_cookies();
if( ! wpfval( $guest, 'email' ) || ! $guest['email'] ) return false;
if( $email == $guest['email'] ) {
return true;
} else {
return false;
}
}
function wpforo_extra_html_parser( $extra_html = '', $allowed_html = [] ) {
if( $extra_html ) {
$extra_html = explode( ',', $extra_html );
$extra_html = array_filter( $extra_html );
if( ! empty( $extra_html ) ) {
foreach( $extra_html as $html ) {
$html = trim( (string) $html );
if( preg_match( '|([^()]+)\((.+)\)|', $html, $item ) ) {
if( wpfval( $item, 1 ) && wpfval( $item, 2 ) ) {
$attrs = explode( ' ', $item[2] );
$attrs = array_map( 'trim', $attrs );
foreach( $attrs as $attr ) {
$allowed_html[ $item[1] ][ $attr ] = [];
}
}
} else {
$allowed_html[ $html ] = [];
}
}
}
}
return $allowed_html;
}
function wpforo_clear_array( $array, $clear = [], $by = 'value' ) {
if( is_array( $clear ) && ! empty( $clear ) ) {
foreach( $clear as $ext ) {
if( $by == 'value' ) {
if( ( $key = array_search( $ext, $array ) ) !== false ) {
unset( $array[ $key ] );
}
} elseif( $by == 'key' ) {
if( wpfkey( $array, $ext ) ) unset( $array[ $ext ] );
}
}
} elseif( is_string( $clear ) || is_numeric( $clear ) ) {
if( wpfval( $array, $clear ) ) unset( $array[ $clear ] );
}
return $array;
}
function wpforo_key( $array = [], $value = '', $type = 'default' ) {
$keys = [];
if( is_array( $array ) && ! empty( $array ) ) {
foreach( $array as $k => $v ) {
if( $v === $value ) {
$keys[] = $k;
}
}
}
if( $type === 'sort' ) {
sort( $keys );
return $keys;
} else {
return $keys;
}
}
function wpforo_unslashe( $data ) {
$data = is_array( $data ) ? array_map( 'wpforo_unslashe', $data ) : stripslashes( (string) $data );
return $data;
}
function wpforo_encode( $data ) {
$data = is_array( $data ) ? array_map( 'wpforo_encode', $data ) : htmlspecialchars( $data, ENT_QUOTES );
return $data;
}
function wpforo_decode( $data ) {
$data = is_array( $data ) ? array_map( 'wpforo_decode', $data ) : htmlspecialchars_decode( $data, ENT_QUOTES );
return $data;
}
function wpforo_trim( $data ) {
$data = is_array( $data ) ? array_map( 'wpforo_trim', $data ) : trim( (string) $data );
return $data;
}
function wpforo_sanitize_int( $data ) {
$data = is_array( $data ) ? array_map( 'wpforo_sanitize_int', $data ) : intval( $data );
return $data;
}
function wpforo_sanitize_text( $data ) {
$data = is_array( $data ) ? array_map( 'wpforo_sanitize_text', $data ) : sanitize_text_field( $data );
return $data;
}
/**
* Sanitize orderby parameter for SQL queries.
* Validates against a whitelist of allowed column names to prevent SQL injection.
*
* @param string $orderby The orderby value to sanitize
* @param string $context The context: 'topics', 'posts', 'members', or 'search'
* @param string $default Default value if validation fails
* @return string Sanitized orderby value
*/
function wpforo_sanitize_orderby( $orderby, $context = 'topics', $default = '' ) {
$orderby = sanitize_text_field( $orderby );
// Define allowed columns for each context
$allowed = [
'topics' => [
'topicid', 'forumid', 'userid', 'title', 'slug', 'created', 'modified',
'views', 'posts', 'type', 'status', 'private', 'closed', 'solved',
'has_attach', 'first_postid', 'last_postid', 'pollid', 'prefix'
],
'posts' => [
'postid', 'forumid', 'topicid', 'userid', 'title', 'created', 'modified',
'status', 'private', 'is_answer', 'is_first_post', 'votes', 'root', 'parentid'
],
'members' => [
'userid', 'posts', 'questions', 'answers', 'comments', 'reactions', 'points',
'online_time', 'registered', 'display_name', 'user_registered'
],
'search' => [
'relevancy', 'date', 'user', 'forum', 'created', 'modified'
],
];
// Get the whitelist for this context
$whitelist = isset( $allowed[$context] ) ? $allowed[$context] : [];
// Also allow common aliases
$whitelist = array_merge( $whitelist, [ 'id', 'date', 'name' ] );
// Check if orderby is in the whitelist (case-insensitive)
$orderby_lower = strtolower( $orderby );
foreach( $whitelist as $allowed_col ) {
if( strtolower( $allowed_col ) === $orderby_lower ) {
return $allowed_col; // Return the properly cased version
}
}
// If not in whitelist, return the default
return $default;
}
if( ! function_exists( 'sanitize_textarea_field' ) && ! function_exists( '_sanitize_text_fields' ) ) {
function sanitize_textarea_field( $str ) {
$filtered = _sanitize_text_fields( $str, true );
return apply_filters( 'sanitize_textarea_field', $filtered, $str );
}
function _sanitize_text_fields( $str, $keep_newlines = false ) {
$filtered = wp_check_invalid_utf8( $str );
if( strpos( (string) $filtered, '<' ) !== false ) {
$filtered = wp_pre_kses_less_than( $filtered );
$filtered = wp_strip_all_tags( $filtered, false );
$filtered = str_replace( "<\n", "<\n", $filtered );
}
if( ! $keep_newlines ) {
$filtered = preg_replace( '/[\r\n\t ]+/', ' ', (string) $filtered );
}
$filtered = trim( (string) $filtered );
$found = false;
while( preg_match( '/%[a-f0-9]{2}/i', (string) $filtered, $match ) ) {
$filtered = str_replace( $match[0], '', $filtered );
$found = true;
}
if( $found ) {
$filtered = trim( preg_replace( '/ +/', ' ', (string) $filtered ) );
}
return $filtered;
}
}
/**
* @param string $role
*
* @return bool
*/
function wpforo_current_user_is( $role ) {
$role = strtolower( (string) $role );
$filter_result = apply_filters( 'wpforo_current_user_is', null, $role );
if( ! is_null( $filter_result ) ) return (bool) $filter_result;
switch( $role ) {
case 'admin':
if( current_user_can( 'activate_plugins' ) ) {
return true;
}
if( current_user_can( 'install_plugins' ) ) {
return true;
}
if( current_user_can( 'create_sites' ) ) {
return true;
}
break;
case 'moderator':
if( WPF()->usergroup->can( 'aum' ) ) {
return true;
}
if( current_user_can( 'moderate_comments' ) ) {
return true;
}
if( current_user_can( 'edit_published_posts' ) ) {
return true;
}
if( current_user_can( 'manage_categories' ) ) {
return true;
}
break;
}
return false;
}
/**
* @param int $userid
* @param string $role
*
* @return bool
*/
function wpforo_user_is( $userid, $role ) {
$userid = wpforo_bigintval( $userid );
$role = strtolower( (string) $role );
$filter_result = apply_filters( 'wpforo_user_is', null, $userid, $role );
if( ! is_null( $filter_result ) ) return (bool) $filter_result;
switch( $role ) {
case 'admin':
if( user_can( $userid, 'activate_plugins' ) ) {
return true;
}
if( user_can( $userid, 'install_plugins' ) ) {
return true;
}
if( user_can( $userid, 'create_sites' ) ) {
return true;
}
if( $user = WPF()->member->get_member( $userid ) ) {
if( WPF()->usergroup->can( 'mf', $user['groupids'] ) || WPF()->usergroup->can( 'ms', $user['groupids'] ) ) {
return true;
}
}
break;
case 'moderator':
if( user_can( $userid, 'moderate_comments' ) ) {
return true;
}
if( user_can( $userid, 'edit_published_posts' ) ) {
return true;
}
if( user_can( $userid, 'manage_categories' ) ) {
return true;
}
if( $user = WPF()->member->get_member( $userid ) ) {
if( WPF()->usergroup->can( 'aum', $user['groupids'] ) ) {
return true;
}
}
break;
}
return false;
}
function wpforo_random_colors() {
mt_srand( (int) ( microtime( true ) * 1000000 ) );
$color = '';
while( strlen( (string) $color ) < 6 ) {
$color .= sprintf( "%02X", mt_rand( 0, 255 ) );
}
return '#' . $color;
}
/**
* @param string $dir
*
* @return string
*/
function wpforo_fix_dir_sep( string $dir ): string {
return WPF()->fix_dir_sep( $dir );
}
/**
* @param string $url
*
* @return string
*/
function wpforo_fix_url_sep( string $url ): string {
return WPF()->fix_url_sep( $url );
}
function wpforo_root_exist() {
$args = [ 'table' => WPF()->tables->posts, 'col' => 'root', 'check' => 'col_exists' ];
return wpforo_db_check( $args );
}
function wpforo_urlencode( $str ): string {
$str = (string) $str;
if( ! preg_match( '#^(\#post-\d+|https?:|s?ftp:)$#iu', (string) $str ) && ! preg_match( '#([?&][^?&/=\r\n]*=?[^?&/=\r\n]*)(?1)*$#iu', (string) $str ) && strpos(
(string) $str,
'~'
) === false && strpos(
(string) $str,
'*'
) === false && $str === urldecode(
(string) $str
) ) {
$str = urlencode( (string) $str );
}
// Use wpforo_url_strtolower() instead of strtolower() to keep the exact values
// of GET variables in pagination buttons. Otherwise, the GET values will differ
// and the field value will be changed on the next page.
// Example: on members search page the selected "field=Test" will be changed to "field=test"
// on the next page. And the select field will loos current selected value.
return $str !== urldecode( (string) $str ) ? wpforo_url_strtolower( (string) $str ) : $str;
}
/**
* Converts the URL to lowercase.
*
* This function converts the URL to lowercase. If the $include_query parameter is set to true,
* the entire URL including the query string is converted to lowercase. Otherwise, only the part of the URL
* before the query string is converted to lowercase.
*
* @param string $url The URL to be converted to lowercase.
* @param bool $include_query Optional. Whether to include the query string in the conversion. Default is false.
*
* @return string The URL converted to lowercase.
*/
function wpforo_url_strtolower( $url, $include_query = false ): string {
// If $include_query is true, convert the entire URL to lowercase and return it.
if( $include_query ) return strtolower( $url );
// If the URL does not contain a query string, convert the entire URL to lowercase and return it.
if( strpos( $url, '?' ) === false ) {
$url = strtolower( $url );
} else {
// If the URL contains a query string, split the URL into two parts at the '?' character.
$parts = explode( '?', $url );
// Remove the last element from the $parts array and store it in $query.
$query = array_pop( $parts );
$parts = array_map( 'strtolower', $parts );
$url = implode( '?', $parts ) . '?' . $query;
}
return $url;
}
function wpforo_fix_url( string $url ): string {
$hash = '';
$url = preg_replace_callback( '#(\#[^/]*)$#iu', function( $m ) use ( &$hash ) {
$hash = $m[1];
return '';
}, $url, 1 );
if( preg_match( '#^((?:https?:|s?ftp:)//)([^?&/=\s:]+)((?::\d+)?)([^\r\n]*)#iu', (string) $url, $match ) ) {
$match[2] = wpforo_urlencode( $match[2] );
$url = $match[1] . $match[2] . $match[3] . implode( '/', array_map( 'wpforo_urlencode', explode( '/', $match[4] ) ) );
} else {
$url = implode( '/', array_map( 'wpforo_urlencode', explode( '/', $url ) ) );
}
return $url . $hash;
}
function wpforo_is_domains_equal( $url1, $url2 ) {
$domain1 = strtolower( str_replace( 'www.', '', parse_url( $url1, PHP_URL_HOST ) ) );
$domain2 = strtolower( str_replace( 'www.', '', parse_url( $url2, PHP_URL_HOST ) ) );
return $domain1 === $domain2;
}
function wpforo_is_url_internal( $url, $home_url = null ) {
$url = trim( (string) $url );
if( ! preg_match( '#^(?:https?:)?//#iu', (string) $url ) ) return true;
if( ! $home_url ) $home_url = home_url();
$home_url = trim( (string) $home_url );
$url = preg_replace( '#^(https?://)?(www\.)?#iu', '', (string) $url );
$home_url = preg_replace( [ '#^(https?://)?(www\.)?#iu', '#/?\?.*$#isu', '#index\.php/?#iu' ], '', (string) $home_url );
return strpos( (string) $url, $home_url ) === 0;
}
function wpforo_is_url_external( $url, $home_url = null ) {
return ! wpforo_is_url_internal( $url, $home_url );
}
function wpforo_settype( $var, $type ) {
$var_type = strtolower( gettype( $var ) );
$type = strtolower( (string) $type );
$allowed_types = [ 'bool', 'boolean', 'int', 'integer', 'double', 'real', 'float', 'string', 'array', 'object', 'null' ];
if( $var_type !== $type && in_array( $var_type, $allowed_types ) && in_array( $type, $allowed_types ) && $type !== 'null' && ! ( $var_type === 'object' && ! in_array( $type, [ 'boolean', 'array' ]
) ) && ! ( $var_type === 'array' && $type === 'string' ) ) {
settype( $var, $type );
}
return $var;
}
function wpforo_array_args_cast( $array, $type ) {
return array_map( function( $var ) use ( $type ) {
return wpforo_settype( $var, $type );
}, $array );
}
function wpforo_array_args_cast_and_merge( $array, $default ) {
$array = (array) $array;
$default = (array) $default;
foreach( $array as $key => $value ) {
if( array_key_exists( $key, $default ) ) {
$array[ $key ] = wpforo_settype( $value, gettype( $default[ $key ] ) );
if( is_array( $array[ $key ] ) ) {
$array[ $key ] = wpforo_array_args_cast_and_merge(
$array[ $key ],
$default[ $key ]
);
} #### do not open this comment until you have checkboxes on options settings pages
}
}
$array += $default;
return $array;
}
function wpforo_db_data_format( $var ) {
switch( gettype( $var ) ) {
case 'bool':
case 'boolean':
case 'int':
case 'integer':
return '%d';
case 'double':
case 'real':
case 'float':
return '%f';
default:
return '%s';
}
}
/**
* @param int $seconds execution time in seconds , by default 0 (unlimited)
*/
function wpforo_set_max_execution_time( $seconds = 0 ) {
if( function_exists( 'set_time_limit' ) ) @set_time_limit( $seconds );
if( function_exists( 'ini_set' ) ) @ini_set( 'max_execution_time', $seconds );
}
/**
* @param string $pattern
* @param array $array
*
* @return array
*/
function wpforo_preg_grep_recursive( $pattern, $array ) {
$m = [];
if( is_array( $array ) ) {
foreach( $array as $key => $value ) {
if( is_string( $value ) || is_numeric( $value ) ) {
if( preg_match( $pattern, (string) $value ) ) $m[ $key ] = $value;
} elseif( is_array( $value = wpforo_settype( $value, 'array' ) ) ) {
if( $_m = wpforo_preg_grep_recursive( $pattern, $value ) ) $m[ $key ] = $_m;
}
}
}
return $m;
}
function wpforo_send_new_user_notifications( $userid, $notify = 'both' ) {
if( wpforo_setting( 'email', 'disable_new_user_admin_notification' ) ) {
if( $notify !== 'admin' ) wp_send_new_user_notifications( $userid, 'user' );
} else {
wp_send_new_user_notifications( $userid, $notify );
}
}
function wpforo_get_callbacks_for_action( $hook = '' ) {
global $wp_filter;
if( empty( $hook ) || ! isset( $wp_filter[ $hook ] ) ) return [];
return $wp_filter[ $hook ]->callbacks;
}
/**
* The optimized version of wordpress url_to_postid($url) function
*
* Examine a URL and try to determine the post ID it represents.
*
* Checks are supposedly from the hosted site blog.
*
* @param string $url Permalink to check.
*
* @return int Post ID, or 0 on failure.
* @global WP $wp Current WordPress environment instance.
*
* @since 1.7.4
*
* @global WP_Rewrite $wp_rewrite WordPress rewrite component.
*/
function _wpforo_wp_url_to_postid( $url ) {
if( strpos( (string) $url, admin_url() ) !== false ) return 0;
$url_host = str_replace( 'www.', '', (string) parse_url( $url, PHP_URL_HOST ) );
$home_url_host = str_replace( 'www.', '', (string) parse_url( home_url(), PHP_URL_HOST ) );
// Bail early if the URL does not belong to this site.
if( $url_host && $url_host !== $home_url_host ) return 0;
// First, check to see if there is a 'p=N' or 'page_id=N' to match against.
if( preg_match( '#[?&](p|page_id|post_id|post|attachment_id)=(\d+)#', (string) $url, $values ) ) {
if( $id = absint( $values[2] ) ) return $id;
}
global $wp_rewrite;
if( $wp_rewrite ) {
// Get rid of the #anchor.
$url_split = explode( '#', $url );
$url = $url_split[0];
// Get rid of URL ?query=string.
$url_split = explode( '?', $url );
$url = $url_split[0];
// Set the correct URL scheme.
$scheme = parse_url( home_url(), PHP_URL_SCHEME );
$url = set_url_scheme( $url, $scheme );
// Add 'www.' if it is absent and should be there.
if( false !== strpos( home_url(), '://www.' ) && false === strpos( $url, '://www.' ) ) {
$url = str_replace( '://', '://www.', $url );
}
// Strip 'www.' if it is present and shouldn't be.
if( false === strpos( home_url(), '://www.' ) ) {
$url = str_replace( '://www.', '://', $url );
}
if( trim( (string) $url, '/' ) === home_url() && 'page' == get_option( 'show_on_front' ) ) {
$page_on_front = get_option( 'page_on_front' );
if( $page_on_front && get_post( $page_on_front ) instanceof WP_Post ) return (int) $page_on_front;
}
// Check to see if we are using rewrite rules.
$rewrite = $wp_rewrite->wp_rewrite_rules();
// Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options.
if( empty( $rewrite ) ) return 0;
// Strip 'index.php/' if we're not using path info permalinks.
if( ! $wp_rewrite->using_index_permalinks() ) {
$url = str_replace( $wp_rewrite->index . '/', '', $url );
}
if( false !== strpos( trailingslashit( (string) $url ), home_url( '/' ) ) ) {
// Chop off http://domain.com/[path].
$url = str_replace( home_url(), '', $url );
} else {
// Chop off /path/to/blog.
$home_path = parse_url( home_url( '/' ) );
$home_path = isset( $home_path['path'] ) ? $home_path['path'] : '';
$url = preg_replace( sprintf( '#^%s#', preg_quote( $home_path ) ), '', trailingslashit( (string) $url ) );
}
// Trim leading and lagging slashes.
$url = trim( (string) $url, '/' );
$request = $url;
$post_type_query_vars = [];
foreach( get_post_types( [], 'objects' ) as $post_type => $t ) {
if( ! empty( $t->query_var ) ) {
$post_type_query_vars[ $t->query_var ] = $post_type;
}
}
// Look for matches.
$request_match = $request;
foreach( (array) $rewrite as $match => $query ) {
if( preg_match( "#^$match#", (string) $request_match, $matches ) ) {
if( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)]/', (string) $query, $varmatch ) ) {
// This is a verbose page match, let's check to be sure about it.
$page = get_page_by_path( $matches[ $varmatch[1] ] );
if( ! $page ) {
continue;
}
$post_status_obj = get_post_status_object( $page->post_status );
if( ! $post_status_obj->public && ! $post_status_obj->protected && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
continue;
}
}
// Got a match.
// Trim the query of everything up to the '?'.
$query = preg_replace( '!^.+\?!', '', (string) $query );
// Substitute the substring matches into the query.
$query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
// Filter out non-public query vars.
global $wp;
parse_str( $query, $query_vars );
$query = [];
foreach( (array) $query_vars as $key => $value ) {
if( in_array( $key, $wp->public_query_vars ) ) {
$query[ $key ] = $value;
if( isset( $post_type_query_vars[ $key ] ) ) {
$query['post_type'] = $post_type_query_vars[ $key ];
$query['name'] = $value;
}
}
}
// Resolve conflicts between posts with numeric slugs and date archive queries.
$query = wp_resolve_numeric_slug_conflicts( $query );
// Do the query.
if( $p = wpforo_bigintval( wpfval( $query, 'p' ) ) ) return $p;
if( $page_id = wpforo_bigintval( wpfval( $query, 'page_id' ) ) ) return $page_id;
$pagename = wpfval( $query, 'pagename' );
$name = wpfval( $query, 'name' );
if( $pagename || $name ) {
if( ! $slug = $pagename ) $slug = $name;
$sql = "SELECT `ID` FROM `" . WPF()->db->posts . "`
WHERE `post_status` = 'publish'
AND `post_name` = %s";
$post_types = (array) apply_filters( 'wpforo_wp_url_to_postid_post_types', [ 'page', 'post' ] );
if( $post_types ) $sql .= " AND `post_type` IN('" . implode( "','", $post_types ) . "')";
$sql = WPF()->db->prepare( $sql, $slug );
$postid = WPF()->db->get_var( $sql );
if( $postid = wpforo_bigintval( $postid ) ) {
return $postid;
} else {
return 0;
}
} else {
return 0;
}
}
}
}
return 0;
}
function wpforo_wp_url_to_postid( $url ) {
return wpforo_ram_get( '_wpforo_wp_url_to_postid', $url );
}
function wpforo_get_blog_content_types() {
$post_types = get_post_types( [
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'capability_type' => 'post',
] );
$post_types['post'] = 'post';
$post_types['page'] = 'page';
unset( $post_types['attachment'] );
$post_types = array_filter( array_keys( $post_types ) );
return apply_filters( 'wpforo_get_blog_content_types', $post_types );
}
/**
* @param string $css
*
* @return string
*/
function wpforo_add_wrapper( $css ) {
$css = preg_replace( '@(#(?:wpforo-wrap|wpfa_dialog|wpfa_dialog_wrap)[\s.#{:>+\[~,])@um', '#wpforo $1', (string) $css );
return preg_replace( '@(#(?:wpforo|wpforo-wrap|wpfa_dialog|wpfa_dialog_wrap)\s*)#wpforo[\s.#{:>+\[~,]@um', '$1', (string) $css );
}
/**
* @param string $css
*
* @return string
*/
function wpforo_wrap_fix_in_css( $css ) {
if( ( strpos( (string) $css, '#wpforo-wrap' ) !== false && strpos( (string) $css, '#wpforo #wpforo-wrap' ) === false ) || ( strpos( (string) $css, '#wpfa_dialog' ) !== false && strpos(
(string) $css,
'#wpforo #wpfa_dialog'
) === false ) ) {
$css = wpforo_add_wrapper( $css );
}
return $css;
}
/**
* @param string $csspath
*/
function wpforo_wrap_fix_in_cssfile( $csspath ) {
$csspath = wpforo_fix_dir_sep( $csspath );
if( is_file( $csspath ) ) {
$css = wpforo_get_file_content( $csspath );
$css = wpforo_wrap_fix_in_css( $css );
if( md5( $css ) !== md5_file( $csspath ) ) wpforo_write_file( $csspath, $css );
}
}
function wpforo_wrap_in_all_addons_css() {
$csspaths = [
'/wpforo-ad-manager/assets/css/style.css',
'/wpforo-advanced-attachments/assets/css/style.css',
'/wpforo-cross-posting/assets/css/wpdiscuz-uploader.css',
'/wpforo-cross-posting/assets/css/wpforo-cross-rtl.css',
'/wpforo-cross-posting/assets/css/wpforo-cross.css',
'/wpforo-embeds/assets/css/embed.css',
'/wpforo-emoticons/assets/emoticons.css',
'/wpforo-mycred/css/mycread.css',
'/wpforo-polls/assets/css/poll.css',
'/wpforo-private-messages/assets/css/style-rtl.css',
'/wpforo-private-messages/assets/css/style.css',
'/wpforo-user-custom-fields/assets/css/frontend.css',
];
foreach( $csspaths as $csspath ) wpforo_wrap_fix_in_cssfile( WP_PLUGIN_DIR . $csspath );
WPF()->dissmissed['addons_css_update'] = 1;
wpforo_update_option( 'dissmissed', WPF()->dissmissed );
}
/*add_action( 'admin_notices', function() {
if( ! (int) wpfval( WPF()->dissmissed, 'addons_css_update' ) ) {
$has_addon = false;
foreach( wpforo_get_addons_info() as $addon ) {
if( class_exists( $addon['class'] ) ) {
$has_addon = true;
break;
}
}
if( ! $has_addon ) return;
$class = 'notice notice-warning';
$message = '
' . __( 'Action Required!', 'wpforo' ) . '' . __( 'Please update wpForo addons CSS style to make compatible with the current version of wpForo.', 'wpforo' ) . '' . '
';
$message .= '' . __( 'Update CSS >>', 'wpforo' ) . '';
printf( '
%2$s', esc_url( (string) $unsubscribe_link ), wpforo_phrase( 'Unsubscribe', false ) );
$value = stripslashes( $value );
}
} elseif( strpos( (string) $shortcode, '[user_' ) === 0 ) {
if( wpforo_bigintval( wpfval( $user, 'userid' ) ) ) {
$value = wpforo_user_field_shortcode_to_value( $shortcode, $user['userid'] );
if( ! $value || ! ( is_string( $value ) || is_numeric( $value ) ) ) {
$value = '';
}
} else {
if( $shortcode === '[user_display_name]' ) {
$value = wpfval( $user, 'display_name' ) ?: wpforo_phrase( 'Anonymous', false );
} elseif( $shortcode === '[user_user_email]' ) {
$value = (string) wpfval( $user, 'user_email' );
}
}
} elseif( strpos( (string) $shortcode, '[owner_' ) === 0 ) {
if( wpforo_bigintval( wpfval( $owner, 'userid' ) ) ) {
$value = wpforo_user_field_shortcode_to_value( $shortcode, $owner['userid'] );
if( ! $value || ! ( is_string( $value ) || is_numeric( $value ) ) ) {
$value = '';
}
} else {
if( $shortcode === '[owner_display_name]' ) {
$value = wpfval( $owner, 'display_name' ) ?: wpforo_phrase( 'Anonymous', false );
} elseif( $shortcode === '[owner_user_email]' ) {
$value = (string) wpfval( $owner, 'user_email' );
}
}
} elseif( strpos( (string) $shortcode, '[forum_' ) === 0 ) {
if( $forumid ) {
$value = wpforo_forum_field_shortcode_to_value( $shortcode, $forumid );
if( ! $value || ! ( is_string( $value ) || is_numeric( $value ) ) ) {
$value = '';
}
}
} elseif( strpos( (string) $shortcode, '[topic_' ) === 0 ) {
if( $topicid ) {
$value = wpforo_topic_field_shortcode_to_value( $shortcode, $topicid );
if( ! $value || ! ( is_string( $value ) || is_numeric( $value ) ) ) {
$value = '';
} elseif( $shortcode === '[topic_body]' ) {
$value = wpforo_text( wpforo_kses( wpforo_content_filter( $value ), 'email' ), $body_length, false, false, false, true, false );
}
}
} elseif( strpos( (string) $shortcode, '[post_' ) === 0 ) {
if( $postid ) {
$value = wpforo_post_field_shortcode_to_value( $shortcode, $postid );
if( ! $value || ! ( is_string( $value ) || is_numeric( $value ) ) ) {
$value = '';
} elseif( $shortcode === '[post_body]' ) {
$value = wpforo_text( wpforo_kses( wpforo_content_filter( $value ), 'email' ), $body_length, false, false, false, true, false );
}
}
}
return $value;
}, (string) $txt );
}
function wpforo_apply_email_shortcodes( $txt, $pitem, $item, $owner, $user, $unsubscribe_link ) {
$forumid = ( intval( wpfval( $pitem, 'forumid' ) ) ?: intval( wpfval( $item, 'forumid' ) ) );
$topicid = ( wpforo_bigintval( wpfval( $pitem, 'topicid' ) ) ?: wpforo_bigintval( wpfval( $item, 'topicid' ) ) );
$postid = ( wpforo_bigintval( wpfval( $item, 'postid' ) ) ?: wpforo_bigintval( wpfval( $item, 'first_postid' ) ) );
return _wpforo_apply_email_shortcodes( $txt, compact( 'forumid', 'topicid', 'postid', 'owner', 'user', 'unsubscribe_link' ) );
}
function wpforo_send_email( $email, $sbj, $msg, $headers = '', $context = 'general', $related_id = 0 ) {
if( defined( 'IS_GO2WPFORO' ) && IS_GO2WPFORO ) return false;
if( apply_filters( 'break_wpforo_send_email', false, $email, $sbj, $msg, $headers ) ) return false;
$key = [ $email, $sbj, substr( $msg, 0, 100 ) ];
if( WPF()->ram_cache->exists( $key ) ) return false;
if( isset( WPF()->email_queue ) ) {
$result = WPF()->email_queue->queue_or_send( $email, $sbj, $msg, $headers, $context, $related_id );
} else {
add_filter( 'wp_mail_content_type', 'wpforo_set_html_content_type', 999 );
$result = wp_mail( $email, $sbj, $msg, ( $headers ?: wpforo_mail_headers() ) );
remove_filter( 'wp_mail_content_type', 'wpforo_set_html_content_type' );
}
if( $result ) {
WPF()->ram_cache->set( $key, true );
return true;
}
return false;
}
function wpforo_get_site_default_locale() {
$locale = trim( (string) get_option( 'WPLANG', 'en_US' ) );
if( ! $locale ) $locale = 'en_US';
return $locale;
}
function wpforo_sanitize( $action, $variable_name, $filter, $default = '' ) {
if( $filter === "FILTER_SANITIZE_STRING" ) {
$glob = INPUT_POST === $action ? $_POST : $_GET;
if( wpfkey( $glob, $variable_name ) ) {
return sanitize_text_field( $glob[ $variable_name ] );
} else {
return $default;
}
}
$variable = isset( $variable_name ) ? filter_input( $action, $variable_name, $filter ) : '';
return $variable ?: $default;
}
function wpforo_length( $str, $filtered = true ) {
$str = $filtered ? strip_tags( trim( (string) $str ) ) : $str;
if( function_exists( 'mb_substr' ) ) {
$length = mb_strlen( (string) $str, get_option( 'blog_charset' ) );
} else {
$length = strlen( (string) $str );
}
return (int) $length;
}
if( ! function_exists( 'wpforo_remote_retrieve_header' ) ) {
/**
*
* @param array|WP_Error $response HTTP response.
* @param string $header Header name to retrieve value from.
*
* @return string string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
*/
function wpforo_remote_retrieve_header( $response, $header ) {
$header = wp_remote_retrieve_header( $response, $header );
if( is_array( $header ) ) $header = (string) array_pop( $header );
return $header;
}
}
function wpforo_is_array_of_scalars( $array ) {
if( ! is_array( $array ) ) return false;
foreach( $array as $element ) if( ! is_scalar( $element ) ) return false;
return true;
}
function wpforo_is_gzipped( $contents ): bool {
// phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found
if( function_exists( 'mb_strpos' ) ) {
return 0 === mb_strpos( $contents, "\x1f" . "\x8b" . "\x08" );
} else {
return 0 === strpos( $contents, "\x1f" . "\x8b" . "\x08" );
}
// phpcs:enable
}
function wpforo_sanitize_svg( $file ): bool {
$dirty = file_get_contents( $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
// Is the SVG gzipped? If so we try and decode the string
$is_zipped = wpforo_is_gzipped( $dirty );
if( $is_zipped ) {
$dirty = gzdecode( $dirty );
// If decoding fails, bail as we're not secure
if( false === $dirty ) {
return false;
}
}
$clean = trim( wpforo_kses( $dirty, 'svg' ) );
if( ! $clean ) {
return false;
}
// If we were gzipped, we need to re-zip
if( $is_zipped ) {
$clean = gzencode( $clean );
}
file_put_contents( $file, $clean ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
return true;
}
function wpforo_check_for_svg( $file ) {
// Ensure we have a proper file path before processing
if( ! isset( $file['tmp_name'] ) ) {
return $file;
}
$wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], ( $file['name'] ?? '' ), [] );
$type = ! empty( $wp_filetype['type'] ) ? $wp_filetype['type'] : (string) wpfval( $file, 'type' );
if( in_array( $type, [ 'image/svg+xml', 'image/svg' ], true ) ) {
if( ! wpforo_sanitize_svg( $file['tmp_name'] ) ) {
$file['error'] = __(
"Sorry, this file couldn't be sanitized so for security reasons wasn't uploaded",
'wpforo'
);
}
}
return $file;
}
/**
* Custom function to replace is_numeric() function avoiding negative
* numbers to be considered as numeric. This is mostly used differentiating
* between ID and slugs. Sometimes slugs can be like "-12345".
*
* @param mixed $value
*
* @return bool
*/
function wpforo_is_id( $value ) {
return is_numeric( $value ) && (int) $value >= 0;
}
function is_avatar_url( string $url ): bool {
// Check if the string is a valid URL
if( filter_var( $url, FILTER_VALIDATE_URL ) ) {
// Make a HEAD request to check the Content-Type
$response = wp_safe_remote_head( $url );
if( ! is_wp_error( $response ) ) {
$content_type = wp_remote_retrieve_header( $response, 'content-type' );
// Check if the Content-Type is an image
if( strpos( $content_type, 'image/' ) !== false ) {
return true; // The URL points to an image
}
}
}
return false; // Not a valid avatar URL
}
/**
* Function to generate image object for DiscussionForumPosting schema JSON-LD
*
* @param string $content
*
* @return string
*/
function wpforo_generate_scheme_image_object( $content ) {
$image = '';
if( function_exists( 'WPF_ATTACH' ) ) {
$content = WPF_ATTACH()->tools->do_shortcodes( $content );
}
# TODO: Add support for secure URLs w/o image extensions
# Currently, only URLs with image extensions are supported
# by wpforo_find_image_urls() function.
$images = wpforo_find_image_urls( $content, false );
if( ! empty( $images ) ) {
$image = '"image": [';
foreach( $images as $img ) {
$image .= '{ "@type": "ImageObject", "url": "' . esc_url_raw( $img ) . '"},';
}
$image = trim( $image, ',' ) . '],';
}
return $image;
}
function wpforo_generate_scheme_author_object( $user_id ) {
$author = '';
$post_member = wpforo_member( $user_id );
$author_posts = wpfval( $post_member, 'posts' ) ? $post_member['posts'] : 1;
$author_name = wpfval( $post_member, 'display_name' ) ? $post_member['display_name'] : 'Guest';
$author_url = wpfval( $post_member, 'profile_url' ) ? '
"url": "' . esc_url_raw( $post_member['profile_url'] ) . '",' : '';
$author = ',
"author": {
"@type": "Person",
"name": "' . esc_attr( $author_name ) . '",' . $author_url . '
"agentInteractionStatistic": {
"@type": "InteractionCounter",
"interactionType": "https://schema.org/WriteAction",
"userInteractionCount": ' . intval( $author_posts ) . '
}
}';
return $author;
}
/**
* Get wpForo home URL for a specific language/locale
*
* @param string $language Language code (e.g., 'de_DE', 'en_US', 'fr_FR')
* @return string Forum home URL for the specified language
*/
function wpforo_get_home_url_for_language( $language ) {
$sql = WPF()->db->prepare(
"SELECT * FROM " . WPF()->tables->boards . " WHERE status = 1 AND locale = %s LIMIT 1",
sanitize_locale_name($language)
);
$board = (array) WPF()->db->get_row( $sql, ARRAY_A );
if( $board ) $board = WPF()->board->decode( $board );
if( !$board ) {
return home_url(); // Fallback to default
}
return trailingslashit( home_url( $board['slug'] ) );
}
function wpforo_get_current_language_url( $url = '' ) {
$url = ( $url ) ? $url : '';
if( function_exists( 'pll_current_language' ) && $language = pll_current_language( 'locale' ) ) {
$sql = WPF()->db->prepare(
"SELECT * FROM " . WPF()->tables->boards . " WHERE status = 1 AND locale = %s LIMIT 1",
sanitize_locale_name($language)
);
$board = (array) WPF()->db->get_row( $sql, ARRAY_A );
if( $boardid = wpfval($board, 'boardid') ){
$url = ( $url ) ? $url : $_SERVER['REQUEST_URI'];
$url = add_query_arg( 'boardid', intval( $boardid ), $_SERVER['REQUEST_URI'] );
}
}
return $url;
}
/**
* Centralized logging function for wpForo AI features.
*
* Nothing is logged unless wpforo General > Debug Mode is enabled
* OR WordPress WP_DEBUG is on. This ensures zero disk usage on production sites.
*
* Log levels: 'error', 'info', 'debug'
* - error: Logged when WP_DEBUG is on OR wpforo Debug Mode is on
* - info: Logged only when BOTH WP_DEBUG and wpforo Debug Mode are on
* - debug: Logged when wpforo Debug Mode is on (with or without WP_DEBUG)
*
* Logs are written to: wp-content/uploads/wpforo/ai-logs/{Y-m-d}.log
*
* @param string $level Log level: 'error', 'info', or 'debug'
* @param string $message Log message
* @param string $tag Component tag, e.g. 'Moderation', 'Client', 'VectorStorage'
*/
function wpforo_ai_log( $level, $message, $tag = '' ) {
static $enabled_levels = null;
static $log_dir = null;
// Resolve enabled levels once per request
if ( $enabled_levels === null ) {
$enabled_levels = [];
$wpforo_debug = wpforo_setting( 'general', 'debug_mode' );
$wp_debug = defined( 'WP_DEBUG' ) && WP_DEBUG;
if ( $wp_debug || $wpforo_debug ) {
$enabled_levels[] = 'error';
}
if ( $wpforo_debug ) {
$enabled_levels[] = 'debug';
}
if ( $wp_debug && $wpforo_debug ) {
$enabled_levels[] = 'info';
}
}
if ( ! in_array( $level, $enabled_levels, true ) ) {
return;
}
// Resolve log directory once per request
if ( $log_dir === null ) {
$upload_dir = wp_upload_dir();
$log_dir = $upload_dir['basedir'] . '/wpforo/ai-logs';
if ( ! is_dir( $log_dir ) ) {
wp_mkdir_p( $log_dir );
@file_put_contents( $log_dir . '/index.php', " '2-letter ISO code', 'locale' => 'WordPress locale', 'name' => 'English name', 'native' => 'Native name' ]
*
* @return array
*/
function wpforo_get_ai_languages() {
return [
// Major world languages
[ 'code' => 'en', 'locale' => 'en_US', 'name' => 'English', 'native' => 'English' ],
[ 'code' => 'en', 'locale' => 'en_GB', 'name' => 'English (UK)', 'native' => 'English (UK)' ],
[ 'code' => 'zh', 'locale' => 'zh_CN', 'name' => 'Chinese Simplified', 'native' => '简体中文' ],
[ 'code' => 'zh', 'locale' => 'zh_TW', 'name' => 'Chinese Traditional', 'native' => '繁體中文' ],
[ 'code' => 'es', 'locale' => 'es_ES', 'name' => 'Spanish', 'native' => 'Español' ],
[ 'code' => 'hi', 'locale' => 'hi_IN', 'name' => 'Hindi', 'native' => 'हिन्दी' ],
[ 'code' => 'ar', 'locale' => 'ar', 'name' => 'Arabic', 'native' => 'العربية' ],
[ 'code' => 'pt', 'locale' => 'pt_BR', 'name' => 'Portuguese (Brazil)', 'native' => 'Português Brasil' ],
[ 'code' => 'pt', 'locale' => 'pt_PT', 'name' => 'Portuguese', 'native' => 'Português' ],
[ 'code' => 'bn', 'locale' => 'bn_BD', 'name' => 'Bengali', 'native' => 'বাংলা' ],
[ 'code' => 'ru', 'locale' => 'ru_RU', 'name' => 'Russian', 'native' => 'Русский' ],
[ 'code' => 'ja', 'locale' => 'ja', 'name' => 'Japanese', 'native' => '日本語' ],
[ 'code' => 'fr', 'locale' => 'fr_FR', 'name' => 'French', 'native' => 'Français' ],
[ 'code' => 'de', 'locale' => 'de_DE', 'name' => 'German', 'native' => 'Deutsch' ],
[ 'code' => 'ko', 'locale' => 'ko_KR', 'name' => 'Korean', 'native' => '한국어' ],
[ 'code' => 'it', 'locale' => 'it_IT', 'name' => 'Italian', 'native' => 'Italiano' ],
[ 'code' => 'tr', 'locale' => 'tr_TR', 'name' => 'Turkish', 'native' => 'Türkçe' ],
[ 'code' => 'vi', 'locale' => 'vi_VN', 'name' => 'Vietnamese', 'native' => 'Tiếng Việt' ],
[ 'code' => 'pl', 'locale' => 'pl_PL', 'name' => 'Polish', 'native' => 'Polski' ],
[ 'code' => 'nl', 'locale' => 'nl_NL', 'name' => 'Dutch', 'native' => 'Nederlands' ],
[ 'code' => 'th', 'locale' => 'th', 'name' => 'Thai', 'native' => 'ไทย' ],
[ 'code' => 'id', 'locale' => 'id_ID', 'name' => 'Indonesian', 'native' => 'Bahasa Indonesia' ],
[ 'code' => 'ms', 'locale' => 'ms_MY', 'name' => 'Malay', 'native' => 'Bahasa Melayu' ],
// European languages
[ 'code' => 'uk', 'locale' => 'uk', 'name' => 'Ukrainian', 'native' => 'Українська' ],
[ 'code' => 'ro', 'locale' => 'ro_RO', 'name' => 'Romanian', 'native' => 'Română' ],
[ 'code' => 'el', 'locale' => 'el_GR', 'name' => 'Greek', 'native' => 'Ελληνικά' ],
[ 'code' => 'cs', 'locale' => 'cs_CZ', 'name' => 'Czech', 'native' => 'Čeština' ],
[ 'code' => 'sv', 'locale' => 'sv_SE', 'name' => 'Swedish', 'native' => 'Svenska' ],
[ 'code' => 'hu', 'locale' => 'hu_HU', 'name' => 'Hungarian', 'native' => 'Magyar' ],
[ 'code' => 'da', 'locale' => 'da_DK', 'name' => 'Danish', 'native' => 'Dansk' ],
[ 'code' => 'fi', 'locale' => 'fi', 'name' => 'Finnish', 'native' => 'Suomi' ],
[ 'code' => 'no', 'locale' => 'no_NO', 'name' => 'Norwegian', 'native' => 'Norsk' ],
[ 'code' => 'sk', 'locale' => 'sk_SK', 'name' => 'Slovak', 'native' => 'Slovenčina' ],
[ 'code' => 'bg', 'locale' => 'bg_BG', 'name' => 'Bulgarian', 'native' => 'Български' ],
[ 'code' => 'hr', 'locale' => 'hr', 'name' => 'Croatian', 'native' => 'Hrvatski' ],
[ 'code' => 'sr', 'locale' => 'sr_RS', 'name' => 'Serbian', 'native' => 'Српски' ],
[ 'code' => 'sl', 'locale' => 'sl_SI', 'name' => 'Slovenian', 'native' => 'Slovenščina' ],
[ 'code' => 'lt', 'locale' => 'lt_LT', 'name' => 'Lithuanian', 'native' => 'Lietuvių' ],
[ 'code' => 'lv', 'locale' => 'lv', 'name' => 'Latvian', 'native' => 'Latviešu' ],
[ 'code' => 'et', 'locale' => 'et', 'name' => 'Estonian', 'native' => 'Eesti' ],
[ 'code' => 'ca', 'locale' => 'ca', 'name' => 'Catalan', 'native' => 'Català' ],
[ 'code' => 'gl', 'locale' => 'gl_ES', 'name' => 'Galician', 'native' => 'Galego' ],
[ 'code' => 'eu', 'locale' => 'eu', 'name' => 'Basque', 'native' => 'Euskara' ],
[ 'code' => 'sq', 'locale' => 'sq', 'name' => 'Albanian', 'native' => 'Shqip' ],
[ 'code' => 'mk', 'locale' => 'mk_MK', 'name' => 'Macedonian', 'native' => 'Македонски' ],
[ 'code' => 'bs', 'locale' => 'bs_BA', 'name' => 'Bosnian', 'native' => 'Bosanski' ],
[ 'code' => 'mt', 'locale' => 'mt_MT', 'name' => 'Maltese', 'native' => 'Malti' ],
[ 'code' => 'is', 'locale' => 'is_IS', 'name' => 'Icelandic', 'native' => 'Íslenska' ],
[ 'code' => 'ga', 'locale' => 'ga', 'name' => 'Irish', 'native' => 'Gaeilge' ],
[ 'code' => 'cy', 'locale' => 'cy', 'name' => 'Welsh', 'native' => 'Cymraeg' ],
[ 'code' => 'be', 'locale' => 'be_BY', 'name' => 'Belarusian', 'native' => 'Беларуская' ],
[ 'code' => 'lb', 'locale' => 'lb_LU', 'name' => 'Luxembourgish', 'native' => 'Lëtzebuergesch' ],
// Middle Eastern & Central Asian
[ 'code' => 'he', 'locale' => 'he_IL', 'name' => 'Hebrew', 'native' => 'עברית' ],
[ 'code' => 'fa', 'locale' => 'fa_IR', 'name' => 'Persian', 'native' => 'فارسی' ],
[ 'code' => 'ur', 'locale' => 'ur', 'name' => 'Urdu', 'native' => 'اردو' ],
[ 'code' => 'ku', 'locale' => 'ku', 'name' => 'Kurdish', 'native' => 'Kurdî' ],
[ 'code' => 'az', 'locale' => 'az', 'name' => 'Azerbaijani', 'native' => 'Azərbaycan' ],
[ 'code' => 'ka', 'locale' => 'ka_GE', 'name' => 'Georgian', 'native' => 'ქართული' ],
[ 'code' => 'hy', 'locale' => 'hy', 'name' => 'Armenian', 'native' => 'Հայերեն' ],
[ 'code' => 'kk', 'locale' => 'kk', 'name' => 'Kazakh', 'native' => 'Қазақша' ],
[ 'code' => 'uz', 'locale' => 'uz_UZ', 'name' => 'Uzbek', 'native' => 'Oʻzbek' ],
[ 'code' => 'tg', 'locale' => 'tg', 'name' => 'Tajik', 'native' => 'Тоҷикӣ' ],
[ 'code' => 'ky', 'locale' => 'ky_KY', 'name' => 'Kyrgyz', 'native' => 'Кыргызча' ],
[ 'code' => 'tk', 'locale' => 'tk', 'name' => 'Turkmen', 'native' => 'Türkmen' ],
[ 'code' => 'mn', 'locale' => 'mn', 'name' => 'Mongolian', 'native' => 'Монгол' ],
// South Asian
[ 'code' => 'ta', 'locale' => 'ta_IN', 'name' => 'Tamil', 'native' => 'தமிழ்' ],
[ 'code' => 'te', 'locale' => 'te', 'name' => 'Telugu', 'native' => 'తెలుగు' ],
[ 'code' => 'mr', 'locale' => 'mr', 'name' => 'Marathi', 'native' => 'मराठी' ],
[ 'code' => 'gu', 'locale' => 'gu', 'name' => 'Gujarati', 'native' => 'ગુજરાતી' ],
[ 'code' => 'kn', 'locale' => 'kn', 'name' => 'Kannada', 'native' => 'ಕನ್ನಡ' ],
[ 'code' => 'ml', 'locale' => 'ml_IN', 'name' => 'Malayalam', 'native' => 'മലയാളം' ],
[ 'code' => 'pa', 'locale' => 'pa_IN', 'name' => 'Punjabi', 'native' => 'ਪੰਜਾਬੀ' ],
[ 'code' => 'si', 'locale' => 'si_LK', 'name' => 'Sinhala', 'native' => 'සිංහල' ],
[ 'code' => 'ne', 'locale' => 'ne_NP', 'name' => 'Nepali', 'native' => 'नेपाली' ],
[ 'code' => 'my', 'locale' => 'my_MM', 'name' => 'Burmese', 'native' => 'မြန်မာ' ],
[ 'code' => 'km', 'locale' => 'km', 'name' => 'Khmer', 'native' => 'ខ្មែរ' ],
[ 'code' => 'lo', 'locale' => 'lo', 'name' => 'Lao', 'native' => 'ລາວ' ],
// East & Southeast Asian
[ 'code' => 'tl', 'locale' => 'tl', 'name' => 'Filipino', 'native' => 'Filipino' ],
[ 'code' => 'jv', 'locale' => 'jv_ID', 'name' => 'Javanese', 'native' => 'Basa Jawa' ],
[ 'code' => 'su', 'locale' => 'su_ID', 'name' => 'Sundanese', 'native' => 'Basa Sunda' ],
// African languages
[ 'code' => 'sw', 'locale' => 'sw', 'name' => 'Swahili', 'native' => 'Kiswahili' ],
[ 'code' => 'am', 'locale' => 'am', 'name' => 'Amharic', 'native' => 'አማርኛ' ],
[ 'code' => 'ha', 'locale' => 'ha', 'name' => 'Hausa', 'native' => 'Hausa' ],
[ 'code' => 'yo', 'locale' => 'yo', 'name' => 'Yoruba', 'native' => 'Yorùbá' ],
[ 'code' => 'ig', 'locale' => 'ig_NG', 'name' => 'Igbo', 'native' => 'Igbo' ],
[ 'code' => 'zu', 'locale' => 'zu', 'name' => 'Zulu', 'native' => 'isiZulu' ],
[ 'code' => 'xh', 'locale' => 'xh', 'name' => 'Xhosa', 'native' => 'isiXhosa' ],
[ 'code' => 'af', 'locale' => 'af', 'name' => 'Afrikaans', 'native' => 'Afrikaans' ],
[ 'code' => 'so', 'locale' => 'so_SO', 'name' => 'Somali', 'native' => 'Soomaali' ],
[ 'code' => 'rw', 'locale' => 'rw_RW', 'name' => 'Kinyarwanda', 'native' => 'Kinyarwanda' ],
[ 'code' => 'mg', 'locale' => 'mg_MG', 'name' => 'Malagasy', 'native' => 'Malagasy' ],
// Other
[ 'code' => 'eo', 'locale' => 'eo', 'name' => 'Esperanto', 'native' => 'Esperanto' ],
[ 'code' => 'la', 'locale' => 'la', 'name' => 'Latin', 'native' => 'Latina' ],
];
}