├── README.md ├── assets ├── blocks.css ├── blocks.min.css └── svg │ ├── LICENSE │ ├── gist.svg │ └── package.svg ├── gutenblocks.php ├── inc ├── classes │ └── gutenblocks-flagmaster.php ├── functions.php └── upgrade.php ├── js └── blocks │ ├── gist.js │ ├── gist.min.js │ ├── i18n.js │ ├── i18n.min.js │ ├── release.js │ └── release.min.js └── languages ├── gutenblocks-en_US.mo ├── gutenblocks-en_US.po └── gutenblocks.pot /README.md: -------------------------------------------------------------------------------- 1 | # GutenBlocks 2 | 3 | ** This WP plugin has been archived and is no more maintained. ** 4 | 5 | WordPress plugin to house my personal collection of custom blocks for Gutenberg. 6 | 7 | ## GitHub Gist 8 | 9 | ![Gist Block](https://c1.staticflickr.com/5/4725/38682277204_41e3b9ee9d_o.png) 10 | 11 | This block lets us add GitHub Gists using their URL. 12 | 13 | ## GitHub Release 14 | 15 | ![GitHub Release](https://c1.staticflickr.com/5/4589/39434045721_eb7c49a4db_o.png) 16 | 17 | This dynamic block will display a Plugin card on your front-end. A link to the 'WordPress ready' zip package of the plugin release will be included (`plugin-name.zip`). 18 | 19 | ## Dubber 20 | 21 | ![GitHub Release](https://cldup.com/-TFW45q_3n.png) 22 | 23 | An experimental block to use the Gutenberg Blocks API to translate your content. 24 | -------------------------------------------------------------------------------- /assets/blocks.css: -------------------------------------------------------------------------------- 1 | /* Style for blocks */ 2 | 3 | /* GitHub ********************************************************************/ 4 | 5 | .wp-block-gutenblocks-gist .gist .blob-num { 6 | border: none; 7 | } 8 | 9 | [data-type="gutenblocks/gist"] .components-placeholder__label label:before { 10 | display: inline-block; 11 | content:""; 12 | width: 20px; 13 | height: 20px; 14 | background: url( 'svg/gist.svg' ) no-repeat; 15 | background-size: contain; 16 | vertical-align: -5px; 17 | } 18 | 19 | [data-type="gutenblocks/gist"] .wp-block-embed.is-loading { 20 | background: none; 21 | } 22 | 23 | [data-type="gutenblocks/release"] .plugin-card { 24 | float: none; 25 | margin: 0; 26 | width: 100%; 27 | } 28 | 29 | [data-type="gutenblocks/release"] .plugin-card-top { 30 | width: 75%; 31 | margin: 1em auto; 32 | } 33 | 34 | [data-type="gutenblocks/release"] .plugin-card-top .release-icon, 35 | body:not(.wp-admin) .plugin-card-top .release-icon { 36 | float:left; 37 | top: 20px; 38 | left: 20px; 39 | width: 128px; 40 | height: 128px; 41 | margin: 0 18px 20px 0; 42 | box-shadow: none; 43 | border: none; 44 | } 45 | 46 | [data-type="gutenblocks/release"] .plugin-card-top h3 input[type="text"] { 47 | width: calc( 100% - 148px ); 48 | } 49 | 50 | [data-type="gutenblocks/release"] .plugin-card-top .column-description { 51 | margin-left: 148px; 52 | margin-right: 0px; 53 | } 54 | 55 | [data-type="gutenblocks/release"] .plugin-card-top .column-description textarea { 56 | width: 100%; 57 | } 58 | 59 | [data-type="gutenblocks/release"] .plugin-card-top .download, 60 | body:not(.wp-admin) .plugin-card-top .download { 61 | clear: both; 62 | text-align: center; 63 | } 64 | 65 | [data-type="gutenblocks/release"] .plugin-card-top .download .dashicons { 66 | vertical-align: middle; 67 | } 68 | 69 | [data-type="gutenblocks/release"] .required-fields { 70 | margin: 1em; 71 | padding-bottom: 1em; 72 | } 73 | 74 | [data-type="gutenblocks/release"] .required-fields input[type="text"] { 75 | width: 98%; 76 | display: block; 77 | } 78 | 79 | [data-type="gutenblocks/release"] .required-fields label { 80 | font-weight: bold; 81 | } 82 | 83 | .plugin-card .download button.button.gh-download-button img { 84 | box-shadow: none; 85 | border: none; 86 | width: 20px; 87 | height: 20px; 88 | line-height: 1; 89 | vertical-align: middle; 90 | margin-right: 0.5em; 91 | } 92 | 93 | .plugin-card .download button.button.gh-download-button:hover img { 94 | -webkit-filter: invert(100%); 95 | filter: invert(100%); 96 | } 97 | 98 | .plugin-card .download button.button.gh-download-button a { 99 | font-weight: bold; 100 | text-decoration: none; 101 | border: none; 102 | color: currentColor; 103 | } 104 | 105 | body:not(.wp-admin) .plugin-card { 106 | margin: 0 auto; 107 | width: 100%; 108 | background-color: #fff; 109 | border: 1px solid #ddd; 110 | -webkit-box-sizing: border-box; 111 | -moz-box-sizing: border-box; 112 | box-sizing: border-box; 113 | } 114 | 115 | body:not(.wp-admin) .plugin-card-top { 116 | position: relative; 117 | padding: 20px 20px 10px; 118 | min-height: 135px; 119 | } 120 | 121 | body:not(.wp-admin) .plugin-card h3 { 122 | margin: 0 0 12px; 123 | font-size: 18px; 124 | line-height: 1.3; 125 | } 126 | 127 | body:not(.wp-admin) .plugin-card h3 a { 128 | text-decoration: none; 129 | border:none; 130 | } 131 | 132 | body:not(.wp-admin) .plugin-card p.description { 133 | font-size: 13px; 134 | line-height: 1.5; 135 | margin: 1em 0; 136 | } 137 | 138 | @media only screen and (min-width: 37.5em) { 139 | body:not(.wp-admin) .plugin-card { 140 | width: 50%; 141 | margin: 0 auto; 142 | } 143 | } 144 | 145 | body.wp-admin [data-type="gutenblocks/i18n"] .block-editor-inner-blocks { 146 | min-height: 50px; 147 | } 148 | 149 | body.wp-admin [data-type="gutenblocks/i18n"].is-selected [class*="layout-row"], 150 | body.wp-admin [data-type="gutenblocks/i18n"].has-child-selected [class*="layout-row"] { 151 | outline-width: 3px; 152 | outline-style: dashed; 153 | outline-offset: 15px; 154 | outline-color: rgba(145,151,162,.25); 155 | } 156 | 157 | body.wp-admin [data-type="gutenblocks/i18n"].is-selected [class*="layout-row"]:after, 158 | body.wp-admin [data-type="gutenblocks/i18n"].has-child-selected [class*="layout-row"]:after { 159 | content:""; 160 | display: block; 161 | clear:both; 162 | margin-bottom: 50px; 163 | } 164 | 165 | body.wp-admin [data-type="gutenblocks/i18n"] [class*="layout-row"] { 166 | position: relative; 167 | margin-bottom: 10px; 168 | } 169 | 170 | .gutenblocks-i18n-switcher { 171 | width: 100%; 172 | height: auto; 173 | border-bottom: solid 1px #ddd; 174 | padding: 0 !important; 175 | margin-bottom: 1.5em !important; 176 | text-align: right; 177 | } 178 | 179 | .gutenblocks-i18n-switcher li { 180 | list-style: none; 181 | display: inline-block; 182 | margin: 0 !important; 183 | } 184 | 185 | .gutenblocks-i18n-switcher li:last-child { 186 | margin-right: 0.5em !important; 187 | } 188 | 189 | .gutenblocks-i18n-switcher li a { 190 | text-decoration: none !important; 191 | box-shadow: none !important; 192 | padding: 0.5em; 193 | padding-bottom: 0.25em; 194 | display: block; 195 | margin-bottom: -1px; 196 | } 197 | 198 | .gutenblocks-i18n-switcher li.current-locale a { 199 | border: solid 1px #ddd; 200 | border-bottom-color: #fff; 201 | } 202 | -------------------------------------------------------------------------------- /assets/blocks.min.css: -------------------------------------------------------------------------------- 1 | .wp-block-gutenblocks-gist .gist .blob-num{border:none}[data-type="gutenblocks/gist"] .components-placeholder__label label:before{display:inline-block;content:"";width:20px;height:20px;background:url('svg/gist.svg') no-repeat;background-size:contain;vertical-align:-5px}[data-type="gutenblocks/gist"] .wp-block-embed.is-loading{background:0 0}[data-type="gutenblocks/release"] .plugin-card{float:none;margin:0;width:100%}[data-type="gutenblocks/release"] .plugin-card-top{width:75%;margin:1em auto}[data-type="gutenblocks/release"] .plugin-card-top .release-icon,body:not(.wp-admin) .plugin-card-top .release-icon{float:left;top:20px;left:20px;width:128px;height:128px;margin:0 18px 20px 0;box-shadow:none;border:none}[data-type="gutenblocks/release"] .plugin-card-top h3 input[type=text]{width:calc(100% - 148px)}[data-type="gutenblocks/release"] .plugin-card-top .column-description{margin-left:148px;margin-right:0}[data-type="gutenblocks/release"] .plugin-card-top .column-description textarea{width:100%}[data-type="gutenblocks/release"] .plugin-card-top .download,body:not(.wp-admin) .plugin-card-top .download{clear:both;text-align:center}[data-type="gutenblocks/release"] .plugin-card-top .download .dashicons{vertical-align:middle}[data-type="gutenblocks/release"] .required-fields{margin:1em;padding-bottom:1em}[data-type="gutenblocks/release"] .required-fields input[type=text]{width:98%;display:block}[data-type="gutenblocks/release"] .required-fields label{font-weight:700}.plugin-card .download button.button.gh-download-button img{box-shadow:none;border:none;width:20px;height:20px;line-height:1;vertical-align:middle;margin-right:.5em}.plugin-card .download button.button.gh-download-button:hover img{-webkit-filter:invert(100%);filter:invert(100%)}.plugin-card .download button.button.gh-download-button a{font-weight:700;text-decoration:none;border:none;color:currentColor}body:not(.wp-admin) .plugin-card{margin:0 auto;width:100%;background-color:#fff;border:1px solid #ddd;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body:not(.wp-admin) .plugin-card-top{position:relative;padding:20px 20px 10px;min-height:135px}body:not(.wp-admin) .plugin-card h3{margin:0 0 12px;font-size:18px;line-height:1.3}body:not(.wp-admin) .plugin-card h3 a{text-decoration:none;border:none}body:not(.wp-admin) .plugin-card p.description{font-size:13px;line-height:1.5;margin:1em 0}@media only screen and (min-width:37.5em){body:not(.wp-admin) .plugin-card{width:50%;margin:0 auto}}body.wp-admin [data-type="gutenblocks/i18n"] .block-editor-inner-blocks{min-height:50px}body.wp-admin [data-type="gutenblocks/i18n"].has-child-selected [class*=layout-row],body.wp-admin [data-type="gutenblocks/i18n"].is-selected [class*=layout-row]{outline-width:3px;outline-style:dashed;outline-offset:15px;outline-color:rgba(145,151,162,.25)}body.wp-admin [data-type="gutenblocks/i18n"].has-child-selected [class*=layout-row]:after,body.wp-admin [data-type="gutenblocks/i18n"].is-selected [class*=layout-row]:after{content:"";display:block;clear:both;margin-bottom:50px}body.wp-admin [data-type="gutenblocks/i18n"] [class*=layout-row]{position:relative;margin-bottom:10px}.gutenblocks-i18n-switcher{width:100%;height:auto;border-bottom:solid 1px #ddd;padding:0!important;margin-bottom:1.5em!important;text-align:right}.gutenblocks-i18n-switcher li{list-style:none;display:inline-block;margin:0!important}.gutenblocks-i18n-switcher li:last-child{margin-right:.5em!important}.gutenblocks-i18n-switcher li a{text-decoration:none!important;box-shadow:none!important;padding:.5em;padding-bottom:.25em;display:block;margin-bottom:-1px}.gutenblocks-i18n-switcher li.current-locale a{border:solid 1px #ddd;border-bottom-color:#fff} -------------------------------------------------------------------------------- /assets/svg/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2017 GitHub, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /assets/svg/gist.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gist 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /assets/svg/package.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | package 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /gutenblocks.php: -------------------------------------------------------------------------------- 1 | globals(); 45 | $this->inc(); 46 | } 47 | 48 | /** 49 | * Return an instance of this class. 50 | * 51 | * @since 1.0.0 52 | * 53 | * @return object A single instance of this class. 54 | */ 55 | public static function start() { 56 | 57 | // If the single instance hasn't been set, set it now. 58 | if ( null == self::$instance ) { 59 | self::$instance = new self; 60 | } 61 | 62 | return self::$instance; 63 | } 64 | 65 | /** 66 | * Setups plugin's globals 67 | * 68 | * @since 1.0.0 69 | */ 70 | private function globals() { 71 | // Version 72 | $this->version = '1.6.2'; 73 | 74 | // DB Version 75 | $this->db_version = get_option( 'gutenblocks_version', 0 ); 76 | 77 | // Domain 78 | $this->domain = 'gutenblocks'; 79 | 80 | // Base name 81 | $this->file = __FILE__; 82 | $this->basename = plugin_basename( $this->file ); 83 | 84 | // Path and URL 85 | $this->dir = plugin_dir_path( $this->file ); 86 | $this->url = plugin_dir_url ( $this->file ); 87 | $this->js_url = trailingslashit( $this->url . 'js' ); 88 | $this->assets_url = trailingslashit( $this->url . 'assets' ); 89 | $this->inc_dir = trailingslashit( $this->dir . 'inc' ); 90 | 91 | // Permalinks type 92 | $this->pretty_urls = get_option( 'permalink_structure' ); 93 | } 94 | 95 | /** 96 | * Includes plugin's server functions 97 | * 98 | * @since 1.0.0 99 | */ 100 | private function inc() { 101 | spl_autoload_register( array( $this, 'autoload' ) ); 102 | 103 | require $this->inc_dir . 'functions.php'; 104 | 105 | if ( (float) $this->db_version < 1.4 ) { 106 | require $this->inc_dir . 'upgrade.php'; 107 | } 108 | } 109 | 110 | /** 111 | * Class Autoload function 112 | * 113 | * @since 1.2.0 114 | * 115 | * @param string $class The class name. 116 | */ 117 | public function autoload( $class ) { 118 | $name = str_replace( '_', '-', strtolower( $class ) ); 119 | 120 | if ( false === strpos( $name, $this->domain ) ) { 121 | return; 122 | } 123 | 124 | $path = $this->inc_dir . "classes/{$name}.php"; 125 | 126 | // Sanity check. 127 | if ( ! file_exists( $path ) ) { 128 | return; 129 | } 130 | 131 | require $path; 132 | } 133 | } 134 | 135 | endif; 136 | 137 | if ( ! function_exists( 'gutenblocks' ) ) : 138 | /** 139 | * Boot the plugin. 140 | * 141 | * @since 1.0.0 142 | */ 143 | function gutenblocks() { 144 | if ( ! function_exists( 'render_block' ) ) { 145 | return false; 146 | } 147 | 148 | return GutenBlocks::start(); 149 | } 150 | add_action( 'plugins_loaded', 'gutenblocks', 5 ); 151 | 152 | endif; 153 | -------------------------------------------------------------------------------- /inc/classes/gutenblocks-flagmaster.php: -------------------------------------------------------------------------------- 1 | 10 | * @since 2017-01-05 11 | * @license Apache License, Version 2.0 12 | * 13 | * Copyright 2017 Peter Kahl 14 | * 15 | * Licensed under the Apache License, Version 2.0 (the "License"); 16 | * you may not use this file except in compliance with the License. 17 | * You may obtain a copy of the License at 18 | * 19 | * 20 | * 21 | * Unless required by applicable law or agreed to in writing, software 22 | * distributed under the License is distributed on an "AS IS" BASIS, 23 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | * See the License for the specific language governing permissions and 25 | * limitations under the License. 26 | */ 27 | 28 | class GutenBlocks_flagMaster { 29 | 30 | const VERSION = '0.9'; 31 | 32 | #=================================================================== 33 | 34 | private static function enclosedUnicode($char) { 35 | $arr = array( 36 | 'a' => '1F1E6', 37 | 'b' => '1F1E7', 38 | 'c' => '1F1E8', 39 | 'd' => '1F1E9', 40 | 'e' => '1F1EA', 41 | 'f' => '1F1EB', 42 | 'g' => '1F1EC', 43 | 'h' => '1F1ED', 44 | 'i' => '1F1EE', 45 | 'j' => '1F1EF', 46 | 'k' => '1F1F0', 47 | 'l' => '1F1F1', 48 | 'm' => '1F1F2', 49 | 'n' => '1F1F3', 50 | 'o' => '1F1F4', 51 | 'p' => '1F1F5', 52 | 'q' => '1F1F6', 53 | 'r' => '1F1F7', 54 | 's' => '1F1F8', 55 | 't' => '1F1F9', 56 | 'u' => '1F1FA', 57 | 'v' => '1F1FB', 58 | 'w' => '1F1FC', 59 | 'x' => '1F1FD', 60 | 'y' => '1F1FE', 61 | 'z' => '1F1FF', 62 | ); 63 | $char = strtolower($char); 64 | if (array_key_exists($char, $arr)) { 65 | return mb_convert_encoding('&#x'.$arr[$char].';', 'UTF-8', 'HTML-ENTITIES'); 66 | } 67 | throw new Exception('Invalid character '.$char); 68 | } 69 | 70 | #=================================================================== 71 | 72 | /** 73 | * Converts country code to emoji flag. 74 | * @var string (2-letter code) 75 | * 76 | */ 77 | private static function code2unicode($code) { 78 | $arr = str_split($code); 79 | $str = ''; 80 | foreach ($arr as $char) { 81 | $str .= self::enclosedUnicode($char); 82 | } 83 | return $str; 84 | } 85 | 86 | #=================================================================== 87 | 88 | /** 89 | * Converts string of country codes to string of emoji flags. 90 | * Makes correction for codes that have no corresponding flag. 91 | * @var string (one or more 2-letter codes) 92 | * 93 | */ 94 | public static function emojiFlag($code) { 95 | $code = strtolower($code); 96 | if (substr($code, 0, 1) == '_') { 97 | # Certain flags don't exist or countries are occupied or not widely recognised. 98 | $flag = array( 99 | '_tibet' => '🇨🇳', 100 | '_basque-country' => '🇪🇸', 101 | '_northern-cyprus' => '🇨🇾', 102 | '_south-ossetia' => '🇷🇺', 103 | '_scotland' => '🇬🇧', 104 | '_wales' => '🇬🇧', 105 | '_england' => '🇬🇧', 106 | '_commonwealth' => '🇬🇧', 107 | '_british-antarctic-territory' => '🇬🇧', 108 | ); 109 | if (array_key_exists($code, $flag)) { 110 | return $flag[$code]; 111 | } 112 | return '🏴'; 113 | } 114 | elseif ($code == 'unknown') { 115 | return '🏴'; 116 | } 117 | $map = array( 118 | 'uk' => 'gb', 119 | 'an' => 'nl', 120 | ); 121 | # break into pairs 122 | $arr = array(); 123 | $str = ''; 124 | while (strlen($code) > 0) { 125 | $arr[] = substr($code, 0, 2); 126 | $code = substr($code, 2); 127 | } 128 | foreach ($arr as $k => $val) { 129 | if (array_key_exists($val, $map)) { 130 | $arr[$k] = $map[$val]; 131 | $val = $map[$val]; 132 | } 133 | if ($val == 'ap' || $val == 'un') { 134 | $str .= '🏴'; # black flag 135 | } 136 | else { 137 | $str .= self::code2unicode($val); 138 | } 139 | } 140 | return $str; 141 | } 142 | 143 | #=================================================================== 144 | 145 | } 146 | -------------------------------------------------------------------------------- /inc/functions.php: -------------------------------------------------------------------------------- 1 | version; 22 | } 23 | 24 | /** 25 | * Get DB version. 26 | * 27 | * @since 1.4.0 28 | * 29 | * @return string the DB version. 30 | */ 31 | function gutenblocks_db_version() { 32 | return gutenblocks()->db_version; 33 | } 34 | 35 | /** 36 | * Get the plugin's JS Url. 37 | * 38 | * @since 1.0.0 39 | * 40 | * @return string the plugin's JS Url. 41 | */ 42 | function gutenblocks_js_url() { 43 | return gutenblocks()->js_url; 44 | } 45 | 46 | /** 47 | * Get the plugin's Assets Url. 48 | * 49 | * @since 1.0.0 50 | * 51 | * @return string the plugin's Assets Url. 52 | */ 53 | function gutenblocks_assets_url() { 54 | return gutenblocks()->assets_url; 55 | } 56 | 57 | /** 58 | * Get the JS minified suffix. 59 | * 60 | * @since 1.0.0 61 | * 62 | * @return string the JS minified suffix. 63 | */ 64 | function gutenblocks_min_suffix() { 65 | $min = '.min'; 66 | 67 | if ( defined( 'SCRIPT_DEBUG' ) && true === SCRIPT_DEBUG ) { 68 | $min = ''; 69 | } 70 | 71 | /** 72 | * Filter here to edit the minified suffix. 73 | * 74 | * @since 1.0.0 75 | * 76 | * @param string $min The minified suffix. 77 | */ 78 | return apply_filters( 'gutenblocks_min_suffix', $min ); 79 | } 80 | 81 | /** 82 | * Checks if the Core WP Embed block is fixed. 83 | * 84 | * @since 1.1.2 85 | * @deprecated 1.2.3 86 | * 87 | * @return boolean True if fixed, false otherwise. 88 | */ 89 | function gutenblocks_wp_embed_is_fixed() { 90 | _deprecated_function( __FUNCTION__, '1.2.3' ); 91 | return true; 92 | } 93 | 94 | /** 95 | * Are permalinks pretty ? 96 | * 97 | * @since 1.2.0 98 | * 99 | * @return boolean True if permalinks are pretty. False otherwise. 100 | */ 101 | function gutenblocks_are_urls_pretty() { 102 | return !! gutenblocks()->pretty_urls; 103 | } 104 | 105 | /** 106 | * Get the available locales. 107 | * 108 | * @since 1.2.0 109 | * 110 | * @return boolean|array False if no other locales than en_US, the list of locales otherwise. 111 | */ 112 | function gutenblocks_get_languages() { 113 | $languages = get_available_languages(); 114 | $locale = get_locale(); 115 | 116 | if ( ! $languages ) { 117 | return false; 118 | } 119 | 120 | $default = array( 'en_US' ); 121 | if ( 'en_US' !== $locale ) { 122 | array_unshift( $default, $locale ); 123 | } 124 | 125 | return array_unique( array_merge( $default, $languages ) ); 126 | } 127 | 128 | /** 129 | * Is the given string a locale ? 130 | * 131 | * @since 1.2.0 132 | * 133 | * @param string $locale A potential locale string 134 | * @return boolean True if it's a locale. False otherwise. 135 | */ 136 | function gutenblocks_is_locale( $locale = '' ) { 137 | if ( $locale && in_array( $locale, gutenblocks_get_languages(), true ) ) { 138 | return true; 139 | } 140 | 141 | return false; 142 | } 143 | 144 | /** 145 | * Adds a Flag to inform about the i18n Block language being edited 146 | * 147 | * @since 1.2.0 148 | * 149 | * @param array $languages The list of available locales. 150 | * @return string Inline style. 151 | */ 152 | function gutenblocks_style_languages( $languages = array() ) { 153 | $flag_master = new GutenBlocks_flagMaster; 154 | 155 | $style = ''; 156 | 157 | foreach( $languages as $language ) { 158 | $style .= sprintf( ' 159 | body.wp-admin [data-type="gutenblocks/i18n"] .layout-row-%1$s:before { 160 | content: "%2$s"; 161 | position: absolute; 162 | top: -17px; 163 | left: -12px; 164 | } 165 | 166 | .gutenblocks-i18n-switcher li.nav-%1$s a:before { 167 | content: "%2$s"; 168 | } 169 | %3$s', 170 | $language, 171 | $flag_master::emojiFlag( strtolower( substr( $language, -2 ) ) ), 172 | "\n" 173 | ); 174 | } 175 | 176 | return $style; 177 | } 178 | 179 | /** 180 | * l10n for GutenBlocks. 181 | * 182 | * @since 1.0.0 183 | * 184 | * @return array The GutenBlocks l10n strings. 185 | */ 186 | function gutenblocks_l10n() { 187 | $g_l10n = array( 188 | 'gist' => array( 189 | 'title' => _x( 'GitHub Gist', 'Gist Block Title', 'gutenblocks' ), 190 | 'instructions' => _x( 'Collez un lien vers le Gist que vous souhaitez afficher sur votre site.', 'Gist Block Instructions', 'gutenblocks' ), 191 | 'inputPlaceholder' => _x( 'Saisissez l’URL du Gist à embarquer…', 'Gist Block Input', 'gutenblocks' ), 192 | 'buttonPlaceholder' => _x( 'Embarquer', 'Gist Block Button', 'gutenblocks' ), 193 | 'description' => _x( 'Ce bloc vous permet d’embarquer facilement vos codes sources hébergés sur gist.GitHub.com', 'Gist Block description', 'gutenblocks' ), 194 | ), 195 | 'release' => array( 196 | 'title' => _x( 'GitHub Release', 'Release Block Title', 'gutenblocks' ), 197 | 'namePlaceholder' => _x( 'Nom du dépôt', 'Release Block Slug', 'gutenblocks' ), 198 | 'labelPlaceholder' => _x( 'Nom de l’extension…', 'Release Block Name', 'gutenblocks' ), 199 | 'tagPlaceholder' => _x( 'Numéro de version', 'Release Block Tag', 'gutenblocks' ), 200 | 'notesPlaceholder' => _x( 'Notes sur la version…', 'Release Block Notes', 'gutenblocks' ), 201 | 'ghUsername' => gutenblocks_github_release_get_username(), 202 | 'downloadHTML' => _x( 'Télécharger la version %s', 'Release Block Download', 'gutenblocks' ), 203 | 'description' => _x( 'Ce bloc vous permet de créer une fiche descriptive de votre extension hébergée sur GitHub.com', 'Release Block description', 'gutenblocks' ), 204 | ), 205 | ); 206 | 207 | return $g_l10n; 208 | } 209 | 210 | /** 211 | * Registers JavaScripts and Styles. 212 | * 213 | * @since 1.0.0 214 | * @since 1.2.0 Register the editor script for the i18n Block. 215 | * @since 1.6.0 Stop using the wp-editor dependency for the i18n block 216 | */ 217 | function gutenblocks_register_scripts() { 218 | $min = gutenblocks_min_suffix(); 219 | $v = gutenblocks_version(); 220 | 221 | /** JavaScripts **********************************************************/ 222 | $url = gutenblocks_js_url(); 223 | 224 | $scripts = apply_filters( 'gutenblocks_register_javascripts', array( 225 | 'gutenblocks-gist' => array( 226 | 'location' => sprintf( '%1$sblocks/gist%2$s.js', $url, $min ), 227 | 'deps' => array( 'wp-block-library' ), 228 | ), 229 | 'gutenblocks-release' => array( 230 | 'location' => sprintf( '%1$sblocks/release%2$s.js', $url, $min ), 231 | 'deps' => array( 'wp-blocks' ), 232 | ), 233 | 'gutenblocks-i18n' => array( 234 | 'location' => sprintf( '%1$sblocks/i18n%2$s.js', $url, $min ), 235 | 'deps' => array( 'wp-block-editor', 'wp-blocks', 'wp-dom-ready' ), 236 | ), 237 | ), $url, $min, $v ); 238 | 239 | foreach ( $scripts as $js_handle => $script ) { 240 | $in_footer = false; 241 | 242 | if ( isset( $script['footer'] ) ) { 243 | $in_footer = $script['footer']; 244 | } 245 | 246 | wp_register_script( $js_handle, $script['location'], $script['deps'], $v, $in_footer ); 247 | } 248 | 249 | $handles = array_keys( $scripts ); 250 | $handle = reset( $handles ); 251 | wp_localize_script( $handle, 'gutenBlocksStrings', gutenblocks_l10n() ); 252 | 253 | /** Style ****************************************************************/ 254 | 255 | wp_register_style( 'gutenblocks', 256 | sprintf( '%1$sblocks%2$s.css', gutenblocks_assets_url(), $min ), 257 | array( 'wp-block-library' ), 258 | $v 259 | ); 260 | 261 | $languages = gutenblocks_get_languages(); 262 | 263 | if ( ! $languages ) { 264 | wp_deregister_script( 'gutenblocks-i18n' ); 265 | } else { 266 | wp_localize_script( 'gutenblocks-i18n', 'gutenblocksI18n', array( 267 | 'languages' => $languages, 268 | 'title' => _x( 'Doubleur (Expérimental)', 'i18n Block Title', 'gutenblocks' ), 269 | 'description' => _x( 'Ce bloc vous permet de proposer votre contenu en plusieurs langue.', 'Dubber Block description', 'gutenblocks' ), 270 | ) ); 271 | 272 | if ( ! wp_doing_ajax() ) { 273 | wp_add_inline_style( 'gutenblocks', gutenblocks_style_languages( $languages ) ); 274 | } 275 | } 276 | } 277 | add_action( 'init', 'gutenblocks_register_scripts', 12 ); 278 | 279 | /** 280 | * Register dynamic Gutenberg blocks. 281 | * 282 | * @since 1.1.0 283 | * @since 1.2.0 Register the i18n Block 284 | * @since 1.4.0 Use this function for all blocks. 285 | */ 286 | function gutenblocks_register_dynamic_blocks() { 287 | if ( ! function_exists( 'register_block_type' ) ) { 288 | return false; 289 | } 290 | 291 | register_block_type( 'gutenblocks/gist', array( 292 | 'editor_script' => 'gutenblocks-gist', 293 | ) ); 294 | 295 | register_block_type( 'gutenblocks/release', array( 296 | 'render_callback' => 'gutenblocks_github_release_callback', 297 | 'editor_script' => 'gutenblocks-release', 298 | ) ); 299 | 300 | if ( wp_scripts()->query( 'gutenblocks-i18n' ) ) { 301 | register_block_type( 'gutenblocks/i18n', array( 302 | 'editor_script' => 'gutenblocks-i18n', 303 | ) ); 304 | } 305 | } 306 | add_action( 'init', 'gutenblocks_register_dynamic_blocks', 20 ); 307 | 308 | /** 309 | * Returns the custom embed providers. 310 | * 311 | * @since 1.1.0 312 | * 313 | * @return array The list of custom providers. 314 | */ 315 | function gutenblocks_get_embed_providers() { 316 | return apply_filters( 'gutenblocks_register_embed_providers', array( 317 | 'gutenblocks_gist' => array( 318 | 'regex' => '#(https://gist.github.com/(.*?)/([a-zA-Z0-9]+)?)(\#file(\-|_)(.+))?$#i', 319 | 'callback' => 'gutenblocks_gist_handler', 320 | 'format' => '#https?://gist\.github\.com/.*#i', 321 | 'provider' => 'https://gist.github.com', 322 | 'validate' => 'gutenblocks_build_gist_src', 323 | ), 324 | ) ); 325 | } 326 | 327 | /** 328 | * Register custom embed providers. 329 | * 330 | * @since 1.1.0 331 | */ 332 | function gutenblocks_register_embed_providers() { 333 | $custom_providers = gutenblocks_get_embed_providers(); 334 | 335 | foreach ( $custom_providers as $provider => $data ) { 336 | // This is needed to fetch the Gist in Gutenberg. 337 | wp_oembed_add_provider( $data['format'], $data['provider'], true ); 338 | 339 | // This is needed for the classic editor and on front-end. 340 | wp_embed_register_handler( $provider, $data['regex'], $data['callback'] ); 341 | } 342 | } 343 | add_action( 'plugins_loaded', 'gutenblocks_register_embed_providers', 14 ); 344 | 345 | /** 346 | * Customize the oembed url for Gists. 347 | * 348 | * @since 1.1.0 349 | * 350 | * @param string $provider The URL provider. 351 | * @param string $url The URL to embed. 352 | * @param array $args The oembed arguments. 353 | * @return string The URL to request. 354 | */ 355 | function gutenblocks_oembed_fetch_url( $provider = '', $url = '', $args = array() ) { 356 | $provider_data = wp_parse_url( $provider ); 357 | 358 | if ( ! isset( $provider_data['host'] ) || 'gist.github.com' !== $provider_data['host'] ) { 359 | return $provider; 360 | } 361 | 362 | // It's a gist, make sure the reply will be a JSON content. 363 | add_filter( 'http_response', 'gutenblocks_embed_response', 10, 3 ); 364 | 365 | return $url; 366 | } 367 | add_filter( 'oembed_fetch_url', 'gutenblocks_oembed_fetch_url', 10, 3 ); 368 | 369 | /** 370 | * Edit the JSON reply for the embed Gist. 371 | * 372 | * @since 1.1.0 373 | * 374 | * @param array $response The HTTP request response. 375 | * @param array $args The HTTP request arguments. 376 | * @param string $url The requested URL. 377 | * @return array The HTTP request response. 378 | */ 379 | function gutenblocks_embed_response( $response, $args, $url ) { 380 | remove_filter( 'http_response', 'gutenblocks_embed_response', 10, 3 ); 381 | 382 | $handlers = wp_list_pluck( gutenblocks_get_embed_providers(), 'regex', 'validate' ); 383 | 384 | if ( ! $handlers ) { 385 | return $response; 386 | } 387 | 388 | $body = ''; 389 | $raw_url = str_replace( '?', '', remove_query_arg( array( 'format' ), $url ) ); 390 | 391 | foreach ( $handlers as $validate => $regex ) { 392 | if ( ! preg_match( $regex, $raw_url, $matches ) ) { 393 | continue; 394 | } 395 | 396 | if ( ! function_exists( $validate ) ) { 397 | continue; 398 | } 399 | 400 | $body = json_encode( array( 401 | 'url' => call_user_func_array( $validate, array( $matches ) ), 402 | ) ); 403 | } 404 | 405 | // We have a body, set it. 406 | if ( $body ) { 407 | $response['body'] = $body; 408 | $response['http_response']->set_data( $body ); 409 | } 410 | 411 | return $response; 412 | } 413 | 414 | /** 415 | * Builds the src attribute of the gist to embed. 416 | * @param array $matches [description] 417 | * @return [type] [description] 418 | */ 419 | function gutenblocks_build_gist_src( $matches = array() ) { 420 | $url = ''; 421 | 422 | if ( isset( $matches[3] ) ) { 423 | $url = $matches[1] . '.js'; 424 | 425 | if ( isset( $matches[6] ) ) { 426 | $url = add_query_arg( 'file', preg_replace( '/[\-\.]([a-z]+)$/', '.\1', $matches[6] ), $url ); 427 | } 428 | } 429 | 430 | return $url; 431 | } 432 | 433 | /** 434 | * Gist embed handler callback. 435 | * 436 | * @since 1.1.0 437 | * 438 | * @param array $matches The RegEx matches from the provided regex when calling 439 | * wp_embed_register_handler(). 440 | * @param array $attr Embed attributes. 441 | * @param string $url The original URL that was matched by the regex. 442 | * @param array $rawattr The original unmodified attributes. 443 | * @return string The embed HTML. 444 | */ 445 | function gutenblocks_gist_handler( $matches, $attr, $url, $rawattr ) { 446 | // Only display full gists on single pages 447 | if ( is_front_page() || is_home() ) { 448 | return sprintf( 449 | '

