Skip to content

Commit f5a2567

Browse files
jasonbahlizzygld
andauthored
feat: add siteIcon and siteIconUrl fields to GeneralSettings (#3475)
Co-authored-by: izzygld <[email protected]>
1 parent 35e8d45 commit f5a2567

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed

plugins/wp-graphql/src/Registry/TypeRegistry.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
namespace WPGraphQL\Registry;
44

55
use GraphQL\Error\Error;
6+
use GraphQL\Type\Definition\ResolveInfo;
67
use GraphQL\Type\Definition\Type;
78
use WPGraphQL;
9+
use WPGraphQL\AppContext;
10+
use WPGraphQL\Data\Connection\PostObjectConnectionResolver;
811
use WPGraphQL\Data\DataSource;
912
use WPGraphQL\Mutation\CommentCreate;
1013
use WPGraphQL\Mutation\CommentDelete;
@@ -590,6 +593,73 @@ public function init_type_registry( self $type_registry ) {
590593
);
591594
}
592595

596+
/**
597+
* Register the siteIconUrl field on GeneralSettings.
598+
*
599+
* WordPress Site Icon is a feature that allows users to set a favicon/icon
600+
* for their site. This exposes that icon URL to the GraphQL Schema.
601+
*
602+
* @see https://developer.wordpress.org/reference/functions/get_site_icon_url/
603+
*/
604+
$this->register_field(
605+
'GeneralSettings',
606+
'siteIconUrl',
607+
[
608+
'type' => 'String',
609+
'description' => static function () {
610+
return __( 'Site icon URL configured in site settings, used as the site\'s favicon and app icon.', 'wp-graphql' );
611+
},
612+
'args' => [
613+
'size' => [
614+
'type' => 'Int',
615+
'description' => static function () {
616+
return __( 'Size of the site icon in pixels. Defaults to 512. Max 512.', 'wp-graphql' );
617+
},
618+
],
619+
],
620+
'resolve' => static function ( $source, array $args ) {
621+
$size = ! empty( $args['size'] ) ? absint( $args['size'] ) : 512;
622+
// WordPress site icons are uploaded at 512x512 max, clamp the size.
623+
$size = min( $size, 512 );
624+
$url = get_site_icon_url( $size );
625+
626+
return ! empty( $url ) ? $url : null;
627+
},
628+
]
629+
);
630+
631+
/**
632+
* Register the siteIcon connection on GeneralSettings.
633+
*
634+
* This provides access to the MediaItem that is set as the site icon,
635+
* allowing clients to access all media properties (alt text, sizes, etc).
636+
*
637+
* @see https://developer.wordpress.org/reference/functions/get_option/ (site_icon option)
638+
*/
639+
register_graphql_connection(
640+
[
641+
'fromType' => 'GeneralSettings',
642+
'toType' => 'MediaItem',
643+
'fromFieldName' => 'siteIcon',
644+
'oneToOne' => true,
645+
'description' => static function () {
646+
return __( 'The media item representing the site icon configured in site settings, used as the site\'s favicon and app icon.', 'wp-graphql' );
647+
},
648+
'resolve' => static function ( $source, array $args, AppContext $context, ResolveInfo $info ) {
649+
$site_icon_id = get_option( 'site_icon' );
650+
651+
if ( empty( $site_icon_id ) ) {
652+
return null;
653+
}
654+
655+
$resolver = new PostObjectConnectionResolver( $source, $args, $context, $info, 'attachment' );
656+
$resolver->set_query_arg( 'p', absint( $site_icon_id ) );
657+
658+
return $resolver->one_to_one()->get_connection();
659+
},
660+
]
661+
);
662+
593663
if ( ! empty( $allowed_setting_types ) && is_array( $allowed_setting_types ) ) {
594664
foreach ( $allowed_setting_types as $group_name => $setting_type ) {
595665
$group_name = DataSource::format_group_name( $group_name );

plugins/wp-graphql/tests/wpunit/SettingQueriesTest.php

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,4 +571,163 @@ static function () use ( $expected ) {
571571
$this->assertArrayNotHasKey( 'errors', $actual );
572572
$this->assertSame( $expected, $actual['data']['generalSettings']['myCustomField'] );
573573
}
574+
575+
/**
576+
* Test that the siteIconUrl field returns null when no site icon is set.
577+
*
578+
* @return void
579+
*/
580+
public function testSiteIconUrlReturnsNullWhenNotSet() {
581+
// Ensure no site icon is set.
582+
delete_option( 'site_icon' );
583+
584+
$query = '
585+
{
586+
generalSettings {
587+
siteIconUrl
588+
}
589+
}
590+
';
591+
592+
$actual = $this->graphql( compact( 'query' ) );
593+
594+
$this->assertArrayNotHasKey( 'errors', $actual );
595+
$this->assertNull( $actual['data']['generalSettings']['siteIconUrl'] );
596+
}
597+
598+
/**
599+
* Test that the siteIconUrl field returns the URL when a site icon is set.
600+
*
601+
* @return void
602+
*/
603+
public function testSiteIconUrlReturnsUrlWhenSet() {
604+
// Create a test attachment to use as site icon.
605+
$filename = WPGRAPHQL_PLUGIN_DIR . 'tests/_data/images/test.png';
606+
$attachment_id = $this->factory()->attachment->create_upload_object( $filename );
607+
608+
// Set the site icon.
609+
update_option( 'site_icon', $attachment_id );
610+
611+
$query = '
612+
{
613+
generalSettings {
614+
siteIconUrl
615+
}
616+
}
617+
';
618+
619+
$actual = $this->graphql( compact( 'query' ) );
620+
621+
$this->assertArrayNotHasKey( 'errors', $actual );
622+
$this->assertNotNull( $actual['data']['generalSettings']['siteIconUrl'] );
623+
$this->assertStringContainsString( 'test', $actual['data']['generalSettings']['siteIconUrl'] );
624+
625+
// Cleanup.
626+
delete_option( 'site_icon' );
627+
wp_delete_attachment( $attachment_id, true );
628+
}
629+
630+
/**
631+
* Test that the siteIconUrl field respects the size argument.
632+
*
633+
* @return void
634+
*/
635+
public function testSiteIconUrlWithSizeArgument() {
636+
// Create a test attachment to use as site icon.
637+
$filename = WPGRAPHQL_PLUGIN_DIR . 'tests/_data/images/test.png';
638+
$attachment_id = $this->factory()->attachment->create_upload_object( $filename );
639+
640+
// Set the site icon.
641+
update_option( 'site_icon', $attachment_id );
642+
643+
$query = '
644+
{
645+
generalSettings {
646+
defaultSize: siteIconUrl
647+
smallSize: siteIconUrl(size: 32)
648+
largeSize: siteIconUrl(size: 512)
649+
}
650+
}
651+
';
652+
653+
$actual = $this->graphql( compact( 'query' ) );
654+
655+
$this->assertArrayNotHasKey( 'errors', $actual );
656+
$this->assertNotNull( $actual['data']['generalSettings']['defaultSize'] );
657+
$this->assertNotNull( $actual['data']['generalSettings']['smallSize'] );
658+
$this->assertNotNull( $actual['data']['generalSettings']['largeSize'] );
659+
660+
// Cleanup.
661+
delete_option( 'site_icon' );
662+
wp_delete_attachment( $attachment_id, true );
663+
}
664+
665+
/**
666+
* Test that the siteIcon connection returns null when no site icon is set.
667+
*
668+
* @return void
669+
*/
670+
public function testSiteIconConnectionReturnsNullWhenNotSet() {
671+
// Ensure no site icon is set.
672+
delete_option( 'site_icon' );
673+
674+
$query = '
675+
{
676+
generalSettings {
677+
siteIcon {
678+
node {
679+
id
680+
databaseId
681+
sourceUrl
682+
}
683+
}
684+
}
685+
}
686+
';
687+
688+
$actual = $this->graphql( compact( 'query' ) );
689+
690+
$this->assertArrayNotHasKey( 'errors', $actual );
691+
$this->assertNull( $actual['data']['generalSettings']['siteIcon'] );
692+
}
693+
694+
/**
695+
* Test that the siteIcon connection returns the MediaItem when a site icon is set.
696+
*
697+
* @return void
698+
*/
699+
public function testSiteIconConnectionReturnsMediaItemWhenSet() {
700+
// Create a test attachment to use as site icon.
701+
$filename = WPGRAPHQL_PLUGIN_DIR . 'tests/_data/images/test.png';
702+
$attachment_id = $this->factory()->attachment->create_upload_object( $filename );
703+
704+
// Set the site icon.
705+
update_option( 'site_icon', $attachment_id );
706+
707+
$query = '
708+
{
709+
generalSettings {
710+
siteIcon {
711+
node {
712+
id
713+
databaseId
714+
sourceUrl
715+
}
716+
}
717+
}
718+
}
719+
';
720+
721+
$actual = $this->graphql( compact( 'query' ) );
722+
723+
$this->assertArrayNotHasKey( 'errors', $actual );
724+
$this->assertNotNull( $actual['data']['generalSettings']['siteIcon'] );
725+
$this->assertNotNull( $actual['data']['generalSettings']['siteIcon']['node'] );
726+
$this->assertEquals( $attachment_id, $actual['data']['generalSettings']['siteIcon']['node']['databaseId'] );
727+
$this->assertNotNull( $actual['data']['generalSettings']['siteIcon']['node']['sourceUrl'] );
728+
729+
// Cleanup.
730+
delete_option( 'site_icon' );
731+
wp_delete_attachment( $attachment_id, true );
732+
}
574733
}

0 commit comments

Comments
 (0)