diff --git a/core/includes/theme.inc b/core/includes/theme.inc index b5b5175d9a2ba9aaa942682eab299072d405eea6..371e0fe929a246120acaa16f9876458c98aad0e6 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -250,28 +250,45 @@ function theme_get_setting($setting_name, $theme = NULL) { /** @var \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator */ $file_url_generator = \Drupal::service('file_url_generator'); + // A dummy query-string is added to filenames, to gain control over + // browser-caching. The string changes on every update or full cache + // flush, forcing browsers to load a new copy of the files, as the + // URL changed. + // We need try-catch due to the installer not having a state yet. + try { + $query_string = \Drupal::service('asset.query_string')->get(); + } + catch (Exception) { + $query_string = '0'; + } + // Generate the path to the logo image. if ($cache[$theme]->get('logo.use_default')) { - $logo = \Drupal::service('theme.initialization')->getActiveThemeByName($theme)->getLogo(); - $cache[$theme]->set('logo.url', $file_url_generator->generateString($logo)); + $logo_path = \Drupal::service('theme.initialization')->getActiveThemeByName($theme)->getLogo(); + } + else { + $logo_path = $cache[$theme]->get('logo.path'); } - elseif ($logo_path = $cache[$theme]->get('logo.path')) { - $cache[$theme]->set('logo.url', $file_url_generator->generateString($logo_path)); + if (isset($logo_path) && is_string($logo_path)) { + $query_string_separator = (strpos($logo_path, '?') !== FALSE) ? '&' : '?'; + $cache[$theme]->set('logo.url', $file_url_generator->generateString($logo_path) . $query_string_separator . $query_string); } // Generate the path to the favicon. if ($cache[$theme]->get('features.favicon')) { - $favicon_path = $cache[$theme]->get('favicon.path'); if ($cache[$theme]->get('favicon.use_default')) { - if (file_exists($favicon = $theme_object->getPath() . '/favicon.ico')) { - $cache[$theme]->set('favicon.url', $file_url_generator->generateString($favicon)); - } - else { - $cache[$theme]->set('favicon.url', $file_url_generator->generateString('core/misc/favicon.ico')); + $favicon_path = $theme_object->getPath() . '/favicon.ico'; + if (!file_exists($favicon_path)) { + $favicon_path = 'core/misc/favicon.ico'; } } - elseif ($favicon_path) { - $cache[$theme]->set('favicon.url', $file_url_generator->generateString($favicon_path)); + else { + $favicon_path = $cache[$theme]->get('favicon.path'); + } + + if ($favicon_path) { + $query_string_separator = (strpos($favicon_path, '?') !== FALSE) ? '&' : '?'; + $cache[$theme]->set('favicon.url', $file_url_generator->generateString($favicon_path) . $query_string_separator . $query_string); } else { $cache[$theme]->set('features.favicon', FALSE); diff --git a/core/tests/Drupal/KernelTests/Core/Theme/ThemeSettingsTest.php b/core/tests/Drupal/KernelTests/Core/Theme/ThemeSettingsTest.php index 569921b6167b92c53da5fdbb9dbfdf1b2255d7c7..91d2e0739f93798aea846aa860242913716d6868 100644 --- a/core/tests/Drupal/KernelTests/Core/Theme/ThemeSettingsTest.php +++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeSettingsTest.php @@ -75,8 +75,11 @@ public function testLogoConfig(): void { $theme = $theme_handler->getTheme('stark'); // Tests default behavior. - $expected = '/' . $theme->getPath() . '/logo.svg'; - $this->assertEquals($expected, theme_get_setting('logo.url', 'stark')); + $logo_url = theme_get_setting('logo.url', 'stark'); + $expected_path = '/' . $theme->getPath() . '/logo.svg'; + $this->setRawContent($logo_url); + $this->assertRaw($expected_path, 'Logo URL contains the correct base path.'); + $this->assertPattern('/\?[0-9]+$/', 'Logo URL contains a cache-busting query parameter.'); $config = $this->config('stark.settings'); drupal_static_reset('theme_get_setting'); @@ -90,8 +93,12 @@ public function testLogoConfig(): void { // Tests logo path with scheme. /** @var \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator */ $file_url_generator = \Drupal::service('file_url_generator'); - $expected = $file_url_generator->generateString('public://logo_with_scheme.png'); - $this->assertEquals($expected, theme_get_setting('logo.url', 'stark')); + $expected_base = $file_url_generator->generateString('public://logo_with_scheme.png'); + $expected_base = preg_replace('/\?.*$/', '', $expected_base); + $logo_url = theme_get_setting('logo.url', 'stark'); + $this->setRawContent($logo_url); + $this->assertRaw($expected_base, 'Logo URL with scheme contains the correct base path.'); + $this->assertPattern('/\?[0-9]+$/', 'Logo URL with scheme contains a cache-busting query parameter.'); $values = [ 'default_logo' => FALSE, @@ -102,8 +109,11 @@ public function testLogoConfig(): void { drupal_static_reset('theme_get_setting'); // Tests relative path. - $expected = '/' . $theme->getPath() . '/logo_relative_path.gif'; - $this->assertEquals($expected, theme_get_setting('logo.url', 'stark')); + $expected_path = '/' . $theme->getPath() . '/logo_relative_path.gif'; + $logo_url = theme_get_setting('logo.url', 'stark'); + $this->setRawContent($logo_url); + $this->assertRaw($expected_path, 'Relative path logo URL contains the correct base path.'); + $this->assertPattern('/\?[0-9]+$/', 'Relative path logo URL contains a cache-busting query parameter.'); $theme_installer->install(['test_theme']); \Drupal::configFactory() @@ -115,8 +125,11 @@ public function testLogoConfig(): void { drupal_static_reset('theme_get_setting'); // Tests logo set in test_theme.info.yml. - $expected = '/' . $theme->getPath() . '/images/logo2.svg'; - $this->assertEquals($expected, theme_get_setting('logo.url', 'test_theme')); + $expected_path = '/' . $theme->getPath() . '/images/logo2.svg'; + $logo_url = theme_get_setting('logo.url', 'test_theme'); + $this->setRawContent($logo_url); + $this->assertRaw($expected_path, 'Info.yml logo URL contains the correct base path.'); + $this->assertPattern('/\?[0-9]+$/', 'Info.yml logo URL contains a cache-busting query parameter.'); } }