%2$s

', 450 | esc_url( $url ), 451 | esc_html__( 'Afficher le code imbriqué', 'gutenblocks' ) 452 | ); 453 | } 454 | 455 | $src = gutenblocks_build_gist_src( $matches ); 456 | 457 | if ( $url ) { 458 | return sprintf( '', esc_url( $src ) ); 459 | } 460 | } 461 | 462 | /** 463 | * Enqueues the Gutenberg blocks script. 464 | * 465 | * @since 1.0.0 466 | * @deprecated 1.2.3 467 | */ 468 | function gutenblocks_editor() { 469 | _deprecated_function( __FUNCTION__, '1.2.3' ); 470 | } 471 | 472 | /** 473 | * Enqueues the Gutenberg blocks style. 474 | * 475 | * @since 1.0.0 476 | */ 477 | function gutenblocks_style() { 478 | wp_enqueue_style( 'gutenblocks' ); 479 | } 480 | add_action( 'enqueue_block_assets', 'gutenblocks_style' ); 481 | 482 | /** 483 | * Get the GitHub username. 484 | * 485 | * @since 1.1.0 486 | * 487 | * @return string The GitHub username. 488 | */ 489 | function gutenblocks_github_release_get_username() { 490 | /** 491 | * Filter here to customize with your GitHub username. 492 | * 493 | * @since 1.1.0 494 | * 495 | * @param string $value Your GitHub username. 496 | */ 497 | return apply_filters( 'gutenblocks_github_release_get_username', 'imath' ); 498 | } 499 | 500 | /** 501 | * Get base64 encoded SVG icon. 502 | * 503 | * @since 1.1.0 504 | * 505 | * @param string $name The name of the SVG icon. 506 | * @return string Base 64 encoded SVG icon. 507 | */ 508 | function gutenblocks_github_release_icon( $name = 'default_icon' ) { 509 | $icons = array( 510 | 'default_icon' => '', 511 | 'download_icon' => '', 512 | ); 513 | 514 | if ( ! isset( $icons[ $name ] ) ) { 515 | return ''; 516 | } 517 | 518 | return 'data:image/svg+xml;base64,' . base64_encode( $icons[ $name ] ); 519 | } 520 | 521 | /** 522 | * Dynamic GutenBlock's GitHub Release callback. 523 | * 524 | * @since 1.1.0 525 | * @since 1.2.0 Add a layout class if used within a nested block. 526 | * 527 | * @param array $attributes The GutenBlock attributes. 528 | * @return string The content to output on front-end 529 | */ 530 | function gutenblocks_github_release_callback( $attributes = array() ) { 531 | // Merge defaults with attributes 532 | $a = wp_parse_args( $attributes, array( 533 | 'name' => '', 534 | 'label' => '', 535 | 'tag' => '', 536 | 'logo' => '', 537 | 'notes' => '', 538 | ) ); 539 | 540 | if ( empty( $a['name'] ) || empty( $a['tag'] ) ) { 541 | return; 542 | } 543 | 544 | // sanitize the name. 545 | $name = sanitize_key( remove_accents( $a['name'] ) ); 546 | $tag = $a['tag']; 547 | 548 | // Try the transient first (dayly updated). 549 | $release_data = get_site_transient( 'github_release_data_' . $name ); 550 | $download_count = 0; 551 | 552 | // The transient is not set yet or it's a new release. 553 | if ( ! isset( $release_data->tag_name ) || version_compare( $tag, $release_data->tag_name, '>' ) ) { 554 | $gh_releases_url = sprintf( 'https://api.github.com/repos/imath/%s/releases', $name ); 555 | $gh_response = wp_remote_get( $gh_releases_url ); 556 | 557 | if ( ! is_wp_error( $gh_response ) && 200 === (int) wp_remote_retrieve_response_code( $gh_response ) ) { 558 | $releases = json_decode( wp_remote_retrieve_body( $gh_response ), true ); 559 | 560 | if ( $releases ) { 561 | foreach ( (array) $releases as $release ) { 562 | $package = array(); 563 | 564 | // Count downloads about all releases. 565 | if ( ! empty( $release['assets'] ) ) { 566 | $package = reset( $release['assets'] ); 567 | $download_count += (int) $package['download_count']; 568 | } 569 | 570 | // Only keep the requested release 571 | if ( $tag !== $release['tag_name'] ) { 572 | continue; 573 | } 574 | 575 | $release_data = (object) array( 576 | 'id' => $release['id'], 577 | 'url' => $release['html_url'], 578 | 'name' => $release['name'], 579 | 'tag_name' => $release['tag_name'], 580 | 'package' => $package, 581 | ); 582 | } 583 | 584 | if ( isset( $release_data->id ) ) { 585 | $release_data->downloads = $download_count; 586 | set_site_transient( 'github_release_data_' . $name, $release_data, DAY_IN_SECONDS ); 587 | } 588 | } 589 | } 590 | } 591 | 592 | $label = $name; 593 | if ( $a['label'] ) { 594 | $label = esc_html( $a['label'] ); 595 | } 596 | 597 | $release_url = sprintf( 'https://github.com/imath/%1$s/releases/tag/%2$s', $name, $tag ); 598 | $download_url = sprintf( 'https://github.com/imath/%1$s/releases/download/%2$s/%1$s.zip', $name, $tag ); 599 | 600 | $container_class = 'plugin-card'; 601 | 602 | if ( isset( $a['layout'] ) && $a['layout'] ) { 603 | $container_class .= ' layout-' . $a['layout']; 604 | 605 | $locale = str_replace( 'row-', '', $a['layout'] ); 606 | if ( gutenblocks_is_locale( $locale ) && $locale !== get_locale() && $locale === gutenblocks_get_locale() ) { 607 | switch_to_locale( $locale ); 608 | 609 | if ( ! is_textdomain_loaded( 'gutenblocks' ) ) { 610 | gutenblocks_load_textdomain(); 611 | } 612 | } 613 | } 614 | 615 | $count = ''; 616 | if ( isset( $release_data->downloads ) ) { 617 | $count = sprintf( '

%s

', 618 | sprintf( 619 | _n( '%d téléchargement', '%d téléchargements', $release_data->downloads, 'gutenblocks' ), 620 | number_format_i18n( $release_data->downloads ) 621 | ) 622 | ); 623 | } 624 | 625 | $logo = sprintf( '', gutenblocks_github_release_icon() ); 626 | if ( ! empty( $a['logo'] ) ) { 627 | $logo = sprintf( '', esc_url( $a['logo'] ) ); 628 | } 629 | 630 | if ( ! empty( $a['notes'] ) ) { 631 | $notes = str_replace( array( '

', '

' ), '', wpautop( trim( $a['notes'], "\n" ) ) ); 632 | $count = sprintf( '

%s

', wp_kses( $notes, array( 'br' => true ) ) ) ."\n" . $count; 633 | } 634 | 635 | $output = sprintf( '', 636 | $container_class, 637 | esc_url( $download_url ), 638 | $logo, 639 | $label, 640 | $count, 641 | esc_url( $release_url ), 642 | esc_html__( 'Afficher la page GitHub de la version', 'gutenblocks' ), 643 | gutenblocks_github_release_icon( 'download_icon' ), 644 | sprintf( esc_html__( 'Télécharger la version %s', 'gutenblocks' ), $tag ) 645 | ); 646 | 647 | if ( is_locale_switched() ) { 648 | restore_current_locale(); 649 | } 650 | 651 | return $output; 652 | } 653 | 654 | /** 655 | * Loads translation. 656 | * 657 | * @since 1.0.0 658 | */ 659 | function gutenblocks_load_textdomain() { 660 | $g = gutenblocks(); 661 | 662 | load_plugin_textdomain( $g->domain, false, trailingslashit( basename( $g->dir ) ) . 'languages' ); 663 | } 664 | add_action( 'plugins_loaded', 'gutenblocks_load_textdomain', 9 ); 665 | 666 | /** 667 | * Add rewrite rules for Post and Page translations. 668 | * 669 | * @since 1.2.0 670 | */ 671 | function gutenblocks_translate_rewrite_rules() { 672 | global $wp_rewrite; 673 | 674 | add_rewrite_tag( 675 | '%translate%', 676 | '([^/]+)' 677 | ); 678 | 679 | $patterns = array( 680 | '/%year%/%monthnum%' => array( 681 | 'pattern' => '([0-9]{4})/([0-9]{1,2})/', 682 | 'query' => '?year=$matches[1]&monthnum=$matches[2]&name=$matches[3]&translate=$matches[4]', 683 | ), 684 | '/%year%/%monthnum%/%day%' => array( 685 | 'pattern' => '([0-9]{4})/([0-9]{1,2})/([0-9]{1,2})/', 686 | 'query' => '?year=$matches[1]&monthnum=$matches[2]&day=$matches[3]&name=$matches[4]&translate=$matches[5]', 687 | ), 688 | '/archives/%post_id%' => array( 689 | 'pattern' => 'archives/', 690 | 'query' => '?p=$matches[1]&translate=$matches[2]', 691 | ), 692 | ); 693 | 694 | $permalink_structure = rtrim( str_replace( '%postname%/', '', $wp_rewrite->permalink_structure ), '/' ); 695 | if ( isset( $patterns[ $permalink_structure ] ) ) { 696 | $post_base = $patterns[ $permalink_structure ]['pattern'] . '([^/]+)/'; 697 | $post_query = $patterns[ $permalink_structure ]['query']; 698 | } else { 699 | $post_base = '(.?.+?)/'; 700 | $post_query = '?name=$matches[1]&translate=$matches[2]'; 701 | } 702 | 703 | $rewrite_rules = array( 704 | // Page 705 | '([^/]+)/translate/?([^/]+)/?$' => '?pagename=$matches[1]&translate=$matches[2]', 706 | '([^/]+)/translate/?([^/]+)/embed/?$' => '?pagename=$matches[1]&translate=$matches[2]&embed=true', 707 | // Post 708 | $post_base . 'translate/?([^/]+)/?$' => $post_query, 709 | $post_base . 'translate/?([^/]+)/embed/?$' => $post_query . '&embed=true', 710 | ); 711 | 712 | foreach ( $rewrite_rules as $regex => $rewrite_rule ) { 713 | add_rewrite_rule( 714 | $regex, 715 | $wp_rewrite->index . $rewrite_rule, 716 | 'top' 717 | ); 718 | } 719 | } 720 | add_action( 'init', 'gutenblocks_translate_rewrite_rules' ); 721 | 722 | /** 723 | * Upgrade the DB Version. 724 | * 725 | * @since 1.4.0 726 | */ 727 | function gutenblocks_upgrade_db_version() { 728 | update_option( 'gutenblocks_version', gutenblocks_version() ); 729 | 730 | return 1; 731 | } 732 | 733 | /** 734 | * Perform some upgrade tasks if needed. 735 | * 736 | * @since 1.2.0 737 | */ 738 | function gutenblocks_upgrade() { 739 | $db_version = gutenblocks_db_version(); 740 | $version = gutenblocks_version(); 741 | 742 | if ( ! version_compare( $db_version, $version, '<' ) ) { 743 | return; 744 | } 745 | 746 | if ( (float) $db_version < 1.2 || (float) $db_version < 1.5 ) { 747 | delete_option( 'rewrite_rules' ); 748 | flush_rewrite_rules( false ); 749 | } 750 | 751 | if ( (float) $db_version < 1.4 ) { 752 | return; 753 | } 754 | 755 | // Update version. 756 | gutenblocks_upgrade_db_version(); 757 | } 758 | add_action( 'admin_init', 'gutenblocks_upgrade', 100 ); 759 | 760 | /** 761 | * Build a page or post link to its translated version. 762 | * 763 | * @since 1.2.0 764 | * 765 | * @param string $link The permalink of the Post or the Page. 766 | * @param string $language The locale of the translated version. 767 | * @return string The link to display the translated version. 768 | */ 769 | function gutenblocks_translate_post_link( $link = '', $language = '' ) { 770 | if ( ! $language ) { 771 | $language = strtolower( str_replace( '_', '-', get_locale() ) ); 772 | } 773 | 774 | if ( gutenblocks_are_urls_pretty() ) { 775 | $link = trailingslashit( $link ) . 'translate/' . $language . '/'; 776 | } else { 777 | $link = add_query_arg( 'translate', $language, $link ); 778 | } 779 | 780 | return $link; 781 | } 782 | 783 | /** 784 | * Build the language switcher on singular templates. 785 | * 786 | * @since 1.2.0 787 | * 788 | * @param string $current The current locale to use for the blocks. 789 | * @return string HTML Output. 790 | */ 791 | function gutenblocks_get_language_switcher( $current = '' ) { 792 | $locales = gutenblocks_get_languages(); 793 | $site_locale = get_locale(); 794 | $include_switcher = wp_using_themes() && $locales && is_singular(); 795 | 796 | if ( ! $include_switcher ) { 797 | return; 798 | } 799 | 800 | if ( ! $current ) { 801 | $current = $site_locale; 802 | } 803 | 804 | $switcher = '\n"; 832 | } 833 | 834 | /** 835 | * Gets the locale for GutenBlocks. 836 | * 837 | * @since 1.2.0 838 | * 839 | * @return string The locale for GutenBlocks. 840 | */ 841 | function gutenblocks_get_locale() { 842 | $locale = get_locale(); 843 | $qv = gutenblocks_get_locale_from_slug( get_query_var( 'translate' ) ); 844 | 845 | if ( $qv ) { 846 | $locale = $qv; 847 | } 848 | 849 | return $locale; 850 | } 851 | 852 | /** 853 | * Returns a locale out of a language slug. 854 | * 855 | * @since 1.2.0 856 | * 857 | * @param string $slug The language slug. 858 | * @return boolean|string False if no locale was found. The locale otherwise. 859 | */ 860 | function gutenblocks_get_locale_from_slug( $slug = '' ) { 861 | if ( ! $slug ) { 862 | return false; 863 | } 864 | 865 | $country = substr( $slug, -2 ); 866 | $locale = str_replace( '-' . $country, '_' . strtoupper( $country ), $slug ); 867 | 868 | if ( false !== array_search( $locale, gutenblocks_get_languages() ) ) { 869 | return $locale; 870 | } 871 | 872 | return false; 873 | } 874 | 875 | /** 876 | * Returns the locale out of a URI. 877 | * 878 | * @since 1.2.0 879 | * 880 | * @param string $uri The URI to get the locale from. 881 | * @return boolean|string False if no locale was found. The locale otherwise. 882 | */ 883 | function gutenblocks_get_locale_from_uri( $uri = '' ) { 884 | if ( ! $uri ) { 885 | $uri = $_SERVER['REQUEST_URI']; 886 | } 887 | 888 | $parts = wp_parse_url( $uri ); 889 | $needs_switch = false; 890 | 891 | if ( gutenblocks_are_urls_pretty() ) { 892 | $path = explode( '/', trim( $parts['path'], '/' ) ); 893 | $t_index = array_search( 'translate', $path ); 894 | 895 | if ( false !== $t_index ) { 896 | $needs_switch = $path[ $t_index + 1 ]; 897 | } 898 | } else { 899 | $q = wp_parse_args( $parts['query'], array( 900 | 'translate' => false, 901 | ) ); 902 | 903 | if ( $q['translate'] ) { 904 | $needs_switch = $q['translate']; 905 | } 906 | } 907 | 908 | return gutenblocks_get_locale_from_slug( $needs_switch ); 909 | } 910 | 911 | /** 912 | * Only keeps the current locale version of the i18n Block. 913 | * 914 | * @since 1.2.0 915 | * @since 1.2.5 Adapts to InnerBlocks changes introduced in Gutenberg 3.5. 916 | * @since 1.2.6 Casts WP_Block_Parser_Block objects as arrays to keep 917 | * compatibility with Gutenberg < 3.8. 918 | * 919 | * @param string $content The Post content. 920 | * @return string The Post content for the current locale. 921 | */ 922 | function gutenblocks_translate_blocks( $content = '' ) { 923 | if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST && false !== strpos( wp_parse_url( $_SERVER['HTTP_REFERER'], PHP_URL_PATH ), '/wp-admin/' ) ) ) { 924 | return $content; 925 | } 926 | 927 | preg_match_all( '/\
([\s\S]*?)\<\/section\>/', $content, $matches ); 928 | 929 | if ( $matches[1] ) { 930 | $locale = gutenblocks_get_locale(); 931 | $localeblock = sprintf( 'gutenblocks/language-%s', str_replace( '_', '-', strtolower( $locale ) ) ); 932 | 933 | foreach ( $matches[1] as $k => $m ) { 934 | $blocks = parse_blocks( $m ); 935 | 936 | foreach( $blocks as $block ) { 937 | if ( is_object( $block ) ) { 938 | $block = (array) $block; 939 | } 940 | 941 | if ( is_object( $block['attrs'] ) ) { 942 | $block['attrs'] = (array) $block['attrs']; 943 | } 944 | 945 | if ( empty( $block['blockName'] ) || $localeblock === $block['blockName'] ) { 946 | continue; 947 | } 948 | 949 | if ( empty( $block['innerBlocks'] ) ) { 950 | continue; 951 | } 952 | 953 | foreach ( $block['innerBlocks'] as $innerblock ) { 954 | if ( is_object( $innerblock ) ) { 955 | $innerblock = (array) $innerblock; 956 | } 957 | 958 | // Remove all other languages blocks' content. 959 | $content = str_replace( $innerblock['innerHTML'], '', $content ); 960 | } 961 | 962 | $parts = explode( '', $content ); 963 | 964 | if ( isset( $parts[1] ) ) { 965 | $content = reset( $parts ); 966 | 967 | foreach ( $parts as $part ) { 968 | $end = explode( '', $part ); 969 | 970 | if ( isset( $end[1] ) ) { 971 | $content .= end( $end ); 972 | } 973 | } 974 | } 975 | } 976 | } 977 | 978 | if ( ! is_front_page() ) { 979 | $content = gutenblocks_get_language_switcher( $locale ) . $content; 980 | } 981 | 982 | if ( is_embed() && preg_match( '/\\<\/span\>/', $content, $more_matches ) ) { 983 | $teaser = explode( $more_matches[0], $content, 2 ); 984 | $content = reset( $teaser ); 985 | } 986 | } 987 | 988 | return $content; 989 | } 990 | add_filter( 'the_content', 'gutenblocks_translate_blocks', 6 ); 991 | 992 | /** 993 | * Get the locale out of the URI and switch the site's one if needed. 994 | * 995 | * @since 1.2.0 996 | * 997 | * @param string $url The requested URL. 998 | */ 999 | function gutenblocks_oembed_add_translate_filters( $url = '' ) { 1000 | $locale = gutenblocks_get_locale_from_uri( $url ); 1001 | 1002 | if ( $locale ) { 1003 | switch_to_locale( $locale ); 1004 | 1005 | // Make sure Post and Page permalinks are translated. 1006 | add_filter( 'post_link', 'gutenblocks_translate_post_link', 10, 1 ); 1007 | add_filter( 'page_link', 'gutenblocks_translate_post_link', 10, 1 ); 1008 | } 1009 | } 1010 | add_action( 'embed_content_meta', 'gutenblocks_oembed_add_translate_filters', 9, 0 ); 1011 | 1012 | /** 1013 | * Restore the site's locale & Page and Post permalinks if needed. 1014 | * 1015 | * @since 1.2.0 1016 | */ 1017 | function gutenblocks_oembed_remove_translate_filters() { 1018 | if ( is_locale_switched() ) { 1019 | remove_filter( 'post_link', 'gutenblocks_translate_post_link', 10, 1 ); 1020 | remove_filter( 'page_link', 'gutenblocks_translate_post_link', 10, 1 ); 1021 | restore_current_locale(); 1022 | } 1023 | } 1024 | add_action( 'embed_footer', 'gutenblocks_oembed_remove_translate_filters', 11 ); 1025 | 1026 | /** 1027 | * Checks if switching locale is required for an embed request. 1028 | * 1029 | * @since 1.2.0 1030 | * 1031 | * @param integer $page_id The current post type ID being embedded. 1032 | * @param string $url The embed url. 1033 | * @return integer The current post type ID being embedded. 1034 | */ 1035 | function gutenblocks_oembed_post_request_id( $page_id = 0, $url = '' ) { 1036 | if ( ! $page_id ) { 1037 | return $page_id; 1038 | } 1039 | 1040 | gutenblocks_oembed_add_translate_filters( $url ); 1041 | 1042 | return $page_id; 1043 | } 1044 | add_filter( 'oembed_request_post_id', 'gutenblocks_oembed_post_request_id', 10, 2 ); 1045 | 1046 | /** 1047 | * Restore the current locale if an embed request needs it. 1048 | * 1049 | * @since 1.2.0 1050 | * 1051 | * @param array $data The embed data. 1052 | * @return array The embed data. 1053 | */ 1054 | function gutenblocks_oembed_response_data( $data = array() ) { 1055 | gutenblocks_oembed_remove_translate_filters(); 1056 | 1057 | return $data; 1058 | } 1059 | add_filter( 'oembed_response_data', 'gutenblocks_oembed_response_data', 11, 1 ); 1060 | -------------------------------------------------------------------------------- /inc/upgrade.php: -------------------------------------------------------------------------------- 1 | ([\s\S]*?)/', $post->post_content, $matches ); 35 | 36 | if ( ! $matches || ! isset( $matches[1] ) || ! isset( $matches[2] ) ) { 37 | continue; 38 | } 39 | 40 | foreach ( $matches[1] as $k => $attrs ) { 41 | $attributes = json_decode( $attrs ); 42 | $inner_html = $matches[2][ $k ]; 43 | 44 | $replace = array( 45 | "\n", 46 | 'wp-block-gutenblocks-photo', 47 | ' style="max-width:100%"', 48 | sprintf( ' style="text-align:%s"', $attributes->alignment ), 49 | ' align' . $attributes->alignment, 50 | sprintf( 'width="%1$d" height="%2$d"', $attributes->width, $attributes->height ), 51 | ); 52 | 53 | $replace_by = array( 54 | '', 55 | 'wp-block-image', 56 | '', 57 | '', 58 | '', 59 | 'alt=""', 60 | ); 61 | 62 | if ( isset( $attributes->alignment ) ) { 63 | if ( 'none' !== $attributes->alignment ) { 64 | $attributes->align = $attributes->alignment; 65 | } 66 | 67 | foreach ( array( 'width', 'height', 'alignment' ) as $key ) { 68 | unset( $attributes->{$key} ); 69 | } 70 | } 71 | 72 | $img_attributes = ' '; 73 | if ( isset( $attributes->align ) ) { 74 | $img_attributes = ' ' . json_encode( $attributes ) . ' '; 75 | 76 | $replace_by[1] = 'align' . $attributes->align; 77 | $inner_html = '
' . $inner_html . '
'; 78 | } 79 | 80 | $inner_html = str_replace( $replace, $replace_by, $inner_html ); 81 | 82 | $image_block = sprintf( '%2$s', $img_attributes, "\n" ); 83 | $image_block .= $inner_html . "\n"; 84 | $image_block .= ''; 85 | 86 | $post->post_content = str_replace( $matches[0][ $k ], $image_block, $post->post_content ); 87 | } 88 | 89 | wp_update_post( $post ); 90 | $upgraded += 1; 91 | } 92 | 93 | return $upgraded; 94 | } 95 | 96 | /** 97 | * Do we have at least one post using the Photo block ? 98 | * 99 | * @since 1.4.0 100 | * 101 | * @param integer $number The number of posts to retrieve. 102 | * @return array The post objects containing Photo blocks. 103 | */ 104 | function gutenblocks_has_photo_block( $number = 1 ) { 105 | return get_posts( array( 106 | 's' => 'wp:gutenblocks/photo', 107 | 'numberposts' => $number, 108 | 'post_type' => 'any', 109 | ) ); 110 | } 111 | 112 | /** 113 | * Get the upgrade URL. 114 | * 115 | * @since 1.4.0 116 | * 117 | * @return string The upgrade URL. 118 | */ 119 | function gutenblocks_get_upgrade_url() { 120 | if ( function_exists( 'entrepot' ) ) { 121 | $upgrade_url = add_query_arg( array( 122 | 'page' => 'upgrade-repositories', 123 | ), admin_url( 'plugins.php' ) ); 124 | } else { 125 | $upgrade_url = add_query_arg( array( 126 | 'page' => 'gutenblocks-upgrade', 127 | ), admin_url( 'index.php' ) ); 128 | } 129 | 130 | return $upgrade_url; 131 | } 132 | 133 | /** 134 | * Manage upgrade actions & add inline script for the Auto upgrader. 135 | * 136 | * @since 1.4.0 137 | */ 138 | function gutenblocks_upgrade_load() { 139 | $auto_upgrader = ''; 140 | 141 | if ( isset( $_GET['action'] ) && 'upgrade' === $_GET['action'] ) { 142 | if ( 0 === gutenblocks_upgrade_photo_block() ) { 143 | // redirect using the upgraded action. 144 | wp_safe_redirect( add_query_arg( 'action', 'upgraded', gutenblocks_get_upgrade_url() ) ); 145 | 146 | exit(); 147 | } 148 | 149 | $auto_upgrader = "\n" . 'setTimeout( function() { 150 | var url = upgrader.getAttribute( \'href\' ); 151 | upgrader.remove(); 152 | 153 | // "Auto" Upgrade. 154 | location.href = url; 155 | }, 250 );'; 156 | } 157 | 158 | wp_add_inline_script( 'common', sprintf( ' 159 | ( function() { 160 | var upgrader = document.querySelector( \'#gutenblocks-upgrade\' ); 161 | 162 | upgrader.addEventListener( \'click\', function( event ) { 163 | event.target.remove(); 164 | } ); 165 | %s 166 | } )(); 167 | ', $auto_upgrader ) ); 168 | } 169 | add_action( 'load-dashboard_page_gutenblocks-upgrade', 'gutenblocks_upgrade_load' ); 170 | 171 | /** 172 | * Upgrade Administration screen output. 173 | * 174 | * @since 1.4.0 175 | */ 176 | function gutenblocks_upgrade_page() { 177 | $upgrade_url = add_query_arg( 'action', 'upgrade' ,gutenblocks_get_upgrade_url() ); 178 | 179 | $upgrading = $upgraded = false; 180 | 181 | if ( isset( $_GET['action'] ) ) { 182 | $upgrading = 'upgrade' === $_GET['action']; 183 | $upgraded = 'upgraded' === $_GET['action']; 184 | } 185 | 186 | if ( $upgraded ) { 187 | $message = esc_html__( 'La mise à niveau est terminée. Merci de votre patience.', 'gutenblocks' ); 188 | printf( '

%s

', $message ); 189 | } 190 | ?> 191 | 192 |
193 |

194 |

195 | 196 | 197 | 198 | 199 |

200 | 201 | 202 |

203 | 204 |

205 | 206 | 207 | 208 |
209 | 210 | 211 | 212 |
213 | 217 |
218 | 1
'; 232 | if ( isset( $_GET['action'] ) && 'upgraded' === $_GET['action'] ) { 233 | $count = ''; 234 | } 235 | 236 | add_dashboard_page( 237 | __( 'Mise à niveau de GutenBlocks', 'gutenblocks' ), 238 | sprintf( __( 'Mise à niveau de GutenBlocks%s', 'gutenblocks' ), $count ), 239 | 'manage_options', 240 | 'gutenblocks-upgrade', 241 | 'gutenblocks_upgrade_page' 242 | ); 243 | } 244 | add_action( 'admin_menu', 'gutenblocks_upgrade_menu' ); 245 | 246 | /** 247 | * Get the number of post objects containing at least a Photo block. 248 | * 249 | * @since 1.4.0 250 | * 251 | * @return integer The number of post objects containing at least a Photo block. 252 | */ 253 | function gutenblocks_count_photo_blocks_inserted() { 254 | $wpdb = $GLOBALS['wpdb']; 255 | 256 | return (int) $wpdb->get_var( "SELECT count(*) FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_content LIKE '%wp:gutenblocks/photo%'" ); 257 | } 258 | 259 | /** 260 | * Registers upgrade routines into the Entrepôt Upgrade API. 261 | * 262 | * @since 1.4.0 263 | */ 264 | function gutenblocks_add_upgrade_routines() { 265 | $db_version = gutenblocks_db_version(); 266 | // We are not using the Entrepôt Upgrade API for install. 267 | if ( 0 === (int) $db_version ) { 268 | return; 269 | } 270 | 271 | if ( version_compare( $db_version, gutenblocks_version(), '<' ) ) { 272 | entrepot_register_upgrade_tasks( 'gutenblocks', $db_version, array( 273 | '1.4.0' => array( 274 | array( 275 | 'callback' => 'gutenblocks_upgrade_photo_block', 276 | 'count' => 'gutenblocks_count_photo_blocks_inserted', 277 | 'message' => _x( 'Remplacement des blocks Photo par des blocs d’image. Merci de patienter', 'Upgrader feedback message', 'gutenblocks' ), 278 | 'number' => 20, 279 | ), 280 | array( 281 | 'callback' => 'gutenblocks_upgrade_db_version', 282 | 'count' => '__return_true', 283 | 'message' => _x( 'Mise à jour de la version de l’extension', 'Upgrader feedback message', 'gutenblocks' ), 284 | 'number' => 1, 285 | ), 286 | ), 287 | ) ); 288 | } 289 | } 290 | add_action( 'entrepot_register_upgrade_tasks', 'gutenblocks_add_upgrade_routines' ); 291 | 292 | /** 293 | * Add an upgrade notice to the Dashboard. 294 | * 295 | * @since 1.4.0 296 | */ 297 | function gutenblocks_upgrade_notice() { 298 | $current_screen = get_current_screen(); 299 | 300 | if ( isset( $current_screen->id ) && ( 'plugins_page_upgrade-repositories' === $current_screen->id || 'dashboard_page_gutenblocks-upgrade' === $current_screen->id ) ) { 301 | return; 302 | } 303 | ?> 304 |
305 |

306 | %2$s', esc_url( gutenblocks_get_upgrade_url() ), esc_html__( 'mise à niveau', 'gutenblocks' ) ) 308 | ); ?> 309 |

310 |
311 | ' 191 | } ) 192 | ); 193 | }, 194 | 195 | save: function( props ) { 196 | if ( ! props || ! props.attributes.url ) { 197 | return; 198 | } 199 | 200 | return el( 'div', null, '\n' + props.attributes.url + '\n' ); 201 | }, 202 | 203 | transforms: { 204 | from: [ 205 | { 206 | type: 'raw', 207 | isMatch: function ( node ) { 208 | return node.nodeName === 'P' && /^\s*(https?:\/\/gist\.github\.com\S+)\s*$/i.test( node.textContent ); 209 | }, 210 | transform: function( node ) { 211 | return createBlock( 'gutenblocks/gist', { 212 | url: node.textContent.trim() 213 | } ); 214 | } 215 | } 216 | ] 217 | } 218 | } ); 219 | 220 | } )( window.wp || {} ); 221 | -------------------------------------------------------------------------------- /js/blocks/gist.min.js: -------------------------------------------------------------------------------- 1 | !function(t){var s=t.element.createElement,e=t.blocks.registerBlockType,n=t.blocks.createBlock,i=t.components.SandBox,o=s("svg",{"aria-hidden":!0,role:"img",className:"dashicon gist-icon",focusable:"false",width:"20",height:"20",viewBox:"0 0 12 16",stroke:"#0073aa",strokeWidth:"0.5",xmlns:"http://www.w3.org/2000/svg"},s("path",{d:"M7.5 5L10 7.5 7.5 10l-.75-.75L8.5 7.5 6.75 5.75 7.5 5zm-3 0L2 7.5 4.5 10l.75-.75L3.5 7.5l1.75-1.75L4.5 5zM0 13V2c0-.55.45-1 1-1h10c.55 0 1 .45 1 1v11c0 .55-.45 1-1 1H1c-.55 0-1-.45-1-1zm1 0h10V2H1v11z"}));e("gutenblocks/gist",{title:gutenBlocksStrings.gist.title,description:gutenBlocksStrings.gist.description,icon:function(){return o},category:"embed",attributes:{url:{type:"string"},src:{type:"string"}},edit:function(e){var t;return!e.attributes.url&&!e.attributes.loading||e.attributes.needsSubmit?(e.setAttributes({needsSubmit:!0}),s("div",{className:"components-placeholder wp-block-embed is-large"},[s("div",{key:"block-placeholder",className:"components-placeholder__label"},[s("span",{key:"block-icon",className:"block-editor-block-icon has-colors"},o),gutenBlocksStrings.gist.title]),s("div",{key:"block-instructions",className:"components-placeholder__instructions"},gutenBlocksStrings.gist.instructions),s("div",{key:"block-fieldset",className:"components-placeholder__fieldset"},s("form",{onSubmit:function(t){t.preventDefault(),e.setAttributes({loading:!0,needsSubmit:!1})}},[s("input",{key:"url-input",type:"url",id:"url-input-"+e.id,className:"components-placeholder__input",placeholder:gutenBlocksStrings.gist.inputPlaceholder,onChange:function(t){t.preventDefault(),e.setAttributes({url:t.target.value})}}),s("button",{key:"url-button",type:"submit",className:"components-button is-primary"},gutenBlocksStrings.gist.buttonPlaceholder)]))])):e.attributes.src?s("figure",{key:"gist-sandbox",className:"wp-block-embed"},s(i,{html:'