Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 37 additions & 13 deletions dash/_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,24 +380,48 @@
return {}, None


def _page_meta_tags(app, request):
request_path = request.path
start_page, path_variables = _path_to_page(request_path.strip("/"))
def _get_image_url(app, request, image, supplied_image_url):
if supplied_image_url:
return supplied_image_url

image = start_page.get("image", "")
if image:
if image.startswith(("http://", "https://")):
return image

image = app.get_asset_url(image)
assets_image_url = "".join([request.root, image.lstrip("/")]) if image else None
supplied_image_url = start_page.get("image_url")
image_url = supplied_image_url if supplied_image_url else assets_image_url
return "".join([request.root, image.lstrip("/")])

return None

title = start_page.get("title", app.title)
if callable(title):
title = title(**path_variables) if path_variables else title()

description = start_page.get("description", "")
if callable(description):
description = description(**path_variables) if path_variables else description()
def _page_meta_tags(app, request):

Check failure on line 397 in dash/_pages.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 20 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=plotly_dash&issues=AaDvZ1KhQyHZJmg_OU3s&open=AaDvZ1KhQyHZJmg_OU3s&pullRequest=4024
if not app.use_pages and not (app.description or app.image):
return []

title = app.title
description = app.description or ""
image = app.image
supplied_image_url = None

if app.use_pages:
request_path = request.path
start_page, path_variables = _path_to_page(request_path.strip("/"))

if start_page:
title = start_page.get("title", title)
description = start_page.get("description", description)
image = start_page.get("image") or image
supplied_image_url = start_page.get("image_url")

if callable(title):
title = title(**path_variables) if path_variables else title()

if callable(description):
description = (
description(**path_variables) if path_variables else description()
)

image_url = _get_image_url(app, request, image, supplied_image_url)

return [
{"name": "description", "content": description},
Expand Down
40 changes: 24 additions & 16 deletions dash/dash.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,23 @@ class Dash(ObsoleteChecker):
to be True. Default `None`.
:type use_pages: boolean

:param include_pages_meta: Include the page meta tags for twitter cards.
:param include_pages_meta: Include the meta tags for social media cards.
:type include_pages_meta: bool

:param title: Default ``Dash``. Configures the document.title
(the text that appears in a browser tab).

:param update_title: Default ``Updating...``. Configures the document.title
(the text that appears in a browser tab) text when a callback is being run.
Set to None or '' if you don't want the document.title to change or if you
want to control the document.title through a separate component or
clientside callback.

:param description: Sets a default description for meta tags.

:param image: The default image used for social media cards. Can be the
name of an image in the assets folder or an image URL.

:param assets_url_path: The local urls for assets will be:
``requests_pathname_prefix + assets_url_path + '/' + asset_path``
where ``asset_path`` is the path to a file inside ``assets_folder``.
Expand Down Expand Up @@ -399,15 +413,6 @@ class Dash(ObsoleteChecker):
be called after the Flask server is attached.
:type plugins: list of objects

:param title: Default ``Dash``. Configures the document.title
(the text that appears in a browser tab).

:param update_title: Default ``Updating...``. Configures the document.title
(the text that appears in a browser tab) text when a callback is being run.
Set to None or '' if you don't want the document.title to change or if you
want to control the document.title through a separate component or
clientside callback.

:param background_callback_manager: Background callback manager instance
to support the ``@callback(..., background=True)`` decorator.
One of ``DiskcacheManager`` or ``CeleryManager`` currently supported.
Expand All @@ -425,8 +430,6 @@ class Dash(ObsoleteChecker):
`routing_callback_inputs={"language": Input("language", "value")}`
NOTE: the keys "pathname_" and "search_" are reserved for internal use.

:param description: Sets a default description for meta tags on Dash pages (use_pages=True).

:param on_error: Global callback error handler to call when
an exception is raised. Receives the exception object as first argument.
The callback_context can be used to access the original callback inputs,
Expand Down Expand Up @@ -492,6 +495,10 @@ def __init__( # pylint: disable=too-many-statements, too-many-branches
eager_loading: bool = False,
include_assets_files: bool = True,
include_pages_meta: bool = True,
title: str = "Dash",
update_title: str = "Updating...",
description: Optional[str] = None,
image: Optional[str] = None,
url_base_pathname: Optional[str] = None,
requests_pathname_prefix: Optional[str] = None,
routes_pathname_prefix: Optional[str] = None,
Expand All @@ -506,15 +513,12 @@ def __init__( # pylint: disable=too-many-statements, too-many-branches
show_undo_redo: bool = False,
extra_hot_reload_paths: Optional[Sequence[str]] = None,
plugins: Optional[list] = None,
title: str = "Dash",
update_title: str = "Updating...",
background_callback_manager: Optional[
Any
] = None, # Type should be specified if possible
add_log_handler: bool = True,
hooks: Optional[RendererHooks] = None,
routing_callback_inputs: Optional[Dict[str, Union[Input, State]]] = None,
description: Optional[str] = None,
on_error: Optional[Callable[[Exception], Any]] = None,
use_async: Optional[bool] = None,
health_endpoint: Optional[str] = None,
Expand Down Expand Up @@ -612,6 +616,7 @@ def __init__( # pylint: disable=too-many-statements, too-many-branches
update_title=update_title,
include_pages_meta=include_pages_meta,
description=description,
image=image,
health_endpoint=health_endpoint,
hide_all_callbacks=False,
csrf_token_name=csrf_token_name,
Expand Down Expand Up @@ -645,6 +650,8 @@ def __init__( # pylint: disable=too-many-statements, too-many-branches

# keep title as a class property for backwards compatibility
self.title = title
self.description = description
self.image = image

# MCP (Model Context Protocol) configuration
self._enable_mcp = get_combined_config("mcp_enabled", enable_mcp, False)
Expand Down Expand Up @@ -1484,7 +1491,8 @@ def index(self, *_args, **_kwargs):
# Refactored: direct access to global request adapter
request = self.backend.request_adapter()

if self.use_pages and self.config.include_pages_meta and request:
# include social media meta tags
if self.config.include_pages_meta and request:
metas = _page_meta_tags(self, request) + metas

if self._favicon:
Expand Down
Loading