diff --git a/.plugin-data b/.plugin-data index 80a8f24..92727a0 100644 --- a/.plugin-data +++ b/.plugin-data @@ -1,4 +1,4 @@ { - "version": "1.1.2", + "version": "1.1.3", "slug": "blockparty-icons" } diff --git a/CHANGELOG.md b/CHANGELOG.md index b9efc8b..cc9f61f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ This plugin **doesn't run any sanitization on SVGs** before using them. Only use ## Changelog +### 1.1.3 - 2026-10-02 + +- Improved link editing with external link support and an edit button + ### 1.1.2 - 2026-09-17 - Fix `beapi/icon-block` migration skipping icons that have a name but no collection (registry lookup then generic fallback) diff --git a/blockparty-icons.php b/blockparty-icons.php index 75dd4ae..2dbcd37 100644 --- a/blockparty-icons.php +++ b/blockparty-icons.php @@ -4,7 +4,7 @@ * Description: Provides blocks in WordPress editor to add custom SVG icons. * Requires at least: 6.2 * Requires PHP: 8.1 - * Version: 1.1.2 + * Version: 1.1.3 * Author: Be API Technical Team * Author URI: https://beapi.fr * License: GPL-2.0-or-later @@ -30,7 +30,7 @@ include_once __DIR__ . '/vendor/autoload.php'; } -define( 'BLOCKPARTY_ICONS_VERSION', '1.1.2' ); +define( 'BLOCKPARTY_ICONS_VERSION', '1.1.3' ); define( 'BLOCKPARTY_ICONS_URL', plugin_dir_url( __FILE__ ) ); define( 'BLOCKPARTY_ICONS_DIR', plugin_dir_path( __FILE__ ) ); define( 'BLOCKPARTY_ICONS_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); diff --git a/includes/BlockRenderer.php b/includes/BlockRenderer.php index 9dbabb0..6292b71 100644 --- a/includes/BlockRenderer.php +++ b/includes/BlockRenderer.php @@ -17,10 +17,11 @@ class BlockRenderer { */ public static function render( $attributes ) { // Block attributes - $icon_data = $attributes['icon'] ?? []; - $radius = (string) ( $attributes['borderRadius'] ?? '0px' ); - $link_url = (string) ( $attributes['url'] ?? '' ); - $link_label = (string) ( $attributes['label'] ?? '' ); + $icon_data = $attributes['icon'] ?? []; + $radius = (string) ( $attributes['borderRadius'] ?? '0px' ); + $link_url = (string) ( $attributes['url'] ?? '' ); + $link_label = (string) ( $attributes['label'] ?? '' ); + $target_blank = ! empty( $attributes['targetBlank'] ); $collection_name = $icon_data['collection'] ?? null; $icon_name = $icon_data['name'] ?? null; @@ -52,10 +53,17 @@ public static function render( $attributes ) { // Start block link if ( ! empty( $link_url ) ) { + $link_attrs = ''; + if ( ! empty( $link_label ) ) { + $link_attrs .= sprintf( ' aria-label="%s"', esc_attr( $link_label ) ); + } + if ( $target_blank ) { + $link_attrs .= ' target="_blank" rel="noopener noreferrer"'; + } $html .= sprintf( '', esc_url( $link_url ), - ! empty( $link_label ) ? sprintf( ' aria-label="%s"', esc_attr( $link_label ) ) : '' + $link_attrs ); } diff --git a/languages/blockparty-icons-fr_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json b/languages/blockparty-icons-fr_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json index 553ef36..dd63b3d 100644 --- a/languages/blockparty-icons-fr_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json +++ b/languages/blockparty-icons-fr_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json @@ -1 +1 @@ -{"translation-revision-date":"2026-06-25 08:38+0200","generator":"WP-CLI\/2.11.0","source":"build\/index.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"fr_FR","plural-forms":"nplurals=2; plural=(n != 1);"},"No name icon":["Ic\u00f4ne sans nom"],"Icon pagination":["Pagination des ic\u00f4nes"],"Previous page":["Page pr\u00e9c\u00e9dente"],"Previous":["Pr\u00e9c\u00e9dent"],"Page %d":["Page %d"],"Next page":["Page suivante"],"Next":["Suivant"],"Select an icon from your collections":["S\u00e9lectionnez une ic\u00f4ne dans vos collections"],"Search an icon":["Recherche une ic\u00f4ne"],"wordpress, heart, star\u2026":["wordpress, coeur, etoile\u2026"],"Hide settings":["Masquer les r\u00e9glages"],"Open settings":["Afficher les r\u00e9glages"],"Modal settings":["R\u00e9glages de la modale"],"Display":["Affichage"],"Preview of icon sizes":["Aper\u00e7u de la taille des ic\u00f4nes"],"Adjust preview size of the icons.":["Ajuster la taille de pr\u00e9visualisation des ic\u00f4nes."],"Pager":["Pagination"],"Icons per page":["Ic\u00f4nes par page"],"Number of icons displayed per page.":["Nombre d\u2019ic\u00f4nes \u00e0 afficher par page."],"No icons found matching your search.":["Aucune ic\u00f4ne trouv\u00e9e selon vos crit\u00e8res de recherche."],"%1$s (%2$d)":["%1$s (%2$d)"],"Icon color":["Couleur de l\u2019ic\u00f4ne"],"Add an icon":["Ajouter une ic\u00f4ne"],"Remove link":["Retirer le lien"],"Add a link":["Ajouter un lien"],"Replace icon":["Remplacer l\u2019ic\u00f4ne"],"Remove icon":["Retirer l\u2019ic\u00f4ne"],"Label of %s":["Libell\u00e9 de %s"],"Link label":["Libell\u00e9 du lien"],"Briefly describe the link to help screen reader users.":["D\u00e9crivez bri\u00e8vement le lien destin\u00e9 aux utilisateurs de lecteurs d'\u00e9cran."],"Icon radius":["Arrondis de l\u2019ic\u00f4ne"],"Icon size":["Taille de l\u2019ic\u00f4ne"],"Adjust the size of the icon (value in pixels)":["Ajustez la taille de l\u2019ic\u00f4ne (valeur en pixels)"]}}} \ No newline at end of file +{"translation-revision-date":"2026-10-02 10:57+0200","generator":"WP-CLI\/2.12.0","source":"build\/index.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"fr_FR","plural-forms":"nplurals=2; plural=(n != 1);"},"No name icon":["Ic\u00f4ne sans nom"],"Icon pagination":["Pagination des ic\u00f4nes"],"Previous page":["Page pr\u00e9c\u00e9dente"],"Previous":["Pr\u00e9c\u00e9dent"],"Page %d":["Page %d"],"Next page":["Page suivante"],"Next":["Suivant"],"Select an icon from your collections":["S\u00e9lectionnez une ic\u00f4ne dans vos collections"],"Search an icon":["Recherche une ic\u00f4ne"],"wordpress, heart, star\u2026":["wordpress, coeur, etoile\u2026"],"Hide settings":["Masquer les r\u00e9glages"],"Open settings":["Afficher les r\u00e9glages"],"Modal settings":["R\u00e9glages de la modale"],"Display":["Affichage"],"Preview of icon sizes":["Aper\u00e7u de la taille des ic\u00f4nes"],"Adjust preview size of the icons.":["Ajuster la taille de pr\u00e9visualisation des ic\u00f4nes."],"Pager":["Pagination"],"Icons per page":["Ic\u00f4nes par page"],"Number of icons displayed per page.":["Nombre d\u2019ic\u00f4nes \u00e0 afficher par page."],"No icons found matching your search.":["Aucune ic\u00f4ne trouv\u00e9e selon vos crit\u00e8res de recherche."],"%1$s (%2$d)":["%1$s (%2$d)"],"Open in a new tab":["Ouvrir dans un nouvel onglet"],"Icon color":["Couleur de l\u2019ic\u00f4ne"],"Add an icon":["Ajouter une ic\u00f4ne"],"Edit link":["Modifier le lien"],"Remove link":["Retirer le lien"],"Add a link":["Ajouter un lien"],"Replace icon":["Remplacer l\u2019ic\u00f4ne"],"Remove icon":["Retirer l\u2019ic\u00f4ne"],"Label of %s":["Libell\u00e9 de %s"],"Link label":["Libell\u00e9 du lien"],"Briefly describe the link to help screen reader users.":["D\u00e9crivez bri\u00e8vement le lien destin\u00e9 aux utilisateurs de lecteurs d'\u00e9cran."],"Icon radius":["Arrondis de l\u2019ic\u00f4ne"],"Icon size":["Taille de l\u2019ic\u00f4ne"],"Adjust the size of the icon (value in pixels)":["Ajustez la taille de l\u2019ic\u00f4ne (valeur en pixels)"]}}} \ No newline at end of file diff --git a/languages/blockparty-icons-fr_FR.mo b/languages/blockparty-icons-fr_FR.mo index 67c1218..cf83044 100644 Binary files a/languages/blockparty-icons-fr_FR.mo and b/languages/blockparty-icons-fr_FR.mo differ diff --git a/languages/blockparty-icons-fr_FR.po b/languages/blockparty-icons-fr_FR.po index 6d364a8..715d844 100644 --- a/languages/blockparty-icons-fr_FR.po +++ b/languages/blockparty-icons-fr_FR.po @@ -5,15 +5,15 @@ msgstr "" "Project-Id-Version: Blockparty Icons 1.0.0\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/blockparty-" "icons\n" -"POT-Creation-Date: 2026-06-25T06:37:19+00:00\n" -"PO-Revision-Date: 2026-06-25 08:38+0200\n" +"POT-Creation-Date: 2026-10-02T08:52:14+00:00\n" +"PO-Revision-Date: 2026-10-02 10:57+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr_FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 3.9\n" +"X-Generator: Poedit 3.6\n" "X-Domain: blockparty-icons\n" #. Plugin Name of the plugin @@ -164,6 +164,10 @@ msgstr "Aucune icône trouvée selon vos critères de recherche." msgid "%1$s (%2$d)" msgstr "%1$s (%2$d)" +#: build/index.js:3 +msgid "Open in a new tab" +msgstr "Ouvrir dans un nouvel onglet" + #: build/index.js:3 msgid "Icon color" msgstr "Couleur de l’icône" @@ -172,6 +176,10 @@ msgstr "Couleur de l’icône" msgid "Add an icon" msgstr "Ajouter une icône" +#: build/index.js:3 +msgid "Edit link" +msgstr "Modifier le lien" + #: build/index.js:3 msgid "Remove link" msgstr "Retirer le lien" diff --git a/languages/blockparty-icons.pot b/languages/blockparty-icons.pot index c35d80e..939b65a 100644 --- a/languages/blockparty-icons.pot +++ b/languages/blockparty-icons.pot @@ -2,16 +2,16 @@ # This file is distributed under the GPL-2.0-or-later. msgid "" msgstr "" -"Project-Id-Version: Blockparty Icons 1.0.7\n" +"Project-Id-Version: Blockparty Icons 1.1.2\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/blockparty-icons\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-06-25T06:37:19+00:00\n" +"POT-Creation-Date: 2026-10-02T08:52:14+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"X-Generator: WP-CLI 2.11.0\n" +"X-Generator: WP-CLI 2.12.0\n" "X-Domain: blockparty-icons\n" #. Plugin Name of the plugin @@ -92,6 +92,7 @@ msgstr "" #. translators: %d: page number #: build/index.js:2 +#, js-format msgid "Page %d" msgstr "" @@ -157,9 +158,14 @@ msgstr "" #. translators: 1: collection name, 2: number of results #: build/index.js:3 +#, js-format msgid "%1$s (%2$d)" msgstr "" +#: build/index.js:3 +msgid "Open in a new tab" +msgstr "" + #: build/index.js:3 msgid "Icon color" msgstr "" @@ -168,6 +174,10 @@ msgstr "" msgid "Add an icon" msgstr "" +#: build/index.js:3 +msgid "Edit link" +msgstr "" + #: build/index.js:3 msgid "Remove link" msgstr "" @@ -186,6 +196,7 @@ msgstr "" #. translators: %s: name of the icon name. #: build/index.js:4 +#, js-format msgid "Label of %s" msgstr "" diff --git a/package-lock.json b/package-lock.json index 12e4c07..baf27a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "blockparty-icons", - "version": "1.1.2", + "version": "1.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "blockparty-icons", - "version": "1.1.2", + "version": "1.1.3", "license": "GPL-2.0-or-later", "dependencies": { "@beapi/icons": "^1.2.5", diff --git a/package.json b/package.json index 1600dbc..bf163ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockparty-icons", - "version": "1.1.2", + "version": "1.1.3", "description": "Provides blocks in WordPress editor to add custom SVG icons from your theme.", "author": "Be API Technical team", "license": "GPL-2.0-or-later", diff --git a/readme.txt b/readme.txt index 91ab7d8..e3b5a6b 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: block, icons, svg, gutenberg, editor Requires at least: 6.2 Tested up to: 6.8 Requires PHP: 8.1 -Stable tag: 1.1.2 +Stable tag: 1.1.3 License: GPL-2.0-or-later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -36,6 +36,9 @@ Yes. Register a collection with `type` set to `folder` and `source` pointing to == Changelog == += 1.1.3 = +* Improved link editing with external link support and an edit button + = 1.1.2 = * Fix `beapi/icon-block` migration skipping icons that have a name but no collection (registry lookup then generic fallback). * Load an icon's SVG only when it is used. Registering a collection now builds a lightweight index, so a front-end page no longer holds every icon of every collection in memory. diff --git a/src/block.json b/src/block.json index d447f27..e7d0f83 100644 --- a/src/block.json +++ b/src/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/icon", - "version": "1.1.2", + "version": "1.1.3", "title": "Icon", "category": "widgets", "description": "Easily add custom vector icon to your content.", @@ -51,6 +51,10 @@ }, "label": { "type": "string" + }, + "targetBlank": { + "type": "boolean", + "default": false } }, "textdomain": "blockparty-icons", diff --git a/src/components/link-url-popover.js b/src/components/link-url-popover.js index 20e24bd..b02cd6d 100644 --- a/src/components/link-url-popover.js +++ b/src/components/link-url-popover.js @@ -9,11 +9,12 @@ import { store as blockEditorStore, } from '@wordpress/block-editor'; import { __ } from '@wordpress/i18n'; -import { Button } from '@wordpress/components'; +import { Button, ToggleControl } from '@wordpress/components'; import { keyboardReturn } from '@wordpress/icons'; export default function SocialLinkURLPopover( { url, + targetBlank, setAttributes, setPopover, popoverAnchor, @@ -25,42 +26,54 @@ export default function SocialLinkURLPopover( { anchor={ popoverAnchor } onClose={ () => setPopover( false ) } > -
{ - event.preventDefault(); - setPopover( false ); - } } - > -
- + { + event.preventDefault(); + setPopover( false ); + } } + > +
+ + setAttributes( { url: nextURL } ) + } + placeholder={ __( 'Enter address' ) } + disableSuggestions={ true } + onKeyDown={ ( event ) => { + if ( + !! url || + event.defaultPrevented || + ! [ BACKSPACE, DELETE ].includes( + event.keyCode + ) + ) { + return; + } + removeBlock( clientId ); + } } + /> +
+
); } diff --git a/src/edit.js b/src/edit.js index 4f36e8d..3984886 100644 --- a/src/edit.js +++ b/src/edit.js @@ -90,7 +90,8 @@ export default function Edit( { isSelected, setAttributes, } ) { - const { borderRadius, iconColor, icon, label, size, url } = attributes; + const { borderRadius, iconColor, icon, label, targetBlank, size, url } = + attributes; const blockRef = useRef( null ); const [ icons, setIcons ] = useState( null ); @@ -107,7 +108,8 @@ export default function Edit( { }; const removeLink = () => { - setAttributes( { url: '' } ); + setPopover( false ); + setAttributes( { url: '', targetBlank: false } ); }; const openIconModal = () => { @@ -233,15 +235,32 @@ export default function Edit( { { icon && ( <> - + { url ? ( + + + + + ) : ( + + ) } @@ -267,6 +286,7 @@ export default function Edit( { { showURLPopover && ( assertStringNotContainsString( 'aria-label', $html ); } + public function test_url_without_target_blank_has_no_target_or_rel(): void { + $html = $this->render( + [ + 'icon' => $this->icon(), + 'url' => 'https://example.org', + ] + ); + + $this->assertStringNotContainsString( 'target=', $html ); + $this->assertStringNotContainsString( 'rel=', $html ); + } + + public function test_target_blank_adds_target_and_rel(): void { + $html = $this->render( + [ + 'icon' => $this->icon(), + 'url' => 'https://example.org', + 'targetBlank' => true, + ] + ); + + $this->assertStringContainsString( 'target="_blank"', $html ); + $this->assertStringContainsString( 'rel="noopener noreferrer"', $html ); + } + + public function test_target_blank_false_leaves_link_unchanged(): void { + $html = $this->render( + [ + 'icon' => $this->icon(), + 'url' => 'https://example.org', + 'targetBlank' => false, + ] + ); + + $this->assertStringContainsString( 'href="https://example.org"', $html ); + $this->assertStringNotContainsString( 'target=', $html ); + $this->assertStringNotContainsString( 'rel=', $html ); + } + + public function test_target_blank_without_url_produces_no_link(): void { + $html = $this->render( + [ + 'icon' => $this->icon(), + 'targetBlank' => true, + ] + ); + + $this->assertStringNotContainsString( '